Skip to content

Commit 3274f21

Browse files
authored
Merge pull request #14 from phan/fix-namespace-handling
Fix namespace handling of keywords
2 parents aceb541 + 686aa8b commit 3274f21

File tree

6 files changed

+63
-30
lines changed

6 files changed

+63
-30
lines changed

src/Parser.php

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}
Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1 @@
1-
[
2-
{
3-
"kind": 0,
4-
"message": "'QualifiedName' expected.",
5-
"start": 64,
6-
"length": 0
7-
}
8-
]
1+
[]

tests/cases/parser/namespaceDefinition2.php.tree

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@
1717
"kind": "NamespaceKeyword",
1818
"textLength": 9
1919
},
20-
"name": {
21-
"error": "MissingToken",
22-
"kind": "QualifiedName",
23-
"textLength": 0
24-
},
20+
"name": null,
2521
"compoundStatementOrSemicolon": {
2622
"kind": "SemicolonToken",
2723
"textLength": 1
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?php
2+
namespace global;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[]
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"SourceFileNode": {
3+
"statementList": [
4+
{
5+
"InlineHtml": {
6+
"scriptSectionEndTag": null,
7+
"text": null,
8+
"scriptSectionStartTag": {
9+
"kind": "ScriptSectionStartTag",
10+
"textLength": 6
11+
}
12+
}
13+
},
14+
{
15+
"NamespaceDefinition": {
16+
"namespaceKeyword": {
17+
"kind": "NamespaceKeyword",
18+
"textLength": 9
19+
},
20+
"name": {
21+
"QualifiedName": {
22+
"globalSpecifier": null,
23+
"relativeSpecifier": null,
24+
"nameParts": [
25+
{
26+
"kind": "Name",
27+
"textLength": 6
28+
}
29+
]
30+
}
31+
},
32+
"compoundStatementOrSemicolon": {
33+
"kind": "SemicolonToken",
34+
"textLength": 1
35+
}
36+
}
37+
}
38+
],
39+
"endOfFileToken": {
40+
"kind": "EndOfFileToken",
41+
"textLength": 0
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)