diff --git a/src/Parser.php b/src/Parser.php index b2bcd6a..5310c59 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -3307,7 +3307,7 @@ class Parser { if ($classBaseClause->extendsKeyword === null) { return null; } - $classBaseClause->baseClass = $this->parseQualifiedName($classBaseClause); + $classBaseClause->baseClass = $this->parseQualifiedName($classBaseClause) ?? new MissingToken(TokenKind::QualifiedName, $this->token->fullStart); return $classBaseClause; } @@ -3500,12 +3500,18 @@ class Parser { $namespaceDefinition->namespaceKeyword = $this->eat1(TokenKind::NamespaceKeyword); if (!$this->checkToken(TokenKind::NamespaceKeyword)) { - $namespaceDefinition->name = $this->parseQualifiedName($namespaceDefinition); // TODO only optional with compound statement block + $namespaceDefinition->name = $this->parseQualifiedName($namespaceDefinition); } - $namespaceDefinition->compoundStatementOrSemicolon = - $this->checkToken(TokenKind::OpenBraceToken) ? - $this->parseCompoundStatement($namespaceDefinition) : $this->eatSemicolonOrAbortStatement(); + if ($this->checkToken(TokenKind::OpenBraceToken)) { + $namespaceDefinition->compoundStatementOrSemicolon = $this->parseCompoundStatement($namespaceDefinition); + } else { + if (!$namespaceDefinition->name) { + // only optional with compound statement block + $namespaceDefinition->name = new MissingToken(TokenKind::QualifiedName, $this->token->fullStart); + } + $namespaceDefinition->compoundStatementOrSemicolon = $this->eatSemicolonOrAbortStatement(); + } return $namespaceDefinition; } @@ -3531,13 +3537,17 @@ class Parser { $namespaceUseClause = new NamespaceUseClause(); $namespaceUseClause->parent = $parentNode; $namespaceUseClause->namespaceName = $this->parseQualifiedName($namespaceUseClause); - if ($this->checkToken(TokenKind::AsKeyword)) { - $namespaceUseClause->namespaceAliasingClause = $this->parseNamespaceAliasingClause($namespaceUseClause); - } - elseif ($this->checkToken(TokenKind::OpenBraceToken)) { + if ($this->checkToken(TokenKind::OpenBraceToken)) { $namespaceUseClause->openBrace = $this->eat1(TokenKind::OpenBraceToken); $namespaceUseClause->groupClauses = $this->parseNamespaceUseGroupClauseList($namespaceUseClause); $namespaceUseClause->closeBrace = $this->eat1(TokenKind::CloseBraceToken); + } else { + if (!$namespaceUseClause->namespaceName) { + $namespaceUseClause->namespaceName = new MissingToken(TokenKind::QualifiedName, $this->token->fullStart); + } + if ($this->checkToken(TokenKind::AsKeyword)) { + $namespaceUseClause->namespaceAliasingClause = $this->parseNamespaceAliasingClause($namespaceUseClause); + } } return $namespaceUseClause; @@ -3558,7 +3568,7 @@ class Parser { $namespaceUseGroupClause->parent = $parentNode; $namespaceUseGroupClause->functionOrConst = $this->eatOptional(TokenKind::FunctionKeyword, TokenKind::ConstKeyword); - $namespaceUseGroupClause->namespaceName = $this->parseQualifiedName($namespaceUseGroupClause); + $namespaceUseGroupClause->namespaceName = $this->parseQualifiedName($namespaceUseGroupClause) ?? new MissingToken(TokenKind::QualifiedName, $this->token->fullStart); if ($this->checkToken(TokenKind::AsKeyword)) { $namespaceUseGroupClause->namespaceAliasingClause = $this->parseNamespaceAliasingClause($namespaceUseGroupClause); } diff --git a/tests/cases/parser/classBaseClause2.php.diag b/tests/cases/parser/classBaseClause2.php.diag index 0637a08..c056680 100644 --- a/tests/cases/parser/classBaseClause2.php.diag +++ b/tests/cases/parser/classBaseClause2.php.diag @@ -1 +1,8 @@ -[] \ No newline at end of file +[ + { + "kind": 0, + "message": "'QualifiedName' expected.", + "start": 48, + "length": 0 + } +] \ No newline at end of file diff --git a/tests/cases/parser/classBaseClause2.php.tree b/tests/cases/parser/classBaseClause2.php.tree index 3ce64cc..4c7db22 100644 --- a/tests/cases/parser/classBaseClause2.php.tree +++ b/tests/cases/parser/classBaseClause2.php.tree @@ -30,7 +30,11 @@ "kind": "ExtendsKeyword", "textLength": 7 }, - "baseClass": null + "baseClass": { + "error": "MissingToken", + "kind": "QualifiedName", + "textLength": 0 + } } }, "classInterfaceClause": null, diff --git a/tests/cases/parser/namespaceDefinition2.php.diag b/tests/cases/parser/namespaceDefinition2.php.diag index 0637a08..d361d02 100644 --- a/tests/cases/parser/namespaceDefinition2.php.diag +++ b/tests/cases/parser/namespaceDefinition2.php.diag @@ -1 +1,8 @@ -[] \ No newline at end of file +[ + { + "kind": 0, + "message": "'QualifiedName' expected.", + "start": 64, + "length": 0 + } +] \ No newline at end of file diff --git a/tests/cases/parser/namespaceDefinition2.php.tree b/tests/cases/parser/namespaceDefinition2.php.tree index 313ae4b..e0f932f 100644 --- a/tests/cases/parser/namespaceDefinition2.php.tree +++ b/tests/cases/parser/namespaceDefinition2.php.tree @@ -17,7 +17,11 @@ "kind": "NamespaceKeyword", "textLength": 9 }, - "name": null, + "name": { + "error": "MissingToken", + "kind": "QualifiedName", + "textLength": 0 + }, "compoundStatementOrSemicolon": { "kind": "SemicolonToken", "textLength": 1 diff --git a/tests/cases/parser/namespaceDefinition4.php.diag b/tests/cases/parser/namespaceDefinition4.php.diag index ebabd1a..1ae2311 100644 --- a/tests/cases/parser/namespaceDefinition4.php.diag +++ b/tests/cases/parser/namespaceDefinition4.php.diag @@ -1,10 +1,22 @@ [ + { + "kind": 0, + "message": "'QualifiedName' expected.", + "start": 16, + "length": 0 + }, { "kind": 0, "message": "';' expected.", "start": 16, "length": 0 }, + { + "kind": 0, + "message": "'QualifiedName' expected.", + "start": 26, + "length": 0 + }, { "kind": 0, "message": "';' expected.", diff --git a/tests/cases/parser/namespaceDefinition4.php.tree b/tests/cases/parser/namespaceDefinition4.php.tree index d333e97..b035fa1 100644 --- a/tests/cases/parser/namespaceDefinition4.php.tree +++ b/tests/cases/parser/namespaceDefinition4.php.tree @@ -17,7 +17,11 @@ "kind": "NamespaceKeyword", "textLength": 9 }, - "name": null, + "name": { + "error": "MissingToken", + "kind": "QualifiedName", + "textLength": 0 + }, "compoundStatementOrSemicolon": { "error": "MissingToken", "kind": "SemicolonToken", @@ -31,7 +35,11 @@ "kind": "NamespaceKeyword", "textLength": 9 }, - "name": null, + "name": { + "error": "MissingToken", + "kind": "QualifiedName", + "textLength": 0 + }, "compoundStatementOrSemicolon": { "error": "MissingToken", "kind": "SemicolonToken", diff --git a/tests/cases/parser/namespaceUseDeclaration33.php b/tests/cases/parser/namespaceUseDeclaration33.php new file mode 100644 index 0000000..6afbf52 --- /dev/null +++ b/tests/cases/parser/namespaceUseDeclaration33.php @@ -0,0 +1,2 @@ +