From d996815820925d3047d829d9015764cd6e8b0bd5 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sun, 11 Feb 2018 21:29:26 -0800 Subject: [PATCH] For #19: Fix an edge case parsing `=` and `instanceof` This does not fix every single edge case. This only fixes the edge cases for unary operators on the left hand side of binary operators expecting a variable. (That probably isn't even every single binary operator or unary operator) --- src/Parser.php | 31 +++++++++- tests/cases/parser/lhsVariable1.php | 3 + tests/cases/parser/lhsVariable1.php.diag | 1 + tests/cases/parser/lhsVariable1.php.tree | 77 ++++++++++++++++++++++++ tests/cases/parser/lhsVariable2.php | 3 + tests/cases/parser/lhsVariable2.php.diag | 1 + tests/cases/parser/lhsVariable2.php.tree | 76 +++++++++++++++++++++++ tests/cases/parser/lhsVariable3.php | 3 + tests/cases/parser/lhsVariable3.php.diag | 1 + tests/cases/parser/lhsVariable3.php.tree | 76 +++++++++++++++++++++++ tests/cases/parser/lhsVariable4.php | 3 + tests/cases/parser/lhsVariable4.php.diag | 1 + tests/cases/parser/lhsVariable4.php.tree | 76 +++++++++++++++++++++++ 13 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 tests/cases/parser/lhsVariable1.php create mode 100644 tests/cases/parser/lhsVariable1.php.diag create mode 100644 tests/cases/parser/lhsVariable1.php.tree create mode 100644 tests/cases/parser/lhsVariable2.php create mode 100644 tests/cases/parser/lhsVariable2.php.diag create mode 100644 tests/cases/parser/lhsVariable2.php.tree create mode 100644 tests/cases/parser/lhsVariable3.php create mode 100644 tests/cases/parser/lhsVariable3.php.diag create mode 100644 tests/cases/parser/lhsVariable3.php.tree create mode 100644 tests/cases/parser/lhsVariable4.php create mode 100644 tests/cases/parser/lhsVariable4.php.diag create mode 100644 tests/cases/parser/lhsVariable4.php.tree diff --git a/src/Parser.php b/src/Parser.php index 7aeece9..7c1b4af 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -1664,8 +1664,35 @@ class Parser { // // After we finish building the BinaryExpression, we rebuild the UnaryExpression so that it includes // the original operator, and the newly constructed exponentiation-expression as the operand. - $shouldOperatorTakePrecedenceOverUnary = - $token->kind === TokenKind::AsteriskAsteriskToken && $leftOperand instanceof UnaryExpression; + $shouldOperatorTakePrecedenceOverUnary = false; + switch ($token->kind) { + case TokenKind::AsteriskAsteriskToken: + $shouldOperatorTakePrecedenceOverUnary = $leftOperand instanceof UnaryExpression; + break; + case TokenKind::EqualsToken: + case TokenKind::AsteriskAsteriskEqualsToken: + case TokenKind::AsteriskEqualsToken: + case TokenKind::SlashEqualsToken: + case TokenKind::PercentEqualsToken: + case TokenKind::PlusEqualsToken: + case TokenKind::MinusEqualsToken: + case TokenKind::DotEqualsToken: + case TokenKind::LessThanLessThanEqualsToken: + case TokenKind::GreaterThanGreaterThanEqualsToken: + case TokenKind::AmpersandEqualsToken: + case TokenKind::CaretEqualsToken: + case TokenKind::BarEqualsToken: + case TokenKind::InstanceOfKeyword: + // Workarounds for https://github.com/Microsoft/tolerant-php-parser/issues/19#issue-201714377 + // Parse `!$a = $b` as `!($a = $b)` - PHP constrains the Left Hand Side of an assignment to a variable. A unary operator (`@`, `!`, etc.) is not a variable. + // Instanceof has similar constraints for the LHS. + // So does `!$a += $b` + // TODO: Any other operators? + if ($leftOperand instanceof UnaryOpExpression) { + $shouldOperatorTakePrecedenceOverUnary = true; + } + break; + } if ($shouldOperatorTakePrecedenceOverUnary) { $unaryExpression = $leftOperand; diff --git a/tests/cases/parser/lhsVariable1.php b/tests/cases/parser/lhsVariable1.php new file mode 100644 index 0000000..1b6b58f --- /dev/null +++ b/tests/cases/parser/lhsVariable1.php @@ -0,0 +1,3 @@ +