mirror of
https://github.com/phabelio/PHP-Parser.git
synced 2024-12-02 17:38:19 +01:00
Support keywords in namespaced names
This commit is contained in:
parent
a98350581c
commit
3aadc15e2e
@ -15,6 +15,7 @@ class Lexer
|
|||||||
|
|
||||||
protected $tokenMap;
|
protected $tokenMap;
|
||||||
protected $dropTokens;
|
protected $dropTokens;
|
||||||
|
protected $identifierTokens;
|
||||||
|
|
||||||
private $attributeStartLineUsed;
|
private $attributeStartLineUsed;
|
||||||
private $attributeEndLineUsed;
|
private $attributeEndLineUsed;
|
||||||
@ -37,6 +38,7 @@ class Lexer
|
|||||||
// Create Map from internal tokens to PhpParser tokens.
|
// Create Map from internal tokens to PhpParser tokens.
|
||||||
$this->defineCompatibilityTokens();
|
$this->defineCompatibilityTokens();
|
||||||
$this->tokenMap = $this->createTokenMap();
|
$this->tokenMap = $this->createTokenMap();
|
||||||
|
$this->identifierTokens = $this->createIdentifierTokenMap();
|
||||||
|
|
||||||
// map of tokens to drop while lexing (the map is only used for isset lookup,
|
// map of tokens to drop while lexing (the map is only used for isset lookup,
|
||||||
// that's why the value is simply set to 1; the value is never actually used.)
|
// that's why the value is simply set to 1; the value is never actually used.)
|
||||||
@ -170,14 +172,13 @@ class Lexer
|
|||||||
|
|
||||||
// Emulate PHP 8 T_NAME_* tokens, by combining sequences of T_NS_SEPARATOR and T_STRING
|
// Emulate PHP 8 T_NAME_* tokens, by combining sequences of T_NS_SEPARATOR and T_STRING
|
||||||
// into a single token.
|
// into a single token.
|
||||||
// TODO: Also handle reserved keywords in namespaced names.
|
|
||||||
if (\is_array($token)
|
if (\is_array($token)
|
||||||
&& ($token[0] === \T_NS_SEPARATOR || $token[0] === \T_STRING || $token[0] === \T_NAMESPACE)) {
|
&& ($token[0] === \T_NS_SEPARATOR || isset($this->identifierTokens[$token[0]]))) {
|
||||||
$lastWasSeparator = $token[0] === \T_NS_SEPARATOR;
|
$lastWasSeparator = $token[0] === \T_NS_SEPARATOR;
|
||||||
$text = $token[1];
|
$text = $token[1];
|
||||||
for ($j = $i + 1; isset($this->tokens[$j]); $j++) {
|
for ($j = $i + 1; isset($this->tokens[$j]); $j++) {
|
||||||
if ($lastWasSeparator) {
|
if ($lastWasSeparator) {
|
||||||
if ($this->tokens[$j][0] !== \T_STRING) {
|
if (!isset($this->identifierTokens[$this->tokens[$j][0]])) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$lastWasSeparator = false;
|
$lastWasSeparator = false;
|
||||||
@ -488,4 +489,19 @@ class Lexer
|
|||||||
|
|
||||||
return $tokenMap;
|
return $tokenMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function createIdentifierTokenMap(): array {
|
||||||
|
// Based on semi_reserved production.
|
||||||
|
return array_fill_keys([
|
||||||
|
\T_STRING,
|
||||||
|
\T_INCLUDE, \T_INCLUDE_ONCE, \T_EVAL, \T_REQUIRE, \T_REQUIRE_ONCE, \T_LOGICAL_OR, \T_LOGICAL_XOR, \T_LOGICAL_AND,
|
||||||
|
\T_INSTANCEOF, \T_NEW, \T_CLONE, \T_EXIT, \T_IF, \T_ELSEIF, \T_ELSE, \T_ENDIF, \T_ECHO, \T_DO, \T_WHILE,
|
||||||
|
\T_ENDWHILE, \T_FOR, \T_ENDFOR, \T_FOREACH, \T_ENDFOREACH, \T_DECLARE, \T_ENDDECLARE, \T_AS, \T_TRY, \T_CATCH,
|
||||||
|
\T_FINALLY, \T_THROW, \T_USE, \T_INSTEADOF, \T_GLOBAL, \T_VAR, \T_UNSET, \T_ISSET, \T_EMPTY, \T_CONTINUE, \T_GOTO,
|
||||||
|
\T_FUNCTION, \T_CONST, \T_RETURN, \T_PRINT, \T_YIELD, \T_LIST, \T_SWITCH, \T_ENDSWITCH, \T_CASE, \T_DEFAULT,
|
||||||
|
\T_BREAK, \T_ARRAY, \T_CALLABLE, \T_EXTENDS, \T_IMPLEMENTS, \T_NAMESPACE, \T_TRAIT, \T_INTERFACE, \T_CLASS,
|
||||||
|
\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,
|
||||||
|
\T_MATCH,
|
||||||
|
], true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,6 +227,18 @@ class LexerTest extends \PHPUnit\Framework\TestCase
|
|||||||
[Tokens::T_NS_SEPARATOR, '\\', [], []],
|
[Tokens::T_NS_SEPARATOR, '\\', [], []],
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
// tests PHP 8 T_NAME_* emulation with reserved keywords
|
||||||
|
[
|
||||||
|
'<?php fn\use \fn\use namespace\fn\use fn\use\\',
|
||||||
|
['usedAttributes' => []],
|
||||||
|
[
|
||||||
|
[Tokens::T_NAME_QUALIFIED, 'fn\use', [], []],
|
||||||
|
[Tokens::T_NAME_FULLY_QUALIFIED, '\fn\use', [], []],
|
||||||
|
[Tokens::T_NAME_RELATIVE, 'namespace\fn\use', [], []],
|
||||||
|
[Tokens::T_NAME_QUALIFIED, 'fn\use', [], []],
|
||||||
|
[Tokens::T_NS_SEPARATOR, '\\', [], []],
|
||||||
|
]
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
45
test/code/parser/expr/keywordsInNamespacedName.test
Normal file
45
test/code/parser/expr/keywordsInNamespacedName.test
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
Keywords in namespaced name
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
fn\use();
|
||||||
|
\fn\use();
|
||||||
|
namespace\fn\use();
|
||||||
|
-----
|
||||||
|
array(
|
||||||
|
0: Stmt_Expression(
|
||||||
|
expr: Expr_FuncCall(
|
||||||
|
name: Name(
|
||||||
|
parts: array(
|
||||||
|
0: fn
|
||||||
|
1: use
|
||||||
|
)
|
||||||
|
)
|
||||||
|
args: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
1: Stmt_Expression(
|
||||||
|
expr: Expr_FuncCall(
|
||||||
|
name: Name_FullyQualified(
|
||||||
|
parts: array(
|
||||||
|
0: fn
|
||||||
|
1: use
|
||||||
|
)
|
||||||
|
)
|
||||||
|
args: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
2: Stmt_Expression(
|
||||||
|
expr: Expr_FuncCall(
|
||||||
|
name: Name_Relative(
|
||||||
|
parts: array(
|
||||||
|
0: fn
|
||||||
|
1: use
|
||||||
|
)
|
||||||
|
)
|
||||||
|
args: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user