Skip to content

Commit

Permalink
Properly handle failure to parse right side of binary operations
Browse files Browse the repository at this point in the history
  • Loading branch information
TysonAndre-tmg committed Feb 6, 2020
1 parent 29c7430 commit 46204f1
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 5 deletions.
29 changes: 24 additions & 5 deletions src/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -1068,10 +1068,9 @@ private function parsePrimaryExpression($parentNode) {
// anonymous-function-creation-expression
case TokenKind::StaticKeyword:
// handle `static::`, `static(`, `new static;`, `instanceof static`
if (($this->lookahead([TokenKind::ColonColonToken, TokenKind::OpenParenToken])) ||
(!$this->lookahead([TokenKind::FunctionKeyword, TokenKind::FnKeyword]))
) {
return $this->parseQualifiedName($parentNode);
if ((!$this->lookahead([TokenKind::FunctionKeyword, TokenKind::FnKeyword]))) {
// TODO: Should this check the parent type to reject `$x = static;`, `$x = static();`, etc.
return $this->parseStaticQualifiedName($parentNode);
}
// Could be `static function` anonymous function creation expression, so flow through
case TokenKind::FunctionKeyword:
Expand Down Expand Up @@ -1370,6 +1369,21 @@ private function isQualifiedNameStartForCatchFn() {
};
}

/**
* @return QualifiedName
*/
private function parseStaticQualifiedName($parentNode) {
$node = new QualifiedName();
$token = $this->eat(TokenKind::StaticKeyword);
$token->kind = TokenKind::Name;
$node->parent = $parentNode;
$node->nameParts = [$token];
return $node;
}

/**
* @return QualifiedName|null - returns null for invalid qualified names such as `static\` (use parseStaticQualifiedName for that)
*/
private function parseQualifiedName($parentNode) {
return ($this->parseQualifiedNameFn())($parentNode);
}
Expand All @@ -1388,7 +1402,9 @@ private function parseQualifiedNameFn() {
DelimitedList\QualifiedNameParts::class,
TokenKind::BackslashToken,
function ($token) {
// a\static() <- VALID
// a\static() <- INVALID (but not checked for right now)
// new a\static() <- INVALID
// new static() <- VALID
// a\static\b <- INVALID
// a\function <- INVALID
// a\true\b <-VALID
Expand Down Expand Up @@ -1485,6 +1501,9 @@ private function parseNamedLabelStatement($parentNode) {
return $namedLabelStatement;
}

/**
* @param int|int[] ...$expectedKinds an array of one or more kinds/sets of allowed kinds in each position
*/
private function lookahead(...$expectedKinds) : bool {
$startPos = $this->lexer->getCurrentPosition();
$startToken = $this->token;
Expand Down
1 change: 1 addition & 0 deletions tests/cases/parser/binaryExpression20.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php \&static\
14 changes: 14 additions & 0 deletions tests/cases/parser/binaryExpression20.php.diag
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"kind": 0,
"message": "';' expected.",
"start": 14,
"length": 0
},
{
"kind": 0,
"message": "';' expected.",
"start": 15,
"length": 0
}
]
78 changes: 78 additions & 0 deletions tests/cases/parser/binaryExpression20.php.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{
"SourceFileNode": {
"statementList": [
{
"InlineHtml": {
"scriptSectionEndTag": null,
"text": null,
"scriptSectionStartTag": {
"kind": "ScriptSectionStartTag",
"textLength": 6
}
}
},
{
"ExpressionStatement": {
"expression": {
"BinaryExpression": {
"leftOperand": {
"QualifiedName": {
"globalSpecifier": {
"kind": "BackslashToken",
"textLength": 1
},
"relativeSpecifier": null,
"nameParts": []
}
},
"operator": {
"kind": "AmpersandToken",
"textLength": 1
},
"rightOperand": {
"QualifiedName": {
"globalSpecifier": null,
"relativeSpecifier": null,
"nameParts": [
{
"kind": "Name",
"textLength": 6
}
]
}
}
}
},
"semicolon": {
"error": "MissingToken",
"kind": "SemicolonToken",
"textLength": 0
}
}
},
{
"ExpressionStatement": {
"expression": {
"QualifiedName": {
"globalSpecifier": {
"kind": "BackslashToken",
"textLength": 1
},
"relativeSpecifier": null,
"nameParts": []
}
},
"semicolon": {
"error": "MissingToken",
"kind": "SemicolonToken",
"textLength": 0
}
}
}
],
"endOfFileToken": {
"kind": "EndOfFileToken",
"textLength": 0
}
}
}

0 comments on commit 46204f1

Please sign in to comment.