Skip to content

Commit 3aadc15

Browse files
committed
Support keywords in namespaced names
1 parent a983505 commit 3aadc15

File tree

3 files changed

+76
-3
lines changed

3 files changed

+76
-3
lines changed

lib/PhpParser/Lexer.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class Lexer
1515

1616
protected $tokenMap;
1717
protected $dropTokens;
18+
protected $identifierTokens;
1819

1920
private $attributeStartLineUsed;
2021
private $attributeEndLineUsed;
@@ -37,6 +38,7 @@ public function __construct(array $options = []) {
3738
// Create Map from internal tokens to PhpParser tokens.
3839
$this->defineCompatibilityTokens();
3940
$this->tokenMap = $this->createTokenMap();
41+
$this->identifierTokens = $this->createIdentifierTokenMap();
4042

4143
// map of tokens to drop while lexing (the map is only used for isset lookup,
4244
// that's why the value is simply set to 1; the value is never actually used.)
@@ -170,14 +172,13 @@ protected function postprocessTokens(ErrorHandler $errorHandler) {
170172

171173
// Emulate PHP 8 T_NAME_* tokens, by combining sequences of T_NS_SEPARATOR and T_STRING
172174
// into a single token.
173-
// TODO: Also handle reserved keywords in namespaced names.
174175
if (\is_array($token)
175-
&& ($token[0] === \T_NS_SEPARATOR || $token[0] === \T_STRING || $token[0] === \T_NAMESPACE)) {
176+
&& ($token[0] === \T_NS_SEPARATOR || isset($this->identifierTokens[$token[0]]))) {
176177
$lastWasSeparator = $token[0] === \T_NS_SEPARATOR;
177178
$text = $token[1];
178179
for ($j = $i + 1; isset($this->tokens[$j]); $j++) {
179180
if ($lastWasSeparator) {
180-
if ($this->tokens[$j][0] !== \T_STRING) {
181+
if (!isset($this->identifierTokens[$this->tokens[$j][0]])) {
181182
break;
182183
}
183184
$lastWasSeparator = false;
@@ -488,4 +489,19 @@ protected function createTokenMap() : array {
488489

489490
return $tokenMap;
490491
}
492+
493+
private function createIdentifierTokenMap(): array {
494+
// Based on semi_reserved production.
495+
return array_fill_keys([
496+
\T_STRING,
497+
\T_INCLUDE, \T_INCLUDE_ONCE, \T_EVAL, \T_REQUIRE, \T_REQUIRE_ONCE, \T_LOGICAL_OR, \T_LOGICAL_XOR, \T_LOGICAL_AND,
498+
\T_INSTANCEOF, \T_NEW, \T_CLONE, \T_EXIT, \T_IF, \T_ELSEIF, \T_ELSE, \T_ENDIF, \T_ECHO, \T_DO, \T_WHILE,
499+
\T_ENDWHILE, \T_FOR, \T_ENDFOR, \T_FOREACH, \T_ENDFOREACH, \T_DECLARE, \T_ENDDECLARE, \T_AS, \T_TRY, \T_CATCH,
500+
\T_FINALLY, \T_THROW, \T_USE, \T_INSTEADOF, \T_GLOBAL, \T_VAR, \T_UNSET, \T_ISSET, \T_EMPTY, \T_CONTINUE, \T_GOTO,
501+
\T_FUNCTION, \T_CONST, \T_RETURN, \T_PRINT, \T_YIELD, \T_LIST, \T_SWITCH, \T_ENDSWITCH, \T_CASE, \T_DEFAULT,
502+
\T_BREAK, \T_ARRAY, \T_CALLABLE, \T_EXTENDS, \T_IMPLEMENTS, \T_NAMESPACE, \T_TRAIT, \T_INTERFACE, \T_CLASS,
503+
\T_CLASS_C, \T_TRAIT_C, \T_FUNC_C, \T_METHOD_C, \T_LINE, \T_FILE, \T_DIR, \T_NS_C, \T_HALT_COMPILER, \T_FN,
504+
\T_MATCH,
505+
], true);
506+
}
491507
}

test/PhpParser/LexerTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,18 @@ public function provideTestLex() {
227227
[Tokens::T_NS_SEPARATOR, '\\', [], []],
228228
]
229229
],
230+
// tests PHP 8 T_NAME_* emulation with reserved keywords
231+
[
232+
'<?php fn\use \fn\use namespace\fn\use fn\use\\',
233+
['usedAttributes' => []],
234+
[
235+
[Tokens::T_NAME_QUALIFIED, 'fn\use', [], []],
236+
[Tokens::T_NAME_FULLY_QUALIFIED, '\fn\use', [], []],
237+
[Tokens::T_NAME_RELATIVE, 'namespace\fn\use', [], []],
238+
[Tokens::T_NAME_QUALIFIED, 'fn\use', [], []],
239+
[Tokens::T_NS_SEPARATOR, '\\', [], []],
240+
]
241+
],
230242
];
231243
}
232244

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
Keywords in namespaced name
2+
-----
3+
<?php
4+
fn\use();
5+
\fn\use();
6+
namespace\fn\use();
7+
-----
8+
array(
9+
0: Stmt_Expression(
10+
expr: Expr_FuncCall(
11+
name: Name(
12+
parts: array(
13+
0: fn
14+
1: use
15+
)
16+
)
17+
args: array(
18+
)
19+
)
20+
)
21+
1: Stmt_Expression(
22+
expr: Expr_FuncCall(
23+
name: Name_FullyQualified(
24+
parts: array(
25+
0: fn
26+
1: use
27+
)
28+
)
29+
args: array(
30+
)
31+
)
32+
)
33+
2: Stmt_Expression(
34+
expr: Expr_FuncCall(
35+
name: Name_Relative(
36+
parts: array(
37+
0: fn
38+
1: use
39+
)
40+
)
41+
args: array(
42+
)
43+
)
44+
)
45+
)

0 commit comments

Comments
 (0)