@@ -132,6 +132,7 @@ class Parser {
132132 private $ nameOrKeywordOrReservedWordTokens ;
133133 private $ nameOrReservedWordTokens ;
134134 private $ nameOrStaticOrReservedWordTokens ;
135+ private $ nameOrKeywordOrReservedWordTokensExceptNamespace ;
135136 private $ reservedWordTokens ;
136137 private $ keywordTokens ;
137138 private $ argumentStartTokensSet ;
@@ -148,6 +149,10 @@ public function __construct() {
148149 $ this ->nameOrKeywordOrReservedWordTokens = \array_merge ([TokenKind::Name], $ this ->keywordTokens , $ this ->reservedWordTokens );
149150 $ this ->nameOrReservedWordTokens = \array_merge ([TokenKind::Name], $ this ->reservedWordTokens );
150151 $ this ->nameOrStaticOrReservedWordTokens = \array_merge ([TokenKind::Name, TokenKind::StaticKeyword], $ this ->reservedWordTokens );
152+ $ this ->nameOrKeywordOrReservedWordTokensExceptNamespace = \array_values (\array_diff (
153+ $ this ->nameOrKeywordOrReservedWordTokens ,
154+ [TokenKind::NamespaceKeyword]
155+ ));
151156 $ this ->parameterTypeDeclarationTokens =
152157 [TokenKind::ArrayKeyword, TokenKind::CallableKeyword, TokenKind::BoolReservedWord,
153158 TokenKind::FloatReservedWord, TokenKind::IntReservedWord, TokenKind::StringReservedWord,
@@ -1872,23 +1877,13 @@ private function parseQualifiedNameFn() {
18721877 DelimitedList \QualifiedNameParts::class,
18731878 TokenKind::BackslashToken,
18741879 function ($ token ) {
1875- // a\static() <- INVALID (but not checked for right now)
1876- // new a\static() <- INVALID
1877- // new static() <- VALID
1878- // a\static\b <- INVALID
1879- // a\function <- INVALID
1880- // a\true\b <-VALID
1881- // a\b\true <-VALID
1882- // a\static::b <-VALID
1883- // TODO more tests
1884- return $ this ->lookahead (TokenKind::BackslashToken)
1885- ? in_array ($ token ->kind , $ this ->nameOrReservedWordTokens )
1886- : in_array ($ token ->kind , $ this ->nameOrStaticOrReservedWordTokens );
1880+ if ($ token ->kind === TokenKind::NamespaceKeyword) {
1881+ return false ;
1882+ }
1883+ return \in_array ($ token ->kind , $ this ->nameOrKeywordOrReservedWordTokensExceptNamespace , true );
18871884 },
18881885 function ($ parentNode ) {
1889- $ name = $ this ->lookahead (TokenKind::BackslashToken)
1890- ? $ this ->eat ($ this ->nameOrReservedWordTokens )
1891- : $ this ->eat ($ this ->nameOrStaticOrReservedWordTokens ); // TODO support keyword name
1886+ $ name = $ this ->eat ($ this ->nameOrKeywordOrReservedWordTokensExceptNamespace ); // TODO support keyword name
18921887 $ name ->kind = TokenKind::Name; // bool/true/null/static should not be treated as keywords in this case
18931888 return $ name ;
18941889 }, $ node );
@@ -3929,8 +3924,10 @@ private function parseNamespaceDefinition($parentNode) {
39293924 $ namespaceDefinition ->compoundStatementOrSemicolon = $ this ->parseCompoundStatement ($ namespaceDefinition );
39303925 } else {
39313926 if (!$ namespaceDefinition ->name ) {
3932- // only optional with compound statement block
3933- $ namespaceDefinition ->name = new MissingToken (TokenKind::QualifiedName, $ this ->token ->fullStart );
3927+ if (!$ this ->checkToken (TokenKind::SemicolonToken)) {
3928+ // name is only optional when followed by a semicolon (global namespace)
3929+ $ namespaceDefinition ->name = new MissingToken (TokenKind::QualifiedName, $ this ->token ->fullStart );
3930+ }
39343931 }
39353932 $ namespaceDefinition ->compoundStatementOrSemicolon = $ this ->eatSemicolonOrAbortStatement ();
39363933 }
0 commit comments