mirror of
https://github.com/phabelio/PHP-Parser.git
synced 2024-11-27 04:24:43 +01:00
Better prededence and associativity handling in pretty printer
Previously the pretty printer added unnecessary and odd-looking parentheses when several operators with the same precedence were chained: 'a' . 'b' . 'c' . 'd' . 'e' // was printed as 'a' . ('b' . ('c' . ('d' . 'e'))) Another issue reported as part of #39 was that assignments inside closures were wrapped in parentheses: function() { $a = $b; } // was printed as function() { ($a = $b); } This was caused by the automatic precedence handling, which just regarded the closure as an ordinal nested expression. With the new system the $predenceMap of PrettyPrinterAbstract contains both precedence and associativity and there is a new method pPrec() which prints a node taking precedence and associativity into account. For simpler usage there are additional function pInfixOp(), pPrefixOp() and pPostfixOp(). Prints not going through pPrec() do not have any precedence handling (fixing the closure issue).
This commit is contained in:
parent
759c04db9b
commit
ac6f221c50
@ -91,225 +91,225 @@ class PHPParser_PrettyPrinter_Zend extends PHPParser_PrettyPrinterAbstract
|
||||
// Assignments
|
||||
|
||||
public function pExpr_Assign(PHPParser_Node_Expr_Assign $node) {
|
||||
return $this->p($node->var) . ' = ' . $this->p($node->expr);
|
||||
return $this->pInfixOp('Expr_Assign', $node->var, ' = ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_AssignRef(PHPParser_Node_Expr_AssignRef $node) {
|
||||
return $this->p($node->var) . ' =& ' . $this->p($node->expr);
|
||||
return $this->pInfixOp('Expr_AssignRef', $node->var, ' =& ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_AssignPlus(PHPParser_Node_Expr_AssignPlus $node) {
|
||||
return $this->p($node->var) . ' += ' . $this->p($node->expr);
|
||||
return $this->pInfixOp('Expr_AssignPlus', $node->var, ' += ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_AssignMinus(PHPParser_Node_Expr_AssignMinus $node) {
|
||||
return $this->p($node->var) . ' -= ' . $this->p($node->expr);
|
||||
return $this->pInfixOp('Expr_AssignMinus', $node->var, ' -= ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_AssignMul(PHPParser_Node_Expr_AssignMul $node) {
|
||||
return $this->p($node->var) . ' *= ' . $this->p($node->expr);
|
||||
return $this->pInfixOp('Expr_AssignMul', $node->var, ' *= ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_AssignDiv(PHPParser_Node_Expr_AssignDiv $node) {
|
||||
return $this->p($node->var) . ' /= ' . $this->p($node->expr);
|
||||
return $this->pInfixOp('Expr_AssignDiv', $node->var, ' /= ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_AssignConcat(PHPParser_Node_Expr_AssignConcat $node) {
|
||||
return $this->p($node->var) . ' .= ' . $this->p($node->expr);
|
||||
return $this->pInfixOp('Expr_AssignConcat', $node->var, ' .= ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_AssignMod(PHPParser_Node_Expr_AssignMod $node) {
|
||||
return $this->p($node->var) . ' %= ' . $this->p($node->expr);
|
||||
return $this->pInfixOp('Expr_AssignMod', $node->var, ' %= ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_AssignBitwiseAnd(PHPParser_Node_Expr_AssignBitwiseAnd $node) {
|
||||
return $this->p($node->var) . ' &= ' . $this->p($node->expr);
|
||||
return $this->pInfixOp('Expr_AssignBitwiseAnd', $node->var, ' &= ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_AssignBitwiseOr(PHPParser_Node_Expr_AssignBitwiseOr $node) {
|
||||
return $this->p($node->var) . ' |= ' . $this->p($node->expr);
|
||||
return $this->pInfixOp('Expr_AssignBitwiseOr', $node->var, ' |= ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_AssignBitwiseXor(PHPParser_Node_Expr_AssignBitwiseXor $node) {
|
||||
return $this->p($node->var) . ' ^= ' . $this->p($node->expr);
|
||||
return $this->pInfixOp('Expr_AssignBitwiseXor', $node->var, ' ^= ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_AssignShiftLeft(PHPParser_Node_Expr_AssignShiftLeft $node) {
|
||||
return $this->p($node->var) . ' <<= ' . $this->p($node->expr);
|
||||
return $this->pInfixOp('Expr_AssignShiftLeft', $node->var, ' <<= ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_AssignShiftRight(PHPParser_Node_Expr_AssignShiftRight $node) {
|
||||
return $this->p($node->var) . ' >>= ' . $this->p($node->expr);
|
||||
return $this->pInfixOp('Expr_AssignShiftRight', $node->var, ' >>= ', $node->expr);
|
||||
}
|
||||
|
||||
// Binary expressions
|
||||
|
||||
public function pExpr_Plus(PHPParser_Node_Expr_Plus $node) {
|
||||
return $this->p($node->left) . ' + ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_Plus', $node->left, ' + ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_Minus(PHPParser_Node_Expr_Minus $node) {
|
||||
return $this->p($node->left) . ' - ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_Minus', $node->left, ' - ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_Mul(PHPParser_Node_Expr_Mul $node) {
|
||||
return $this->p($node->left) . ' * ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_Mul', $node->left, ' * ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_Div(PHPParser_Node_Expr_Div $node) {
|
||||
return $this->p($node->left) . ' / ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_Div', $node->left, ' / ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_Concat(PHPParser_Node_Expr_Concat $node) {
|
||||
return $this->p($node->left) . ' . ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_Concat', $node->left, ' . ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_Mod(PHPParser_Node_Expr_Mod $node) {
|
||||
return $this->p($node->left) . ' % ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_Mod', $node->left, ' % ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_BooleanAnd(PHPParser_Node_Expr_BooleanAnd $node) {
|
||||
return $this->p($node->left) . ' && ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_BooleanAnd', $node->left, ' && ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_BooleanOr(PHPParser_Node_Expr_BooleanOr $node) {
|
||||
return $this->p($node->left) . ' || ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_BooleanOr', $node->left, ' || ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_BitwiseAnd(PHPParser_Node_Expr_BitwiseAnd $node) {
|
||||
return $this->p($node->left) . ' & ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_BitwiseAnd', $node->left, ' & ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_BitwiseOr(PHPParser_Node_Expr_BitwiseOr $node) {
|
||||
return $this->p($node->left) . ' | ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_BitwiseOr', $node->left, ' | ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_BitwiseXor(PHPParser_Node_Expr_BitwiseXor $node) {
|
||||
return $this->p($node->left) . ' ^ ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_BitwiseXor', $node->left, ' ^ ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_ShiftLeft(PHPParser_Node_Expr_ShiftLeft $node) {
|
||||
return $this->p($node->left) . ' << ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_ShiftLeft', $node->left, ' << ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_ShiftRight(PHPParser_Node_Expr_ShiftRight $node) {
|
||||
return $this->p($node->left) . ' >> ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_ShiftRight', $node->left, ' >> ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_LogicalAnd(PHPParser_Node_Expr_LogicalAnd $node) {
|
||||
return $this->p($node->left) . ' and ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_LogicalAnd', $node->left, ' and ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_LogicalOr(PHPParser_Node_Expr_LogicalOr $node) {
|
||||
return $this->p($node->left) . ' or ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_LogicalOr', $node->left, ' or ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_LogicalXor(PHPParser_Node_Expr_LogicalXor $node) {
|
||||
return $this->p($node->left) . ' xor ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_LogicalXor', $node->left, ' xor ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_Equal(PHPParser_Node_Expr_Equal $node) {
|
||||
return $this->p($node->left) . ' == ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_Equal', $node->left, ' == ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_NotEqual(PHPParser_Node_Expr_NotEqual $node) {
|
||||
return $this->p($node->left) . ' != ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_NotEqual', $node->left, ' != ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_Identical(PHPParser_Node_Expr_Identical $node) {
|
||||
return $this->p($node->left) . ' === ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_Identical', $node->left, ' === ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_NotIdentical(PHPParser_Node_Expr_NotIdentical $node) {
|
||||
return $this->p($node->left) . ' !== ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_NotIdentical', $node->left, ' !== ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_Greater(PHPParser_Node_Expr_Greater $node) {
|
||||
return $this->p($node->left) . ' > ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_Greater', $node->left, ' > ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_GreaterOrEqual(PHPParser_Node_Expr_GreaterOrEqual $node) {
|
||||
return $this->p($node->left) . ' >= ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_GreaterOrEqual', $node->left, ' >= ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_Smaller(PHPParser_Node_Expr_Smaller $node) {
|
||||
return $this->p($node->left) . ' < ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_Smaller', $node->left, ' < ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_SmallerOrEqual(PHPParser_Node_Expr_SmallerOrEqual $node) {
|
||||
return $this->p($node->left) . ' <= ' . $this->p($node->right);
|
||||
return $this->pInfixOp('Expr_SmallerOrEqual', $node->left, ' <= ', $node->right);
|
||||
}
|
||||
|
||||
public function pExpr_Instanceof(PHPParser_Node_Expr_Instanceof $node) {
|
||||
return $this->p($node->expr) . ' instanceof ' . $this->p($node->class);
|
||||
return $this->pInfixOp('Expr_Instanceof', $node->expr, ' instanceof ', $node->class);
|
||||
}
|
||||
|
||||
// Unary expressions
|
||||
|
||||
public function pExpr_BooleanNot(PHPParser_Node_Expr_BooleanNot $node) {
|
||||
return '!' . $this->p($node->expr);
|
||||
return $this->pPrefixOp('Expr_BooleanNot', '!', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_BitwiseNot(PHPParser_Node_Expr_BitwiseNot $node) {
|
||||
return '~' . $this->p($node->expr);
|
||||
return $this->pPrefixOp('Expr_BitwiseNot', '~', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_UnaryMinus(PHPParser_Node_Expr_UnaryMinus $node) {
|
||||
return '-' . $this->p($node->expr);
|
||||
return $this->pPrefixOp('Expr_UnaryMinus', '-', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_UnaryPlus(PHPParser_Node_Expr_UnaryPlus $node) {
|
||||
return '+' . $this->p($node->expr);
|
||||
return $this->pPrefixOp('Expr_UnaryPlus', '+', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_PreInc(PHPParser_Node_Expr_PreInc $node) {
|
||||
return '++' . $this->p($node->var);
|
||||
return $this->pPrefixOp('Expr_PreInc', '++', $node->var);
|
||||
}
|
||||
|
||||
public function pExpr_PreDec(PHPParser_Node_Expr_PreDec $node) {
|
||||
return '--' . $this->p($node->var);
|
||||
return $this->pPrefixOp('Expr_PreDec', '--', $node->var);
|
||||
}
|
||||
|
||||
public function pExpr_PostInc(PHPParser_Node_Expr_PostInc $node) {
|
||||
return $this->p($node->var) . '++';
|
||||
return $this->pPostfixOp('Expr_PostInc', $node->var, '++');
|
||||
}
|
||||
|
||||
public function pExpr_PostDec(PHPParser_Node_Expr_PostDec $node) {
|
||||
return $this->p($node->var) . '--';
|
||||
return $this->pPostfixOp('Expr_PostDec', $node->var, '--');
|
||||
}
|
||||
|
||||
public function pExpr_ErrorSuppress(PHPParser_Node_Expr_ErrorSuppress $node) {
|
||||
return '@' . $this->p($node->expr);
|
||||
return $this->pPrefixOp('Expr_ErrorSuppress', '@', $node->expr);
|
||||
}
|
||||
|
||||
// Casts
|
||||
|
||||
public function pExpr_Cast_Int(PHPParser_Node_Expr_Cast_Int $node) {
|
||||
return '(int) ' . $this->p($node->expr);
|
||||
return $this->pPrefixOp('Expr_Cast_Int', '(int) ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_Cast_Double(PHPParser_Node_Expr_Cast_Double $node) {
|
||||
return '(double) ' . $this->p($node->expr);
|
||||
return $this->pPrefixOp('Expr_Cast_Double', '(double) ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_Cast_String(PHPParser_Node_Expr_Cast_String $node) {
|
||||
return '(string) ' . $this->p($node->expr);
|
||||
return $this->pPrefixOp('Expr_Cast_String', '(string) ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_Cast_Array(PHPParser_Node_Expr_Cast_Array $node) {
|
||||
return '(array) ' . $this->p($node->expr);
|
||||
return $this->pPrefixOp('Expr_Cast_Array', '(array) ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_Cast_Object(PHPParser_Node_Expr_Cast_Object $node) {
|
||||
return '(object) ' . $this->p($node->expr);
|
||||
return $this->pPrefixOp('Expr_Cast_Object', '(object) ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_Cast_Bool(PHPParser_Node_Expr_Cast_Bool $node) {
|
||||
return '(bool) ' . $this->p($node->expr);
|
||||
return $this->pPrefixOp('Expr_Cast_Bool', '(bool) ', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_Cast_Unset(PHPParser_Node_Expr_Cast_Unset $node) {
|
||||
return '(unset) ' . $this->p($node->expr);
|
||||
return $this->pPrefixOp('Expr_Cast_Unset', '(unset) ', $node->expr);
|
||||
}
|
||||
|
||||
// Function calls and similar constructs
|
||||
@ -439,9 +439,11 @@ class PHPParser_PrettyPrinter_Zend extends PHPParser_PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
public function pExpr_Ternary(PHPParser_Node_Expr_Ternary $node) {
|
||||
return $this->p($node->cond) . ' ?'
|
||||
. (null !== $node->if ? ' ' . $this->p($node->if) . ' ' : '')
|
||||
. ': ' . $this->p($node->else);
|
||||
// a bit of cheating: we treat the ternary as a binary op where the ?...: part is the operator.
|
||||
// this is okay because the part between ? and : never needs parentheses.
|
||||
return $this->pInfixOp('Expr_Ternary',
|
||||
$node->cond, ' ?' . (null !== $node->if ? ' ' . $this->p($node->if) . ' ' : '') . ': ', $node->else
|
||||
);
|
||||
}
|
||||
|
||||
public function pExpr_Exit(PHPParser_Node_Expr_Exit $node) {
|
||||
|
@ -3,69 +3,68 @@
|
||||
abstract class PHPParser_PrettyPrinterAbstract
|
||||
{
|
||||
protected $precedenceMap = array(
|
||||
'Expr_BitwiseNot' => 1,
|
||||
'Expr_PreInc' => 1,
|
||||
'Expr_PreDec' => 1,
|
||||
'Expr_PostInc' => 1,
|
||||
'Expr_PostDec' => 1,
|
||||
'Expr_UnaryPlus' => 1,
|
||||
'Expr_UnaryMinus' => 1,
|
||||
'Expr_Cast_Int' => 1,
|
||||
'Expr_Cast_Double' => 1,
|
||||
'Expr_Cast_String' => 1,
|
||||
'Expr_Cast_Array' => 1,
|
||||
'Expr_Cast_Object' => 1,
|
||||
'Expr_Cast_Bool' => 1,
|
||||
'Expr_Cast_Unset' => 1,
|
||||
'Expr_ErrorSuppress' => 1,
|
||||
'Expr_Instanceof' => 2,
|
||||
'Expr_BooleanNot' => 3,
|
||||
'Expr_Mul' => 4,
|
||||
'Expr_Div' => 4,
|
||||
'Expr_Mod' => 4,
|
||||
'Expr_Plus' => 5,
|
||||
'Expr_Minus' => 5,
|
||||
'Expr_Concat' => 5,
|
||||
'Expr_ShiftLeft' => 6,
|
||||
'Expr_ShiftRight' => 6,
|
||||
'Expr_Smaller' => 7,
|
||||
'Expr_SmallerOrEqual' => 7,
|
||||
'Expr_Greater' => 7,
|
||||
'Expr_GreaterOrEqual' => 7,
|
||||
'Expr_Equal' => 8,
|
||||
'Expr_NotEqual' => 8,
|
||||
'Expr_Identical' => 8,
|
||||
'Expr_NotIdentical' => 8,
|
||||
'Expr_BitwiseAnd' => 9,
|
||||
'Expr_BitwiseXor' => 10,
|
||||
'Expr_BitwiseOr' => 11,
|
||||
'Expr_BooleanAnd' => 12,
|
||||
'Expr_BooleanOr' => 13,
|
||||
'Expr_Ternary' => 14,
|
||||
'Expr_Assign' => 15,
|
||||
'Expr_AssignPlus' => 15,
|
||||
'Expr_AssignMinus' => 15,
|
||||
'Expr_AssignMul' => 15,
|
||||
'Expr_AssignDiv' => 15,
|
||||
'Expr_AssignConcat' => 15,
|
||||
'Expr_AssignMod' => 15,
|
||||
'Expr_AssignBitwiseAnd' => 15,
|
||||
'Expr_AssignBitwiseOr' => 15,
|
||||
'Expr_AssignBitwiseXor' => 15,
|
||||
'Expr_AssignShiftLeft' => 15,
|
||||
'Expr_AssignShiftRight' => 15,
|
||||
'Expr_AssignList' => 15,
|
||||
'Expr_LogicalAnd' => 16,
|
||||
'Expr_LogicalXor' => 17,
|
||||
'Expr_LogicalOr' => 18,
|
||||
// [precedence, associativity] where for the latter -1 is %left, 0 is %nonassoc and 1 is %right
|
||||
'Expr_BitwiseNot' => array( 1, 1),
|
||||
'Expr_PreInc' => array( 1, 1),
|
||||
'Expr_PreDec' => array( 1, 1),
|
||||
'Expr_PostInc' => array( 1, -1),
|
||||
'Expr_PostDec' => array( 1, -1),
|
||||
'Expr_UnaryPlus' => array( 1, 1),
|
||||
'Expr_UnaryMinus' => array( 1, 1),
|
||||
'Expr_Cast_Int' => array( 1, 1),
|
||||
'Expr_Cast_Double' => array( 1, 1),
|
||||
'Expr_Cast_String' => array( 1, 1),
|
||||
'Expr_Cast_Array' => array( 1, 1),
|
||||
'Expr_Cast_Object' => array( 1, 1),
|
||||
'Expr_Cast_Bool' => array( 1, 1),
|
||||
'Expr_Cast_Unset' => array( 1, 1),
|
||||
'Expr_ErrorSuppress' => array( 1, 1),
|
||||
'Expr_Instanceof' => array( 2, 0),
|
||||
'Expr_BooleanNot' => array( 3, 1),
|
||||
'Expr_Mul' => array( 4, -1),
|
||||
'Expr_Div' => array( 4, -1),
|
||||
'Expr_Mod' => array( 4, -1),
|
||||
'Expr_Plus' => array( 5, -1),
|
||||
'Expr_Minus' => array( 5, -1),
|
||||
'Expr_Concat' => array( 5, -1),
|
||||
'Expr_ShiftLeft' => array( 6, -1),
|
||||
'Expr_ShiftRight' => array( 6, -1),
|
||||
'Expr_Smaller' => array( 7, 0),
|
||||
'Expr_SmallerOrEqual' => array( 7, 0),
|
||||
'Expr_Greater' => array( 7, 0),
|
||||
'Expr_GreaterOrEqual' => array( 7, 0),
|
||||
'Expr_Equal' => array( 8, 0),
|
||||
'Expr_NotEqual' => array( 8, 0),
|
||||
'Expr_Identical' => array( 8, 0),
|
||||
'Expr_NotIdentical' => array( 8, 0),
|
||||
'Expr_BitwiseAnd' => array( 9, -1),
|
||||
'Expr_BitwiseXor' => array(10, -1),
|
||||
'Expr_BitwiseOr' => array(11, -1),
|
||||
'Expr_BooleanAnd' => array(12, -1),
|
||||
'Expr_BooleanOr' => array(13, -1),
|
||||
'Expr_Ternary' => array(14, -1),
|
||||
// parser uses %left for assignments, but they really behave as %right
|
||||
'Expr_Assign' => array(15, 1),
|
||||
'Expr_AssignRef' => array(15, 1),
|
||||
'Expr_AssignPlus' => array(15, 1),
|
||||
'Expr_AssignMinus' => array(15, 1),
|
||||
'Expr_AssignMul' => array(15, 1),
|
||||
'Expr_AssignDiv' => array(15, 1),
|
||||
'Expr_AssignConcat' => array(15, 1),
|
||||
'Expr_AssignMod' => array(15, 1),
|
||||
'Expr_AssignBitwiseAnd' => array(15, 1),
|
||||
'Expr_AssignBitwiseOr' => array(15, 1),
|
||||
'Expr_AssignBitwiseXor' => array(15, 1),
|
||||
'Expr_AssignShiftLeft' => array(15, 1),
|
||||
'Expr_AssignShiftRight' => array(15, 1),
|
||||
'Expr_LogicalAnd' => array(16, -1),
|
||||
'Expr_LogicalXor' => array(17, -1),
|
||||
'Expr_LogicalOr' => array(18, -1),
|
||||
);
|
||||
|
||||
protected $precedenceStack;
|
||||
protected $precedenceStackPos;
|
||||
protected $noIndentToken;
|
||||
|
||||
public function __construct() {
|
||||
$this->precedenceStack = array($this->precedenceStackPos = 0 => 19);
|
||||
$this->noIndentToken = uniqid('_NO_INDENT_');
|
||||
}
|
||||
|
||||
@ -126,25 +125,51 @@ abstract class PHPParser_PrettyPrinterAbstract
|
||||
* @return string Pretty printed node
|
||||
*/
|
||||
protected function p(PHPParser_Node $node) {
|
||||
return $this->{'p' . $node->getType()}($node);
|
||||
}
|
||||
|
||||
protected function pInfixOp($type, PHPParser_Node $leftNode, $operatorString, PHPParser_Node $rightNode) {
|
||||
list($precedence, $associativity) = $this->precedenceMap[$type];
|
||||
|
||||
return $this->pPrec($leftNode, $precedence, $associativity, -1)
|
||||
. $operatorString
|
||||
. $this->pPrec($rightNode, $precedence, $associativity, 1);
|
||||
}
|
||||
|
||||
protected function pPrefixOp($type, $operatorString, PHPParser_Node $node) {
|
||||
list($precedence, $associativity) = $this->precedenceMap[$type];
|
||||
return $operatorString . $this->pPrec($node, $precedence, $associativity, 1);
|
||||
}
|
||||
|
||||
protected function pPostfixOp($type, PHPParser_Node $node, $operatorString) {
|
||||
list($precedence, $associativity) = $this->precedenceMap[$type];
|
||||
return $this->pPrec($node, $precedence, $associativity, -1) . $operatorString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints an expression node with the least amount of parentheses necessary to preserve the meaning.
|
||||
*
|
||||
* @param PHPParser_Node $node Node to pretty print
|
||||
* @param int $parentPrecedence Precedence of the parent operator
|
||||
* @param int $parentAssociativity Associativity of parent operator
|
||||
* (-1 is left, 0 is nonassoc, 1 is right)
|
||||
* @param int $childPosition Position of the node relative to the operator
|
||||
* (-1 is left, 1 is right)
|
||||
*
|
||||
* @return string The pretty printed node
|
||||
*/
|
||||
protected function pPrec(PHPParser_Node $node, $parentPrecedence, $parentAssociativity, $childPosition) {
|
||||
$type = $node->getType();
|
||||
|
||||
if (isset($this->precedenceMap[$type])) {
|
||||
$precedence = $this->precedenceMap[$type];
|
||||
|
||||
if ($precedence >= $this->precedenceStack[$this->precedenceStackPos]) {
|
||||
$this->precedenceStack[++$this->precedenceStackPos] = $precedence;
|
||||
$return = '(' . $this->{'p' . $type}($node) . ')';
|
||||
--$this->precedenceStackPos;
|
||||
} else {
|
||||
$this->precedenceStack[++$this->precedenceStackPos] = $precedence;
|
||||
$return = $this->{'p' . $type}($node);
|
||||
--$this->precedenceStackPos;
|
||||
$childPrecedence = $this->precedenceMap[$type][0];
|
||||
if ($childPrecedence > $parentPrecedence
|
||||
|| ($parentPrecedence == $childPrecedence && $parentAssociativity != $childPosition)
|
||||
) {
|
||||
return '(' . $this->{'p' . $type}($node) . ')';
|
||||
}
|
||||
|
||||
return $return;
|
||||
} else {
|
||||
return $this->{'p' . $type}($node);
|
||||
}
|
||||
|
||||
return $this->{'p' . $type}($node);
|
||||
}
|
||||
|
||||
/**
|
||||
|
18
test/code/prettyPrinter/closure.test
Normal file
18
test/code/prettyPrinter/closure.test
Normal file
@ -0,0 +1,18 @@
|
||||
Closures
|
||||
-----
|
||||
<?php
|
||||
|
||||
$closureWithArgs = function ($arg1, $arg2) {
|
||||
$comment = 'closure body';
|
||||
};
|
||||
|
||||
$closureWithArgsAndVars = function ($arg1, $arg2) use($var1, $var2) {
|
||||
$comment = 'closure body';
|
||||
};
|
||||
-----
|
||||
$closureWithArgs = function ($arg1, $arg2) {
|
||||
$comment = 'closure body';
|
||||
};
|
||||
$closureWithArgsAndVars = function ($arg1, $arg2) use($var1, $var2) {
|
||||
$comment = 'closure body';
|
||||
};
|
45
test/code/prettyPrinter/parentheses.test
Normal file
45
test/code/prettyPrinter/parentheses.test
Normal file
@ -0,0 +1,45 @@
|
||||
Pretty printer generates least-parentheses output
|
||||
-----
|
||||
<?php
|
||||
|
||||
echo 'abc' . 'cde' . 'fgh';
|
||||
echo 'abc' . ('cde' . 'fgh');
|
||||
|
||||
echo 'abc' . 1 + 2 . 'fgh';
|
||||
echo 'abc' . (1 + 2) . 'fgh';
|
||||
|
||||
echo 1 * 2 + 3 / 4 % 5 . 6;
|
||||
echo 1 * (2 + 3) / (4 % (5 . 6));
|
||||
|
||||
$a = $b = $c = $d = $f && true;
|
||||
($a = $b = $c = $d = $f) && true;
|
||||
$a = $b = $c = $d = $f and true;
|
||||
$a = $b = $c = $d = ($f and true);
|
||||
|
||||
$a ? $b : $c ? $d : $e ? $f : $g;
|
||||
$a ? $b : ($c ? $d : ($e ? $f : $g));
|
||||
$a ? $b ? $c : $d : $f;
|
||||
|
||||
(1 > 0) > (1 < 0);
|
||||
|
||||
// this will currently unnecessarily print !($a = $b). This is correct as far as operator precedence is concerned, but
|
||||
// the parentheses are not really necessary, because = takes only variables as the left hand side operator.
|
||||
!$a = $b;
|
||||
-----
|
||||
echo 'abc' . 'cde' . 'fgh';
|
||||
echo 'abc' . ('cde' . 'fgh');
|
||||
echo 'abc' . 1 + 2 . 'fgh';
|
||||
echo 'abc' . (1 + 2) . 'fgh';
|
||||
echo 1 * 2 + 3 / 4 % 5 . 6;
|
||||
echo 1 * (2 + 3) / (4 % (5 . 6));
|
||||
$a = $b = $c = $d = $f && true;
|
||||
($a = $b = $c = $d = $f) && true;
|
||||
$a = $b = $c = $d = $f and true;
|
||||
$a = $b = $c = $d = ($f and true);
|
||||
$a ? $b : $c ? $d : $e ? $f : $g;
|
||||
$a ? $b : ($c ? $d : ($e ? $f : $g));
|
||||
$a ? $b ? $c : $d : $f;
|
||||
(1 > 0) > (1 < 0);
|
||||
// this will currently unnecessarily print !($a = $b). This is correct as far as operator precedence is concerned, but
|
||||
// the parentheses are not really necessary, because = takes only variables as the left hand side operator.
|
||||
!($a = $b);
|
Loading…
Reference in New Issue
Block a user