Support UVS in pretty printer

Try to generate interoperable code where possible (but not
everything can be expressed in PHP 5).
This commit is contained in:
Nikita Popov 2015-06-13 19:46:01 +02:00
parent f3f24e03ae
commit 71fa7c6674
5 changed files with 99 additions and 33 deletions

View File

@ -24,7 +24,7 @@ if (empty($files)) {
$lexer = new PhpParser\Lexer\Emulative(array('usedAttributes' => array(
'startLine', 'endLine', 'startFilePos', 'endFilePos'
)));
$parser = new PhpParser\Parser\Php5($lexer);
$parser = new PhpParser\Parser\Php7($lexer);
$dumper = new PhpParser\NodeDumper;
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
$serializer = new PhpParser\Serializer\XML;

View File

@ -356,19 +356,19 @@ class Standard extends PrettyPrinterAbstract
// Function calls and similar constructs
public function pExpr_FuncCall(Expr\FuncCall $node) {
return $this->p($node->name) . '(' . $this->pCommaSeparated($node->args) . ')';
return $this->pCallLhs($node->name)
. '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_MethodCall(Expr\MethodCall $node) {
return $this->pVarOrNewExpr($node->var) . '->' . $this->pObjectProperty($node->name)
return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name)
. '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_StaticCall(Expr\StaticCall $node) {
return $this->p($node->class) . '::'
return $this->pDereferenceLhs($node->class) . '::'
. ($node->name instanceof Expr
? ($node->name instanceof Expr\Variable
|| $node->name instanceof Expr\ArrayDimFetch
? $this->p($node->name)
: '{' . $this->p($node->name) . '}')
: $node->name)
@ -431,7 +431,7 @@ class Standard extends PrettyPrinterAbstract
}
public function pExpr_ArrayDimFetch(Expr\ArrayDimFetch $node) {
return $this->pVarOrNewExpr($node->var)
return $this->pDereferenceLhs($node->var)
. '[' . (null !== $node->dim ? $this->p($node->dim) : '') . ']';
}
@ -444,11 +444,11 @@ class Standard extends PrettyPrinterAbstract
}
public function pExpr_PropertyFetch(Expr\PropertyFetch $node) {
return $this->pVarOrNewExpr($node->var) . '->' . $this->pObjectProperty($node->name);
return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name);
}
public function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) {
return $this->p($node->class) . '::$' . $this->pObjectProperty($node->name);
return $this->pDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name);
}
public function pExpr_ShellExec(Expr\ShellExec $node) {
@ -748,8 +748,7 @@ class Standard extends PrettyPrinterAbstract
. "\n" . '{' . $this->pStmts($node->stmts) . "\n" . '}';
}
/** @internal */
public function pObjectProperty($node) {
protected function pObjectProperty($node) {
if ($node instanceof Expr) {
return '{' . $this->p($node) . '}';
} else {
@ -757,8 +756,7 @@ class Standard extends PrettyPrinterAbstract
}
}
/** @internal */
public function pModifiers($modifiers) {
protected function pModifiers($modifiers) {
return ($modifiers & Stmt\Class_::MODIFIER_PUBLIC ? 'public ' : '')
. ($modifiers & Stmt\Class_::MODIFIER_PROTECTED ? 'protected ' : '')
. ($modifiers & Stmt\Class_::MODIFIER_PRIVATE ? 'private ' : '')
@ -767,8 +765,7 @@ class Standard extends PrettyPrinterAbstract
. ($modifiers & Stmt\Class_::MODIFIER_FINAL ? 'final ' : '');
}
/** @internal */
public function pEncapsList(array $encapsList, $quote) {
protected function pEncapsList(array $encapsList, $quote) {
$return = '';
foreach ($encapsList as $element) {
if (is_string($element)) {
@ -781,12 +778,35 @@ class Standard extends PrettyPrinterAbstract
return $return;
}
/** @internal */
public function pVarOrNewExpr(Node $node) {
if ($node instanceof Expr\New_) {
return '(' . $this->p($node) . ')';
} else {
protected function pDereferenceLhs(Node $node) {
if ($node instanceof Expr\Variable
|| $node instanceof Name
|| $node instanceof Expr\ArrayDimFetch
|| $node instanceof Expr\PropertyFetch
|| $node instanceof Expr\StaticPropertyFetch
|| $node instanceof Expr\FuncCall
|| $node instanceof Expr\MethodCall
|| $node instanceof Expr\StaticCall
|| $node instanceof Expr\Array_
) {
return $this->p($node);
} else {
return '(' . $this->p($node) . ')';
}
}
protected function pCallLhs(Node $node) {
if ($node instanceof Name
|| $node instanceof Expr\Variable
|| $node instanceof Expr\ArrayDimFetch
|| $node instanceof Expr\FuncCall
|| $node instanceof Expr\MethodCall
|| $node instanceof Expr\StaticCall
|| $node instanceof Expr\Array_
) {
return $this->p($node);
} else {
return '(' . $this->p($node) . ')';
}
}
}

View File

@ -11,32 +11,52 @@ require_once __DIR__ . '/CodeTestAbstract.php';
class PrettyPrinterTest extends CodeTestAbstract
{
protected function doTestPrettyPrintMethod($method, $name, $code, $expected) {
$parser = new Parser(new Lexer\Emulative);
protected function doTestPrettyPrintMethod($method, $name, $code, $expected, $mode) {
$lexer = new Lexer\Emulative;
$parser5 = new Parser\Php5($lexer);
$parser7 = new Parser\Php7($lexer);
$prettyPrinter = new Standard;
$stmts = $parser->parse($code);
$this->assertSame(
$expected,
$this->canonicalize($prettyPrinter->$method($stmts)),
$name
);
try {
$output5 = $this->canonicalize($prettyPrinter->$method($parser5->parse($code)));
} catch (Error $e) {
$output5 = null;
$this->assertEquals('php7', $mode);
}
try {
$output7 = $this->canonicalize($prettyPrinter->$method($parser7->parse($code)));
} catch (Error $e) {
$output7 = null;
$this->assertEquals('php5', $mode);
}
if ('php5' === $mode) {
$this->assertSame($expected, $output5, $name);
$this->assertNotSame($expected, $output7, $name);
} else if ('php7' === $mode) {
$this->assertSame($expected, $output7, $name);
$this->assertNotSame($expected, $output5, $name);
} else {
$this->assertSame($expected, $output5, $name);
$this->assertSame($expected, $output7, $name);
}
}
/**
* @dataProvider provideTestPrettyPrint
* @covers PhpParser\PrettyPrinter\Standard<extended>
*/
public function testPrettyPrint($name, $code, $expected) {
$this->doTestPrettyPrintMethod('prettyPrint', $name, $code, $expected);
public function testPrettyPrint($name, $code, $expected, $mode) {
$this->doTestPrettyPrintMethod('prettyPrint', $name, $code, $expected, $mode);
}
/**
* @dataProvider provideTestPrettyPrintFile
* @covers PhpParser\PrettyPrinter\Standard<extended>
*/
public function testPrettyPrintFile($name, $code, $expected) {
$this->doTestPrettyPrintMethod('prettyPrintFile', $name, $code, $expected);
public function testPrettyPrintFile($name, $code, $expected, $mode) {
$this->doTestPrettyPrintMethod('prettyPrintFile', $name, $code, $expected, $mode);
}
public function provideTestPrettyPrint() {

View File

@ -0,0 +1,23 @@
Uniform variable syntax
-----
<?php
(function() {})();
array('a', 'b')()();
A::$b::$c;
$A::$b[$c]();
$A::{$b[$c]}();
A::$$b[$c]();
($a->b)();
(A::$b)();
-----
!!php7
(function () {
})();
array('a', 'b')()();
A::$b::$c;
$A::$b[$c]();
$A::{$b[$c]}();
A::${$b}[$c]();
($a->b)();
(A::$b)();

View File

@ -24,6 +24,7 @@ $a::$b[$c];
$a::$b[$c]($d);
$a::{$b[$c]}($d);
$a::{$b->c}();
A::$$b[$c]();
a();
$a();
$a()[$b];
@ -36,6 +37,7 @@ $a::$b()[$c];
global $a, $$a, $$a[$b], $$a->b;
-----
!!php5
$a;
${$a};
${$a};
@ -55,9 +57,10 @@ $a::b();
$a::b($c);
$a::$b();
$a::$b[$c];
$a::$b[$c]($d);
$a::$b[$c]($d);
$a::{$b[$c]}($d);
$a::{$b[$c]}($d);
$a::{$b->c}();
A::${$b[$c]}();
a();
$a();
$a()[$b];