From 98fbbd206a8aecbeb61aca223e32e45367cb5c7f Mon Sep 17 00:00:00 2001 From: Felix Siebeneicker Date: Fri, 7 Aug 2020 11:21:14 +0200 Subject: [PATCH 1/6] Adding declare directive list support --- .../DelimitedList/DeclareDirectiveList.php | 12 +++++ src/Node/Statement/DeclareStatement.php | 8 +-- src/Parser.php | 51 +++++++++++-------- 3 files changed, 46 insertions(+), 25 deletions(-) create mode 100644 src/Node/DelimitedList/DeclareDirectiveList.php diff --git a/src/Node/DelimitedList/DeclareDirectiveList.php b/src/Node/DelimitedList/DeclareDirectiveList.php new file mode 100644 index 00000000..a88b7331 --- /dev/null +++ b/src/Node/DelimitedList/DeclareDirectiveList.php @@ -0,0 +1,12 @@ +parent = $parentNode; $declareStatement->declareKeyword = $this->eat1(TokenKind::DeclareKeyword); $declareStatement->openParen = $this->eat1(TokenKind::OpenParenToken); - $declareStatement->declareDirective = $this->parseDeclareDirective($declareStatement); + $declareStatement->declareDirectives = $this->parseDelimitedList( + DelimitedList\DeclareDirectiveList::class, + TokenKind::CommaToken, + function ($token) { + return $token->kind === TokenKind::Name; + }, + $this->parseDeclareDirectiveFn(), + $declareStatement); $declareStatement->closeParen = $this->eat1(TokenKind::CloseParenToken); if ($this->checkToken(TokenKind::SemicolonToken)) { @@ -2325,26 +2332,28 @@ private function parseDeclareStatement($parentNode) { return $declareStatement; } - private function parseDeclareDirective($parentNode) { - $declareDirective = new DeclareDirective(); - $declareDirective->parent = $parentNode; - $declareDirective->name = $this->eat1(TokenKind::Name); - $declareDirective->equals = $this->eat1(TokenKind::EqualsToken); - $declareDirective->literal = - $this->eat( - TokenKind::FloatingLiteralToken, - TokenKind::IntegerLiteralToken, - TokenKind::DecimalLiteralToken, - TokenKind::OctalLiteralToken, - TokenKind::HexadecimalLiteralToken, - TokenKind::BinaryLiteralToken, - TokenKind::InvalidOctalLiteralToken, - TokenKind::InvalidHexadecimalLiteral, - TokenKind::InvalidBinaryLiteral, - TokenKind::StringLiteralToken - ); // TODO simplify - - return $declareDirective; + private function parseDeclareDirectiveFn() { + return function ($parentNode) { + $declareDirective = new DeclareDirective(); + $declareDirective->parent = $parentNode; + $declareDirective->name = $this->eat1(TokenKind::Name); + $declareDirective->equals = $this->eat1(TokenKind::EqualsToken); + $declareDirective->literal = + $this->eat( + TokenKind::FloatingLiteralToken, + TokenKind::IntegerLiteralToken, + TokenKind::DecimalLiteralToken, + TokenKind::OctalLiteralToken, + TokenKind::HexadecimalLiteralToken, + TokenKind::BinaryLiteralToken, + TokenKind::InvalidOctalLiteralToken, + TokenKind::InvalidHexadecimalLiteral, + TokenKind::InvalidBinaryLiteral, + TokenKind::StringLiteralToken + ); // TODO simplify + + return $declareDirective; + }; } private function parseSimpleVariable($parentNode) { From ceb5125f732d1929fba6940e64b60ca81efbbdea Mon Sep 17 00:00:00 2001 From: Felix Siebeneicker Date: Fri, 7 Aug 2020 11:21:57 +0200 Subject: [PATCH 2/6] Adding test case for simple list --- tests/cases/parser/declareStatement14.php | 5 + .../cases/parser/declareStatement14.php.diag | 1 + .../cases/parser/declareStatement14.php.tree | 117 ++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 tests/cases/parser/declareStatement14.php create mode 100644 tests/cases/parser/declareStatement14.php.diag create mode 100644 tests/cases/parser/declareStatement14.php.tree diff --git a/tests/cases/parser/declareStatement14.php b/tests/cases/parser/declareStatement14.php new file mode 100644 index 00000000..88349bb7 --- /dev/null +++ b/tests/cases/parser/declareStatement14.php @@ -0,0 +1,5 @@ + Date: Fri, 7 Aug 2020 11:22:36 +0200 Subject: [PATCH 3/6] Updating existing test structures --- tests/cases/parser/declareStatement1.php.tree | 34 ++++++++++-------- .../cases/parser/declareStatement10.php.tree | 34 ++++++++++-------- .../cases/parser/declareStatement11.php.tree | 34 ++++++++++-------- .../cases/parser/declareStatement12.php.diag | 21 +---------- .../cases/parser/declareStatement12.php.tree | 20 +---------- .../cases/parser/declareStatement13.php.tree | 34 ++++++++++-------- tests/cases/parser/declareStatement2.php.tree | 34 ++++++++++-------- tests/cases/parser/declareStatement3.php.tree | 34 ++++++++++-------- tests/cases/parser/declareStatement4.php.tree | 34 ++++++++++-------- tests/cases/parser/declareStatement5.php.tree | 34 ++++++++++-------- tests/cases/parser/declareStatement6.php.tree | 34 ++++++++++-------- tests/cases/parser/declareStatement7.php.tree | 36 +++++++++++-------- tests/cases/parser/declareStatement8.php.tree | 34 ++++++++++-------- tests/cases/parser/declareStatement9.php.tree | 36 +++++++++++-------- 14 files changed, 244 insertions(+), 209 deletions(-) diff --git a/tests/cases/parser/declareStatement1.php.tree b/tests/cases/parser/declareStatement1.php.tree index 866cb590..42cdec0e 100644 --- a/tests/cases/parser/declareStatement1.php.tree +++ b/tests/cases/parser/declareStatement1.php.tree @@ -21,20 +21,26 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirective": { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "IntegerLiteralToken", - "textLength": 1 - } + "declareDirectives": { + "DeclareDirectiveList": { + "children": [ + { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "IntegerLiteralToken", + "textLength": 1 + } + } + } + ] } }, "closeParen": { diff --git a/tests/cases/parser/declareStatement10.php.tree b/tests/cases/parser/declareStatement10.php.tree index d5efa715..adeb8a5e 100644 --- a/tests/cases/parser/declareStatement10.php.tree +++ b/tests/cases/parser/declareStatement10.php.tree @@ -21,20 +21,26 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirective": { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "FloatingLiteralToken", - "textLength": 3 - } + "declareDirectives": { + "DeclareDirectiveList": { + "children": [ + { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "FloatingLiteralToken", + "textLength": 3 + } + } + } + ] } }, "closeParen": { diff --git a/tests/cases/parser/declareStatement11.php.tree b/tests/cases/parser/declareStatement11.php.tree index 4ed0df10..e437b41d 100644 --- a/tests/cases/parser/declareStatement11.php.tree +++ b/tests/cases/parser/declareStatement11.php.tree @@ -21,20 +21,26 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirective": { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "FloatingLiteralToken", - "textLength": 3 - } + "declareDirectives": { + "DeclareDirectiveList": { + "children": [ + { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "FloatingLiteralToken", + "textLength": 3 + } + } + } + ] } }, "closeParen": { diff --git a/tests/cases/parser/declareStatement12.php.diag b/tests/cases/parser/declareStatement12.php.diag index 41d4ac51..0637a088 100644 --- a/tests/cases/parser/declareStatement12.php.diag +++ b/tests/cases/parser/declareStatement12.php.diag @@ -1,20 +1 @@ -[ - { - "kind": 0, - "message": "'Name' expected.", - "start": 16, - "length": 0 - }, - { - "kind": 0, - "message": "'=' expected.", - "start": 16, - "length": 0 - }, - { - "kind": 0, - "message": "'FloatingLiteralToken' expected.", - "start": 16, - "length": 0 - } -] \ No newline at end of file +[] \ No newline at end of file diff --git a/tests/cases/parser/declareStatement12.php.tree b/tests/cases/parser/declareStatement12.php.tree index c03f2936..7c98f4e6 100644 --- a/tests/cases/parser/declareStatement12.php.tree +++ b/tests/cases/parser/declareStatement12.php.tree @@ -21,25 +21,7 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirective": { - "DeclareDirective": { - "name": { - "error": "MissingToken", - "kind": "Name", - "textLength": 0 - }, - "equals": { - "error": "MissingToken", - "kind": "EqualsToken", - "textLength": 0 - }, - "literal": { - "error": "MissingToken", - "kind": "FloatingLiteralToken", - "textLength": 0 - } - } - }, + "declareDirectives": null, "closeParen": { "kind": "CloseParenToken", "textLength": 1 diff --git a/tests/cases/parser/declareStatement13.php.tree b/tests/cases/parser/declareStatement13.php.tree index 9eefc85b..0f13cdcf 100644 --- a/tests/cases/parser/declareStatement13.php.tree +++ b/tests/cases/parser/declareStatement13.php.tree @@ -21,20 +21,26 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirective": { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "IntegerLiteralToken", - "textLength": 1 - } + "declareDirectives": { + "DeclareDirectiveList": { + "children": [ + { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "IntegerLiteralToken", + "textLength": 1 + } + } + } + ] } }, "closeParen": { diff --git a/tests/cases/parser/declareStatement2.php.tree b/tests/cases/parser/declareStatement2.php.tree index 2378096e..955e5fcd 100644 --- a/tests/cases/parser/declareStatement2.php.tree +++ b/tests/cases/parser/declareStatement2.php.tree @@ -21,20 +21,26 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirective": { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "IntegerLiteralToken", - "textLength": 1 - } + "declareDirectives": { + "DeclareDirectiveList": { + "children": [ + { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "IntegerLiteralToken", + "textLength": 1 + } + } + } + ] } }, "closeParen": { diff --git a/tests/cases/parser/declareStatement3.php.tree b/tests/cases/parser/declareStatement3.php.tree index 6d6d5e90..38e600a3 100644 --- a/tests/cases/parser/declareStatement3.php.tree +++ b/tests/cases/parser/declareStatement3.php.tree @@ -21,20 +21,26 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirective": { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "IntegerLiteralToken", - "textLength": 1 - } + "declareDirectives": { + "DeclareDirectiveList": { + "children": [ + { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "IntegerLiteralToken", + "textLength": 1 + } + } + } + ] } }, "closeParen": { diff --git a/tests/cases/parser/declareStatement4.php.tree b/tests/cases/parser/declareStatement4.php.tree index e471da6f..621b9fd0 100644 --- a/tests/cases/parser/declareStatement4.php.tree +++ b/tests/cases/parser/declareStatement4.php.tree @@ -21,20 +21,26 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirective": { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 2 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "IntegerLiteralToken", - "textLength": 1 - } + "declareDirectives": { + "DeclareDirectiveList": { + "children": [ + { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 2 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "IntegerLiteralToken", + "textLength": 1 + } + } + } + ] } }, "closeParen": { diff --git a/tests/cases/parser/declareStatement5.php.tree b/tests/cases/parser/declareStatement5.php.tree index 7aa53b3d..b0599cd2 100644 --- a/tests/cases/parser/declareStatement5.php.tree +++ b/tests/cases/parser/declareStatement5.php.tree @@ -21,20 +21,26 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirective": { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "IntegerLiteralToken", - "textLength": 1 - } + "declareDirectives": { + "DeclareDirectiveList": { + "children": [ + { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "IntegerLiteralToken", + "textLength": 1 + } + } + } + ] } }, "closeParen": { diff --git a/tests/cases/parser/declareStatement6.php.tree b/tests/cases/parser/declareStatement6.php.tree index 6d6d5e90..38e600a3 100644 --- a/tests/cases/parser/declareStatement6.php.tree +++ b/tests/cases/parser/declareStatement6.php.tree @@ -21,20 +21,26 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirective": { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "IntegerLiteralToken", - "textLength": 1 - } + "declareDirectives": { + "DeclareDirectiveList": { + "children": [ + { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "IntegerLiteralToken", + "textLength": 1 + } + } + } + ] } }, "closeParen": { diff --git a/tests/cases/parser/declareStatement7.php.tree b/tests/cases/parser/declareStatement7.php.tree index 4993bcb7..aa38b966 100644 --- a/tests/cases/parser/declareStatement7.php.tree +++ b/tests/cases/parser/declareStatement7.php.tree @@ -21,21 +21,27 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirective": { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "error": "MissingToken", - "kind": "FloatingLiteralToken", - "textLength": 0 - } + "declareDirectives": { + "DeclareDirectiveList": { + "children": [ + { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "error": "MissingToken", + "kind": "FloatingLiteralToken", + "textLength": 0 + } + } + } + ] } }, "closeParen": { diff --git a/tests/cases/parser/declareStatement8.php.tree b/tests/cases/parser/declareStatement8.php.tree index 5f3340a4..a3191ef7 100644 --- a/tests/cases/parser/declareStatement8.php.tree +++ b/tests/cases/parser/declareStatement8.php.tree @@ -21,20 +21,26 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirective": { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "StringLiteralToken", - "textLength": 2 - } + "declareDirectives": { + "DeclareDirectiveList": { + "children": [ + { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "StringLiteralToken", + "textLength": 2 + } + } + } + ] } }, "closeParen": { diff --git a/tests/cases/parser/declareStatement9.php.tree b/tests/cases/parser/declareStatement9.php.tree index c5d03602..041f842f 100644 --- a/tests/cases/parser/declareStatement9.php.tree +++ b/tests/cases/parser/declareStatement9.php.tree @@ -21,21 +21,27 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirective": { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "error": "MissingToken", - "kind": "EqualsToken", - "textLength": 0 - }, - "literal": { - "kind": "IntegerLiteralToken", - "textLength": 3 - } + "declareDirectives": { + "DeclareDirectiveList": { + "children": [ + { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "error": "MissingToken", + "kind": "EqualsToken", + "textLength": 0 + }, + "literal": { + "kind": "IntegerLiteralToken", + "textLength": 3 + } + } + } + ] } }, "closeParen": { From b1e2ec09b693ff95e41eba2b25f7831daabb2751 Mon Sep 17 00:00:00 2001 From: Felix Siebeneicker Date: Fri, 7 Aug 2020 11:22:52 +0200 Subject: [PATCH 4/6] :lipstick: --- tests/ParserGrammarTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/ParserGrammarTest.php b/tests/ParserGrammarTest.php index 6fff0c25..32fa8cf3 100644 --- a/tests/ParserGrammarTest.php +++ b/tests/ParserGrammarTest.php @@ -4,7 +4,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -use Microsoft\PhpParser\Token; use Microsoft\PhpParser\DiagnosticsProvider; use PHPUnit\Framework\Test; use PHPUnit\Framework\TestCase; @@ -123,7 +122,7 @@ public function testSpecOutputTreeClassificationAndLength($testCaseFile, $expect } public function outTreeProvider() { - $testCases = glob(__dir__ . "/cases/php-langspec/**/*.php"); + $testCases = glob(__DIR__ . "/cases/php-langspec/**/*.php"); $skipped = json_decode(file_get_contents(__DIR__ . "/skipped.json")); $testProviderArray = array(); From a56215494fec4928b8448b0617fd26cb5ff73bb2 Mon Sep 17 00:00:00 2001 From: Felix Siebeneicker Date: Fri, 7 Aug 2020 13:12:35 +0200 Subject: [PATCH 5/6] Fixing start tag length by including whitespace tokens --- tests/cases/parser/declareStatement14.php.tree | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/parser/declareStatement14.php.tree b/tests/cases/parser/declareStatement14.php.tree index 4c0d6b63..20b67ef2 100644 --- a/tests/cases/parser/declareStatement14.php.tree +++ b/tests/cases/parser/declareStatement14.php.tree @@ -7,7 +7,7 @@ "text": null, "scriptSectionStartTag": { "kind": "ScriptSectionStartTag", - "textLength": 7 + "textLength": 6 } } }, From ec691a001d0a7ca627c1932a35441812f4dfe7e5 Mon Sep 17 00:00:00 2001 From: Felix Siebeneicker Date: Mon, 10 Aug 2020 10:27:54 +0200 Subject: [PATCH 6/6] Making changes backwards compatible --- src/Node/Statement/DeclareStatement.php | 12 ++- src/Parser.php | 57 ++++++++++-- tests/cases/parser/declareStatement1.php.tree | 35 ++++---- .../cases/parser/declareStatement10.php.tree | 35 ++++---- .../cases/parser/declareStatement11.php.tree | 35 ++++---- .../cases/parser/declareStatement12.php.diag | 21 ++++- .../cases/parser/declareStatement12.php.tree | 21 ++++- .../cases/parser/declareStatement13.php.tree | 35 ++++---- tests/cases/parser/declareStatement14.php | 2 - .../cases/parser/declareStatement14.php.tree | 66 ++++---------- tests/cases/parser/declareStatement15.php | 3 + .../cases/parser/declareStatement15.php.diag | 14 +++ .../cases/parser/declareStatement15.php.tree | 87 +++++++++++++++++++ tests/cases/parser/declareStatement16.php | 3 + .../cases/parser/declareStatement16.php.diag | 1 + .../cases/parser/declareStatement16.php.tree | 60 +++++++++++++ tests/cases/parser/declareStatement2.php.tree | 35 ++++---- tests/cases/parser/declareStatement3.php.tree | 35 ++++---- tests/cases/parser/declareStatement4.php.tree | 35 ++++---- tests/cases/parser/declareStatement5.php.tree | 35 ++++---- tests/cases/parser/declareStatement6.php.tree | 35 ++++---- tests/cases/parser/declareStatement7.php.tree | 37 ++++---- tests/cases/parser/declareStatement8.php.tree | 35 ++++---- tests/cases/parser/declareStatement9.php.tree | 37 ++++---- 24 files changed, 464 insertions(+), 307 deletions(-) create mode 100644 tests/cases/parser/declareStatement15.php create mode 100644 tests/cases/parser/declareStatement15.php.diag create mode 100644 tests/cases/parser/declareStatement15.php.tree create mode 100644 tests/cases/parser/declareStatement16.php create mode 100644 tests/cases/parser/declareStatement16.php.diag create mode 100644 tests/cases/parser/declareStatement16.php.tree diff --git a/src/Node/Statement/DeclareStatement.php b/src/Node/Statement/DeclareStatement.php index 0066d490..fcf39715 100644 --- a/src/Node/Statement/DeclareStatement.php +++ b/src/Node/Statement/DeclareStatement.php @@ -6,7 +6,8 @@ namespace Microsoft\PhpParser\Node\Statement; -use Microsoft\PhpParser\Node\DelimitedList\DeclareDirectiveList; +use Microsoft\PhpParser\Node; +use Microsoft\PhpParser\Node\DelimitedList; use Microsoft\PhpParser\Node\StatementNode; use Microsoft\PhpParser\Token; @@ -15,8 +16,10 @@ class DeclareStatement extends StatementNode { public $declareKeyword; /** @var Token */ public $openParen; - /** @var DeclareDirectiveList */ - public $declareDirectives; + /** @var Node */ + public $declareDirective; + /** @var DelimitedList\DeclareDirectiveList|null TODO: Merge with $declareDirective in a future backwards incompatible release. */ + public $otherDeclareDirectives; /** @var Token */ public $closeParen; /** @var Token|null */ @@ -31,7 +34,8 @@ class DeclareStatement extends StatementNode { const CHILD_NAMES = [ 'declareKeyword', 'openParen', - 'declareDirectives', + 'declareDirective', + 'otherDeclareDirectives', 'closeParen', 'colon', 'statements', diff --git a/src/Parser.php b/src/Parser.php index 0566f896..8d2e82d6 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -2308,14 +2308,7 @@ private function parseDeclareStatement($parentNode) { $declareStatement->parent = $parentNode; $declareStatement->declareKeyword = $this->eat1(TokenKind::DeclareKeyword); $declareStatement->openParen = $this->eat1(TokenKind::OpenParenToken); - $declareStatement->declareDirectives = $this->parseDelimitedList( - DelimitedList\DeclareDirectiveList::class, - TokenKind::CommaToken, - function ($token) { - return $token->kind === TokenKind::Name; - }, - $this->parseDeclareDirectiveFn(), - $declareStatement); + $this->parseAndSetDeclareDirectiveList($declareStatement); $declareStatement->closeParen = $this->eat1(TokenKind::CloseParenToken); if ($this->checkToken(TokenKind::SemicolonToken)) { @@ -2332,6 +2325,54 @@ function ($token) { return $declareStatement; } + /** + * @param DeclareStatement $parentNode + */ + private function parseAndSetDeclareDirectiveList($parentNode) { + $declareDirectiveList = $this->parseDeclareDirectiveList($parentNode); + + if (!$declareDirectiveList) { + $declareDirective = new DeclareDirective(); + $declareDirective->parent = $parentNode; + + $declareDirective->name = new MissingToken(TokenKind::Name, $this->token->fullStart); + $declareDirective->equals = new MissingToken(TokenKind::EqualsToken, $this->token->fullStart); + // TODO: This is matching the first token in $this::parseDeclareDirectiveFn. + // Probably best to emit a more general "literal error". + $declareDirective->literal = new MissingToken(TokenKind::FloatingLiteralToken, $this->token->fullStart); + + $parentNode->declareDirective = $declareDirective; + return; + } + + $declareDirective = array_shift($declareDirectiveList->children); + $parentNode->declareDirective = $declareDirective; + $declareDirective->parent = $parentNode; + + if ($declareDirectiveList->children) { + $parentNode->otherDeclareDirectives = $declareDirectiveList; + } + } + + /** + * @param DeclareStatement $parentNode + * @return DelimitedList\DeclareDirectiveList|null + */ + private function parseDeclareDirectiveList($parentNode) { + $declareDirectiveList = $this->parseDelimitedList( + DelimitedList\DeclareDirectiveList::class, + TokenKind::CommaToken, + function ($token) { + return $token->kind === TokenKind::Name; + }, + $this->parseDeclareDirectiveFn(), + $parentNode, + false + ); + + return $declareDirectiveList; + } + private function parseDeclareDirectiveFn() { return function ($parentNode) { $declareDirective = new DeclareDirective(); diff --git a/tests/cases/parser/declareStatement1.php.tree b/tests/cases/parser/declareStatement1.php.tree index 42cdec0e..f991f2f1 100644 --- a/tests/cases/parser/declareStatement1.php.tree +++ b/tests/cases/parser/declareStatement1.php.tree @@ -21,28 +21,23 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirectives": { - "DeclareDirectiveList": { - "children": [ - { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "IntegerLiteralToken", - "textLength": 1 - } - } - } - ] + "declareDirective": { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "IntegerLiteralToken", + "textLength": 1 + } } }, + "otherDeclareDirectives": null, "closeParen": { "kind": "CloseParenToken", "textLength": 1 diff --git a/tests/cases/parser/declareStatement10.php.tree b/tests/cases/parser/declareStatement10.php.tree index adeb8a5e..2bece8e3 100644 --- a/tests/cases/parser/declareStatement10.php.tree +++ b/tests/cases/parser/declareStatement10.php.tree @@ -21,28 +21,23 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirectives": { - "DeclareDirectiveList": { - "children": [ - { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "FloatingLiteralToken", - "textLength": 3 - } - } - } - ] + "declareDirective": { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "FloatingLiteralToken", + "textLength": 3 + } } }, + "otherDeclareDirectives": null, "closeParen": { "kind": "CloseParenToken", "textLength": 1 diff --git a/tests/cases/parser/declareStatement11.php.tree b/tests/cases/parser/declareStatement11.php.tree index e437b41d..8cbbd70f 100644 --- a/tests/cases/parser/declareStatement11.php.tree +++ b/tests/cases/parser/declareStatement11.php.tree @@ -21,28 +21,23 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirectives": { - "DeclareDirectiveList": { - "children": [ - { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "FloatingLiteralToken", - "textLength": 3 - } - } - } - ] + "declareDirective": { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "FloatingLiteralToken", + "textLength": 3 + } } }, + "otherDeclareDirectives": null, "closeParen": { "kind": "CloseParenToken", "textLength": 1 diff --git a/tests/cases/parser/declareStatement12.php.diag b/tests/cases/parser/declareStatement12.php.diag index 0637a088..41d4ac51 100644 --- a/tests/cases/parser/declareStatement12.php.diag +++ b/tests/cases/parser/declareStatement12.php.diag @@ -1 +1,20 @@ -[] \ No newline at end of file +[ + { + "kind": 0, + "message": "'Name' expected.", + "start": 16, + "length": 0 + }, + { + "kind": 0, + "message": "'=' expected.", + "start": 16, + "length": 0 + }, + { + "kind": 0, + "message": "'FloatingLiteralToken' expected.", + "start": 16, + "length": 0 + } +] \ No newline at end of file diff --git a/tests/cases/parser/declareStatement12.php.tree b/tests/cases/parser/declareStatement12.php.tree index 7c98f4e6..b958b359 100644 --- a/tests/cases/parser/declareStatement12.php.tree +++ b/tests/cases/parser/declareStatement12.php.tree @@ -21,7 +21,26 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirectives": null, + "declareDirective": { + "DeclareDirective": { + "name": { + "error": "MissingToken", + "kind": "Name", + "textLength": 0 + }, + "equals": { + "error": "MissingToken", + "kind": "EqualsToken", + "textLength": 0 + }, + "literal": { + "error": "MissingToken", + "kind": "FloatingLiteralToken", + "textLength": 0 + } + } + }, + "otherDeclareDirectives": null, "closeParen": { "kind": "CloseParenToken", "textLength": 1 diff --git a/tests/cases/parser/declareStatement13.php.tree b/tests/cases/parser/declareStatement13.php.tree index 0f13cdcf..70b508d7 100644 --- a/tests/cases/parser/declareStatement13.php.tree +++ b/tests/cases/parser/declareStatement13.php.tree @@ -21,28 +21,23 @@ "kind": "OpenParenToken", "textLength": 1 }, - "declareDirectives": { - "DeclareDirectiveList": { - "children": [ - { - "DeclareDirective": { - "name": { - "kind": "Name", - "textLength": 5 - }, - "equals": { - "kind": "EqualsToken", - "textLength": 1 - }, - "literal": { - "kind": "IntegerLiteralToken", - "textLength": 1 - } - } - } - ] + "declareDirective": { + "DeclareDirective": { + "name": { + "kind": "Name", + "textLength": 5 + }, + "equals": { + "kind": "EqualsToken", + "textLength": 1 + }, + "literal": { + "kind": "IntegerLiteralToken", + "textLength": 1 + } } }, + "otherDeclareDirectives": null, "closeParen": { "kind": "CloseParenToken", "textLength": 1 diff --git a/tests/cases/parser/declareStatement14.php b/tests/cases/parser/declareStatement14.php index 88349bb7..f1c5bf99 100644 --- a/tests/cases/parser/declareStatement14.php +++ b/tests/cases/parser/declareStatement14.php @@ -1,5 +1,3 @@