From cdc7feccc88bc32c3648588aa894bc23f258ec80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Wed, 14 Dec 2022 21:27:40 +0100 Subject: [PATCH] Drop doctrine/lexer 1 This allows us to introduce the TokenType enum that represents the type of DQL tokens. --- composer.json | 2 +- .../cookbook/dql-user-defined-functions.rst | 20 +- .../reference/dql-doctrine-query-language.rst | 8 +- .../ORM/Query/AST/Functions/AbsFunction.php | 8 +- .../Query/AST/Functions/BitAndFunction.php | 10 +- .../ORM/Query/AST/Functions/BitOrFunction.php | 10 +- .../Query/AST/Functions/ConcatFunction.php | 14 +- .../AST/Functions/CurrentDateFunction.php | 8 +- .../AST/Functions/CurrentTimeFunction.php | 8 +- .../Functions/CurrentTimestampFunction.php | 8 +- .../Query/AST/Functions/DateAddFunction.php | 12 +- .../Query/AST/Functions/DateDiffFunction.php | 10 +- .../Query/AST/Functions/IdentityFunction.php | 14 +- .../Query/AST/Functions/LengthFunction.php | 8 +- .../Query/AST/Functions/LocateFunction.php | 14 +- .../ORM/Query/AST/Functions/LowerFunction.php | 8 +- .../ORM/Query/AST/Functions/ModFunction.php | 10 +- .../ORM/Query/AST/Functions/SizeFunction.php | 8 +- .../ORM/Query/AST/Functions/SqrtFunction.php | 8 +- .../Query/AST/Functions/SubstringFunction.php | 14 +- .../ORM/Query/AST/Functions/TrimFunction.php | 20 +- .../ORM/Query/AST/Functions/UpperFunction.php | 8 +- lib/Doctrine/ORM/Query/Lexer.php | 134 +-- lib/Doctrine/ORM/Query/Parser.php | 845 +++++++++--------- lib/Doctrine/ORM/Query/TokenType.php | 92 ++ phpstan-baseline.neon | 2 +- psalm-baseline.xml | 28 +- .../ORM/Functional/CustomFunctionsTest.php | 8 +- .../ORM/Functional/Ticket/GH7286Test.php | 10 +- tests/Doctrine/Tests/ORM/Query/LexerTest.php | 65 +- tests/Doctrine/Tests/ORM/Query/ParserTest.php | 30 +- .../ORM/Query/SelectSqlGenerationTest.php | 8 +- 32 files changed, 729 insertions(+), 723 deletions(-) create mode 100644 lib/Doctrine/ORM/Query/TokenType.php diff --git a/composer.json b/composer.json index e127ac4c3a1..d716d360fda 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "doctrine/event-manager": "^1.2 || ^2", "doctrine/inflector": "^1.4 || ^2.0", "doctrine/instantiator": "^1.3", - "doctrine/lexer": "^1.2.3 || ^2", + "doctrine/lexer": "^2", "doctrine/persistence": "^3.1.1", "psr/cache": "^1 || ^2 || ^3", "symfony/console": "^5.4 || ^6.0" diff --git a/docs/en/cookbook/dql-user-defined-functions.rst b/docs/en/cookbook/dql-user-defined-functions.rst index 9345a2535e9..b189ed59fcd 100644 --- a/docs/en/cookbook/dql-user-defined-functions.rst +++ b/docs/en/cookbook/dql-user-defined-functions.rst @@ -99,12 +99,12 @@ discuss it step by step: public function parse(\Doctrine\ORM\Query\Parser $parser) { - $parser->match(Lexer::T_IDENTIFIER); // (2) - $parser->match(Lexer::T_OPEN_PARENTHESIS); // (3) + $parser->match(TokenType::T_IDENTIFIER); // (2) + $parser->match(TokenType::T_OPEN_PARENTHESIS); // (3) $this->firstDateExpression = $parser->ArithmeticPrimary(); // (4) - $parser->match(Lexer::T_COMMA); // (5) + $parser->match(TokenType::T_COMMA); // (5) $this->secondDateExpression = $parser->ArithmeticPrimary(); // (6) - $parser->match(Lexer::T_CLOSE_PARENTHESIS); // (3) + $parser->match(TokenType::T_CLOSE_PARENTHESIS); // (3) } public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) @@ -183,23 +183,23 @@ I'll skip the blah and show the code for this function: public function parse(\Doctrine\ORM\Query\Parser $parser) { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->firstDateExpression = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_COMMA); - $parser->match(Lexer::T_IDENTIFIER); + $parser->match(TokenType::T_COMMA); + $parser->match(TokenType::T_IDENTIFIER); $this->intervalExpression = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_IDENTIFIER); + $parser->match(TokenType::T_IDENTIFIER); /** @var Lexer $lexer */ $lexer = $parser->getLexer(); $this->unit = $lexer->token['value']; - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) diff --git a/docs/en/reference/dql-doctrine-query-language.rst b/docs/en/reference/dql-doctrine-query-language.rst index 57f2e91231c..127719b9738 100644 --- a/docs/en/reference/dql-doctrine-query-language.rst +++ b/docs/en/reference/dql-doctrine-query-language.rst @@ -807,7 +807,7 @@ classes have to implement the base class : namespace MyProject\Query\AST; use Doctrine\ORM\Query\AST\Functions\FunctionNode; - use Doctrine\ORM\Query\Lexer; + use Doctrine\ORM\Query\TokenType; class MysqlFloor extends FunctionNode { @@ -822,12 +822,12 @@ classes have to implement the base class : public function parse(\Doctrine\ORM\Query\Parser $parser) { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/AbsFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/AbsFunction.php index 0930faf2616..d9dd68bba0a 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/AbsFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/AbsFunction.php @@ -5,9 +5,9 @@ namespace Doctrine\ORM\Query\AST\Functions; use Doctrine\ORM\Query\AST\SimpleArithmeticExpression; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * "ABS" "(" SimpleArithmeticExpression ")" @@ -28,11 +28,11 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/BitAndFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/BitAndFunction.php index 1f67866c536..f2d3146d21e 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/BitAndFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/BitAndFunction.php @@ -5,9 +5,9 @@ namespace Doctrine\ORM\Query\AST\Functions; use Doctrine\ORM\Query\AST\Node; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * "BIT_AND" "(" ArithmeticPrimary "," ArithmeticPrimary ")" @@ -31,13 +31,13 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->firstArithmetic = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_COMMA); + $parser->match(TokenType::T_COMMA); $this->secondArithmetic = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/BitOrFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/BitOrFunction.php index 49d29a982cf..f3f84da56f6 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/BitOrFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/BitOrFunction.php @@ -5,9 +5,9 @@ namespace Doctrine\ORM\Query\AST\Functions; use Doctrine\ORM\Query\AST\Node; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * "BIT_OR" "(" ArithmeticPrimary "," ArithmeticPrimary ")" @@ -31,13 +31,13 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->firstArithmetic = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_COMMA); + $parser->match(TokenType::T_COMMA); $this->secondArithmetic = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/ConcatFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/ConcatFunction.php index 976a5a4bff1..5b8d69605d4 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/ConcatFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/ConcatFunction.php @@ -5,9 +5,9 @@ namespace Doctrine\ORM\Query\AST\Functions; use Doctrine\ORM\Query\AST\Node; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * "CONCAT" "(" StringPrimary "," StringPrimary {"," StringPrimary }* ")" @@ -37,22 +37,22 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->firstStringPrimary = $parser->StringPrimary(); $this->concatExpressions[] = $this->firstStringPrimary; - $parser->match(Lexer::T_COMMA); + $parser->match(TokenType::T_COMMA); $this->secondStringPrimary = $parser->StringPrimary(); $this->concatExpressions[] = $this->secondStringPrimary; - while ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) { - $parser->match(Lexer::T_COMMA); + while ($parser->getLexer()->isNextToken(TokenType::T_COMMA)) { + $parser->match(TokenType::T_COMMA); $this->concatExpressions[] = $parser->StringPrimary(); } - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php index 4c585d40c23..cec963269f0 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php @@ -4,9 +4,9 @@ namespace Doctrine\ORM\Query\AST\Functions; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * "CURRENT_DATE" @@ -22,8 +22,8 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimeFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimeFunction.php index 7cf2841129a..6473fcea494 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimeFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimeFunction.php @@ -4,9 +4,9 @@ namespace Doctrine\ORM\Query\AST\Functions; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * "CURRENT_TIME" @@ -22,8 +22,8 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimestampFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimestampFunction.php index 96d564be452..edcd27cfa11 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimestampFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimestampFunction.php @@ -4,9 +4,9 @@ namespace Doctrine\ORM\Query\AST\Functions; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * "CURRENT_TIMESTAMP" @@ -22,8 +22,8 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php index 33aca04f780..385ebac99c9 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php @@ -6,10 +6,10 @@ use Doctrine\ORM\Query\AST\ASTException; use Doctrine\ORM\Query\AST\Node; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\QueryException; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; use function assert; use function is_numeric; @@ -78,15 +78,15 @@ private function dispatchIntervalExpression(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->firstDateExpression = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_COMMA); + $parser->match(TokenType::T_COMMA); $this->intervalExpression = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_COMMA); + $parser->match(TokenType::T_COMMA); $this->unit = $parser->StringPrimary(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/DateDiffFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/DateDiffFunction.php index bbd73c47df6..55598c09010 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/DateDiffFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/DateDiffFunction.php @@ -5,9 +5,9 @@ namespace Doctrine\ORM\Query\AST\Functions; use Doctrine\ORM\Query\AST\Node; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * "DATE_DIFF" "(" ArithmeticPrimary "," ArithmeticPrimary ")" @@ -29,13 +29,13 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->date1 = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_COMMA); + $parser->match(TokenType::T_COMMA); $this->date2 = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php index f98a1c486d5..18b396e58f8 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php @@ -5,10 +5,10 @@ namespace Doctrine\ORM\Query\AST\Functions; use Doctrine\ORM\Query\AST\PathExpression; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\QueryException; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; use function assert; use function reset; @@ -70,20 +70,20 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->pathExpression = $parser->SingleValuedAssociationPathExpression(); - if ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) { - $parser->match(Lexer::T_COMMA); - $parser->match(Lexer::T_STRING); + if ($parser->getLexer()->isNextToken(TokenType::T_COMMA)) { + $parser->match(TokenType::T_COMMA); + $parser->match(TokenType::T_STRING); $token = $parser->getLexer()->token; assert($token !== null); $this->fieldMapping = $token['value']; } - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/LengthFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/LengthFunction.php index ad9dcf8d4c3..39949183bd2 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/LengthFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/LengthFunction.php @@ -8,9 +8,9 @@ use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Query\AST\Node; use Doctrine\ORM\Query\AST\TypedExpression; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * "LENGTH" "(" StringPrimary ")" @@ -30,12 +30,12 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->stringPrimary = $parser->StringPrimary(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } public function getReturnType(): Type diff --git a/lib/Doctrine/ORM/Query/AST/Functions/LocateFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/LocateFunction.php index b9fe10d6ea9..839d54ca546 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/LocateFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/LocateFunction.php @@ -6,9 +6,9 @@ use Doctrine\ORM\Query\AST\Node; use Doctrine\ORM\Query\AST\SimpleArithmeticExpression; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" @@ -43,22 +43,22 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->firstStringPrimary = $parser->StringPrimary(); - $parser->match(Lexer::T_COMMA); + $parser->match(TokenType::T_COMMA); $this->secondStringPrimary = $parser->StringPrimary(); $lexer = $parser->getLexer(); - if ($lexer->isNextToken(Lexer::T_COMMA)) { - $parser->match(Lexer::T_COMMA); + if ($lexer->isNextToken(TokenType::T_COMMA)) { + $parser->match(TokenType::T_COMMA); $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); } - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/LowerFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/LowerFunction.php index 65afff783cf..8ae337ac273 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/LowerFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/LowerFunction.php @@ -5,9 +5,9 @@ namespace Doctrine\ORM\Query\AST\Functions; use Doctrine\ORM\Query\AST\Node; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; use function sprintf; @@ -30,11 +30,11 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->stringPrimary = $parser->StringPrimary(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/ModFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/ModFunction.php index d4529aeffee..f9daa3c3bdf 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/ModFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/ModFunction.php @@ -5,9 +5,9 @@ namespace Doctrine\ORM\Query\AST\Functions; use Doctrine\ORM\Query\AST\SimpleArithmeticExpression; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" @@ -32,15 +32,15 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - $parser->match(Lexer::T_COMMA); + $parser->match(TokenType::T_COMMA); $this->secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php index e59818ad2ce..f95eeefe2f0 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php @@ -6,9 +6,9 @@ use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Query\AST\PathExpression; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; use function assert; @@ -104,11 +104,11 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->collectionPathExpression = $parser->CollectionValuedPathExpression(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/SqrtFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/SqrtFunction.php index 1f74392f5bc..036ba9a42ac 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/SqrtFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/SqrtFunction.php @@ -5,9 +5,9 @@ namespace Doctrine\ORM\Query\AST\Functions; use Doctrine\ORM\Query\AST\SimpleArithmeticExpression; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; use function sprintf; @@ -31,11 +31,11 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php index 89e45ebe111..5b21fe42606 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php @@ -6,9 +6,9 @@ use Doctrine\ORM\Query\AST\Node; use Doctrine\ORM\Query\AST\SimpleArithmeticExpression; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; /** * "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" @@ -41,22 +41,22 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->stringPrimary = $parser->StringPrimary(); - $parser->match(Lexer::T_COMMA); + $parser->match(TokenType::T_COMMA); $this->firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression(); $lexer = $parser->getLexer(); - if ($lexer->isNextToken(Lexer::T_COMMA)) { - $parser->match(Lexer::T_COMMA); + if ($lexer->isNextToken(TokenType::T_COMMA)) { + $parser->match(TokenType::T_COMMA); $this->secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression(); } - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/TrimFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/TrimFunction.php index e214f4c515f..10ab8ebb1ad 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/TrimFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/TrimFunction.php @@ -6,9 +6,9 @@ use Doctrine\DBAL\Platforms\TrimMode; use Doctrine\ORM\Query\AST\Node; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; use function assert; use function strcasecmp; @@ -47,25 +47,25 @@ public function parse(Parser $parser): void { $lexer = $parser->getLexer(); - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->parseTrimMode($parser); - if ($lexer->isNextToken(Lexer::T_STRING)) { - $parser->match(Lexer::T_STRING); + if ($lexer->isNextToken(TokenType::T_STRING)) { + $parser->match(TokenType::T_STRING); assert($lexer->token !== null); $this->trimChar = $lexer->token['value']; } if ($this->leading || $this->trailing || $this->both || $this->trimChar) { - $parser->match(Lexer::T_FROM); + $parser->match(TokenType::T_FROM); } $this->stringPrimary = $parser->StringPrimary(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } /** @psalm-return TrimMode::* */ @@ -93,7 +93,7 @@ private function parseTrimMode(Parser $parser): void $value = $lexer->lookahead['value']; if (strcasecmp('leading', $value) === 0) { - $parser->match(Lexer::T_LEADING); + $parser->match(TokenType::T_LEADING); $this->leading = true; @@ -101,7 +101,7 @@ private function parseTrimMode(Parser $parser): void } if (strcasecmp('trailing', $value) === 0) { - $parser->match(Lexer::T_TRAILING); + $parser->match(TokenType::T_TRAILING); $this->trailing = true; @@ -109,7 +109,7 @@ private function parseTrimMode(Parser $parser): void } if (strcasecmp('both', $value) === 0) { - $parser->match(Lexer::T_BOTH); + $parser->match(TokenType::T_BOTH); $this->both = true; diff --git a/lib/Doctrine/ORM/Query/AST/Functions/UpperFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/UpperFunction.php index 3f1cd6b3333..1ecef66f8a5 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/UpperFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/UpperFunction.php @@ -5,9 +5,9 @@ namespace Doctrine\ORM\Query\AST\Functions; use Doctrine\ORM\Query\AST\Node; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; use function sprintf; @@ -30,11 +30,11 @@ public function getSql(SqlWalker $sqlWalker): string public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->stringPrimary = $parser->StringPrimary(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } diff --git a/lib/Doctrine/ORM/Query/Lexer.php b/lib/Doctrine/ORM/Query/Lexer.php index 45d241da3be..33db4c24287 100644 --- a/lib/Doctrine/ORM/Query/Lexer.php +++ b/lib/Doctrine/ORM/Query/Lexer.php @@ -20,94 +20,10 @@ /** * Scans a DQL query for tokens. * - * @extends AbstractLexer + * @extends AbstractLexer */ class Lexer extends AbstractLexer { - // All tokens that are not valid identifiers must be < 100 - final public const T_NONE = 1; - final public const T_INTEGER = 2; - final public const T_STRING = 3; - final public const T_INPUT_PARAMETER = 4; - final public const T_FLOAT = 5; - final public const T_CLOSE_PARENTHESIS = 6; - final public const T_OPEN_PARENTHESIS = 7; - final public const T_COMMA = 8; - final public const T_DIVIDE = 9; - final public const T_DOT = 10; - final public const T_EQUALS = 11; - final public const T_GREATER_THAN = 12; - final public const T_LOWER_THAN = 13; - final public const T_MINUS = 14; - final public const T_MULTIPLY = 15; - final public const T_NEGATE = 16; - final public const T_PLUS = 17; - final public const T_OPEN_CURLY_BRACE = 18; - final public const T_CLOSE_CURLY_BRACE = 19; - - // All tokens that are identifiers or keywords that could be considered as identifiers should be >= 100 - final public const T_FULLY_QUALIFIED_NAME = 101; - final public const T_IDENTIFIER = 102; - - // All keyword tokens should be >= 200 - final public const T_ALL = 200; - final public const T_AND = 201; - final public const T_ANY = 202; - final public const T_AS = 203; - final public const T_ASC = 204; - final public const T_AVG = 205; - final public const T_BETWEEN = 206; - final public const T_BOTH = 207; - final public const T_BY = 208; - final public const T_CASE = 209; - final public const T_COALESCE = 210; - final public const T_COUNT = 211; - final public const T_DELETE = 212; - final public const T_DESC = 213; - final public const T_DISTINCT = 214; - final public const T_ELSE = 215; - final public const T_EMPTY = 216; - final public const T_END = 217; - final public const T_ESCAPE = 218; - final public const T_EXISTS = 219; - final public const T_FALSE = 220; - final public const T_FROM = 221; - final public const T_GROUP = 222; - final public const T_HAVING = 223; - final public const T_HIDDEN = 224; - final public const T_IN = 225; - final public const T_INDEX = 226; - final public const T_INNER = 227; - final public const T_INSTANCE = 228; - final public const T_IS = 229; - final public const T_JOIN = 230; - final public const T_LEADING = 231; - final public const T_LEFT = 232; - final public const T_LIKE = 233; - final public const T_MAX = 234; - final public const T_MEMBER = 235; - final public const T_MIN = 236; - final public const T_NEW = 237; - final public const T_NOT = 238; - final public const T_NULL = 239; - final public const T_NULLIF = 240; - final public const T_OF = 241; - final public const T_OR = 242; - final public const T_ORDER = 243; - final public const T_OUTER = 244; - final public const T_PARTIAL = 245; - final public const T_SELECT = 246; - final public const T_SET = 247; - final public const T_SOME = 248; - final public const T_SUM = 249; - final public const T_THEN = 250; - final public const T_TRAILING = 251; - final public const T_TRUE = 252; - final public const T_UPDATE = 253; - final public const T_WHEN = 254; - final public const T_WHERE = 255; - final public const T_WITH = 256; - /** * Creates a new query scanner object. * @@ -143,89 +59,89 @@ protected function getNonCatchablePatterns(): array /** * {@inheritdoc} */ - protected function getType(&$value) + protected function getType(&$value): TokenType { - $type = self::T_NONE; + $type = TokenType::T_NONE; switch (true) { // Recognize numeric values case is_numeric($value): if (str_contains($value, '.') || stripos($value, 'e') !== false) { - return self::T_FLOAT; + return TokenType::T_FLOAT; } - return self::T_INTEGER; + return TokenType::T_INTEGER; // Recognize quoted strings case $value[0] === "'": $value = str_replace("''", "'", substr($value, 1, strlen($value) - 2)); - return self::T_STRING; + return TokenType::T_STRING; // Recognize identifiers, aliased or qualified names case ctype_alpha($value[0]) || $value[0] === '_' || $value[0] === '\\': - $name = 'Doctrine\ORM\Query\Lexer::T_' . strtoupper($value); + $name = 'Doctrine\ORM\Query\TokenType::T_' . strtoupper($value); if (defined($name)) { $type = constant($name); - if ($type > 100) { + if ($type->value > 100) { return $type; } } if (str_contains($value, '\\')) { - return self::T_FULLY_QUALIFIED_NAME; + return TokenType::T_FULLY_QUALIFIED_NAME; } - return self::T_IDENTIFIER; + return TokenType::T_IDENTIFIER; // Recognize input parameters case $value[0] === '?' || $value[0] === ':': - return self::T_INPUT_PARAMETER; + return TokenType::T_INPUT_PARAMETER; // Recognize symbols case $value === '.': - return self::T_DOT; + return TokenType::T_DOT; case $value === ',': - return self::T_COMMA; + return TokenType::T_COMMA; case $value === '(': - return self::T_OPEN_PARENTHESIS; + return TokenType::T_OPEN_PARENTHESIS; case $value === ')': - return self::T_CLOSE_PARENTHESIS; + return TokenType::T_CLOSE_PARENTHESIS; case $value === '=': - return self::T_EQUALS; + return TokenType::T_EQUALS; case $value === '>': - return self::T_GREATER_THAN; + return TokenType::T_GREATER_THAN; case $value === '<': - return self::T_LOWER_THAN; + return TokenType::T_LOWER_THAN; case $value === '+': - return self::T_PLUS; + return TokenType::T_PLUS; case $value === '-': - return self::T_MINUS; + return TokenType::T_MINUS; case $value === '*': - return self::T_MULTIPLY; + return TokenType::T_MULTIPLY; case $value === '/': - return self::T_DIVIDE; + return TokenType::T_DIVIDE; case $value === '!': - return self::T_NEGATE; + return TokenType::T_NEGATE; case $value === '{': - return self::T_OPEN_CURLY_BRACE; + return TokenType::T_OPEN_CURLY_BRACE; case $value === '}': - return self::T_CLOSE_CURLY_BRACE; + return TokenType::T_CLOSE_CURLY_BRACE; // Default default: diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php index 4574200b71e..d4713b6be50 100644 --- a/lib/Doctrine/ORM/Query/Parser.php +++ b/lib/Doctrine/ORM/Query/Parser.php @@ -34,7 +34,7 @@ * An LL(*) recursive-descent parser for the context-free grammar of the Doctrine Query Language. * Parses a DQL query, reports any errors in it, and generates an AST. * - * @psalm-type DqlToken = Token + * @psalm-type DqlToken = Token * @psalm-type QueryComponent = array{ * metadata?: ClassMetadata, * parent?: string|null, @@ -288,15 +288,13 @@ public function getAST() * If they match, updates the lookahead token; otherwise raises a syntax * error. * - * @param Lexer::T_* $token The token type. - * * @return void * * @throws QueryException If the tokens don't match. */ - public function match($token) + public function match(TokenType $token) { - $lookaheadType = $this->lexer->lookahead['type'] ?? null; + $lookaheadType = $this->lexer->lookahead->type ?? null; // Short-circuit on first condition, usually types match if ($lookaheadType === $token) { @@ -306,17 +304,17 @@ public function match($token) } // If parameter is not identifier (1-99) must be exact match - if ($token < Lexer::T_IDENTIFIER) { + if ($token->value < TokenType::T_IDENTIFIER->value) { $this->syntaxError($this->lexer->getLiteral($token)); } // If parameter is keyword (200+) must be exact match - if ($token > Lexer::T_IDENTIFIER) { + if ($token->value > TokenType::T_IDENTIFIER->value) { $this->syntaxError($this->lexer->getLiteral($token)); } // If parameter is T_IDENTIFIER, then matches T_IDENTIFIER (100) and keywords (200+) - if ($token === Lexer::T_IDENTIFIER && $lookaheadType < Lexer::T_IDENTIFIER) { + if ($token->value === TokenType::T_IDENTIFIER->value && $lookaheadType->value < TokenType::T_IDENTIFIER->value) { $this->syntaxError($this->lexer->getLiteral($token)); } @@ -447,11 +445,11 @@ public function syntaxError($expected = '', $token = null) $token = $this->lexer->lookahead; } - $tokenPos = $token['position'] ?? '-1'; + $tokenPos = $token->position ?? '-1'; $message = sprintf('line 0, col %d: Error: ', $tokenPos); $message .= $expected !== '' ? sprintf('Expected %s, got ', $expected) : 'Unexpected '; - $message .= $this->lexer->lookahead === null ? 'end of string.' : sprintf("'%s'", $token['value']); + $message .= $this->lexer->lookahead === null ? 'end of string.' : sprintf("'%s'", $token->value); throw QueryException::syntaxError($message, QueryException::dqlError($this->query->getDQL() ?? '')); } @@ -459,8 +457,7 @@ public function syntaxError($expected = '', $token = null) /** * Generates a new semantical error. * - * @param string $message Optional message. - * @param mixed[]|null $token Optional token. + * @param string $message Optional message. * @psalm-param DqlToken|null $token * * @return void @@ -468,10 +465,10 @@ public function syntaxError($expected = '', $token = null) * * @throws QueryException */ - public function semanticalError($message = '', $token = null) + public function semanticalError($message = '', Token|null $token = null) { if ($token === null) { - $token = $this->lexer->lookahead ?? ['position' => 0]; + $token = $this->lexer->lookahead ?? new Token('fake token', 42, 0); } // Minimum exposed chars ahead of token @@ -480,12 +477,12 @@ public function semanticalError($message = '', $token = null) // Find a position of a final word to display in error string $dql = $this->query->getDQL(); $length = strlen($dql); - $pos = $token['position'] + $distance; + $pos = $token->position + $distance; $pos = strpos($dql, ' ', $length > $pos ? $pos : $length); - $length = $pos !== false ? $pos - $token['position'] : $distance; + $length = $pos !== false ? $pos - $token->position : $distance; - $tokenPos = $token['position'] > 0 ? $token['position'] : '-1'; - $tokenStr = substr($dql, $token['position'], $length); + $tokenPos = $token->position > 0 ? $token->position : '-1'; + $tokenStr = substr($dql, $token->position, $length); // Building informative message $message = 'line 0, col ' . $tokenPos . " near '" . $tokenStr . "': Error: " . $message; @@ -499,20 +496,20 @@ public function semanticalError($message = '', $token = null) * @param bool $resetPeek Reset peek after finding the closing parenthesis. * * @return mixed[] - * @psalm-return DqlToken|array|null + * @psalm-return DqlToken|null */ - private function peekBeyondClosingParenthesis(bool $resetPeek = true): Token|array|null + private function peekBeyondClosingParenthesis(bool $resetPeek = true): Token|null { $token = $this->lexer->peek(); $numUnmatched = 1; while ($numUnmatched > 0 && $token !== null) { - switch ($token['type']) { - case Lexer::T_OPEN_PARENTHESIS: + switch ($token->type) { + case TokenType::T_OPEN_PARENTHESIS: ++$numUnmatched; break; - case Lexer::T_CLOSE_PARENTHESIS: + case TokenType::T_CLOSE_PARENTHESIS: --$numUnmatched; break; @@ -533,11 +530,11 @@ private function peekBeyondClosingParenthesis(bool $resetPeek = true): Token|arr /** * Checks if the given token indicates a mathematical operator. * - * @psalm-param DqlToken|array|null $token + * @psalm-param DqlToken|null $token */ - private function isMathOperator(Token|array|null $token): bool + private function isMathOperator(Token|null $token): bool { - return $token !== null && in_array($token['type'], [Lexer::T_PLUS, Lexer::T_MINUS, Lexer::T_DIVIDE, Lexer::T_MULTIPLY], true); + return $token !== null && in_array($token->type, [TokenType::T_PLUS, TokenType::T_MINUS, TokenType::T_DIVIDE, TokenType::T_MULTIPLY], true); } /** @@ -548,26 +545,24 @@ private function isMathOperator(Token|array|null $token): bool private function isFunction(): bool { assert($this->lexer->lookahead !== null); - $lookaheadType = $this->lexer->lookahead['type']; + $lookaheadType = $this->lexer->lookahead->type; $peek = $this->lexer->peek(); $this->lexer->resetPeek(); - return $lookaheadType >= Lexer::T_IDENTIFIER && $peek !== null && $peek['type'] === Lexer::T_OPEN_PARENTHESIS; + return $lookaheadType->value >= TokenType::T_IDENTIFIER->value && $peek !== null && $peek->type === TokenType::T_OPEN_PARENTHESIS; } /** * Checks whether the given token type indicates an aggregate function. * - * @psalm-param Lexer::T_* $tokenType - * * @return bool TRUE if the token type is an aggregate function, FALSE otherwise. */ - private function isAggregateFunction(int $tokenType): bool + private function isAggregateFunction(TokenType $tokenType): bool { return in_array( $tokenType, - [Lexer::T_AVG, Lexer::T_MIN, Lexer::T_MAX, Lexer::T_SUM, Lexer::T_COUNT], + [TokenType::T_AVG, TokenType::T_MIN, TokenType::T_MAX, TokenType::T_SUM, TokenType::T_COUNT], true, ); } @@ -580,8 +575,8 @@ private function isNextAllAnySome(): bool assert($this->lexer->lookahead !== null); return in_array( - $this->lexer->lookahead['type'], - [Lexer::T_ALL, Lexer::T_ANY, Lexer::T_SOME], + $this->lexer->lookahead->type, + [TokenType::T_ALL, TokenType::T_ANY, TokenType::T_SOME], true, ); } @@ -843,16 +838,16 @@ public function QueryLanguage() $this->lexer->moveNext(); - switch ($this->lexer->lookahead['type'] ?? null) { - case Lexer::T_SELECT: + switch ($this->lexer->lookahead->type ?? null) { + case TokenType::T_SELECT: $statement = $this->SelectStatement(); break; - case Lexer::T_UPDATE: + case TokenType::T_UPDATE: $statement = $this->UpdateStatement(); break; - case Lexer::T_DELETE: + case TokenType::T_DELETE: $statement = $this->DeleteStatement(); break; @@ -878,10 +873,10 @@ public function SelectStatement() { $selectStatement = new AST\SelectStatement($this->SelectClause(), $this->FromClause()); - $selectStatement->whereClause = $this->lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null; - $selectStatement->groupByClause = $this->lexer->isNextToken(Lexer::T_GROUP) ? $this->GroupByClause() : null; - $selectStatement->havingClause = $this->lexer->isNextToken(Lexer::T_HAVING) ? $this->HavingClause() : null; - $selectStatement->orderByClause = $this->lexer->isNextToken(Lexer::T_ORDER) ? $this->OrderByClause() : null; + $selectStatement->whereClause = $this->lexer->isNextToken(TokenType::T_WHERE) ? $this->WhereClause() : null; + $selectStatement->groupByClause = $this->lexer->isNextToken(TokenType::T_GROUP) ? $this->GroupByClause() : null; + $selectStatement->havingClause = $this->lexer->isNextToken(TokenType::T_HAVING) ? $this->HavingClause() : null; + $selectStatement->orderByClause = $this->lexer->isNextToken(TokenType::T_ORDER) ? $this->OrderByClause() : null; return $selectStatement; } @@ -895,7 +890,7 @@ public function UpdateStatement() { $updateStatement = new AST\UpdateStatement($this->UpdateClause()); - $updateStatement->whereClause = $this->lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null; + $updateStatement->whereClause = $this->lexer->isNextToken(TokenType::T_WHERE) ? $this->WhereClause() : null; return $updateStatement; } @@ -909,7 +904,7 @@ public function DeleteStatement() { $deleteStatement = new AST\DeleteStatement($this->DeleteClause()); - $deleteStatement->whereClause = $this->lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null; + $deleteStatement->whereClause = $this->lexer->isNextToken(TokenType::T_WHERE) ? $this->WhereClause() : null; return $deleteStatement; } @@ -921,10 +916,10 @@ public function DeleteStatement() */ public function IdentificationVariable() { - $this->match(Lexer::T_IDENTIFIER); + $this->match(TokenType::T_IDENTIFIER); assert($this->lexer->token !== null); - $identVariable = $this->lexer->token['value']; + $identVariable = $this->lexer->token->value; $this->deferredIdentificationVariables[] = [ 'expression' => $identVariable, @@ -942,10 +937,10 @@ public function IdentificationVariable() */ public function AliasIdentificationVariable() { - $this->match(Lexer::T_IDENTIFIER); + $this->match(TokenType::T_IDENTIFIER); assert($this->lexer->token !== null); - $aliasIdentVariable = $this->lexer->token['value']; + $aliasIdentVariable = $this->lexer->token->value; $exists = isset($this->queryComponents[$aliasIdentVariable]); if ($exists) { @@ -965,17 +960,17 @@ public function AliasIdentificationVariable() */ public function AbstractSchemaName() { - if ($this->lexer->isNextToken(Lexer::T_FULLY_QUALIFIED_NAME)) { - $this->match(Lexer::T_FULLY_QUALIFIED_NAME); + if ($this->lexer->isNextToken(TokenType::T_FULLY_QUALIFIED_NAME)) { + $this->match(TokenType::T_FULLY_QUALIFIED_NAME); assert($this->lexer->token !== null); - return $this->lexer->token['value']; + return $this->lexer->token->value; } - $this->match(Lexer::T_IDENTIFIER); + $this->match(TokenType::T_IDENTIFIER); assert($this->lexer->token !== null); - return $this->lexer->token['value']; + return $this->lexer->token->value; } /** @@ -1003,10 +998,10 @@ private function validateAbstractSchemaName(string $schemaName): void */ public function AliasResultVariable() { - $this->match(Lexer::T_IDENTIFIER); + $this->match(TokenType::T_IDENTIFIER); assert($this->lexer->token !== null); - $resultVariable = $this->lexer->token['value']; + $resultVariable = $this->lexer->token->value; $exists = isset($this->queryComponents[$resultVariable]); if ($exists) { @@ -1026,10 +1021,10 @@ public function AliasResultVariable() */ public function ResultVariable() { - $this->match(Lexer::T_IDENTIFIER); + $this->match(TokenType::T_IDENTIFIER); assert($this->lexer->token !== null); - $resultVariable = $this->lexer->token['value']; + $resultVariable = $this->lexer->token->value; // Defer ResultVariable validation $this->deferredResultVariables[] = [ @@ -1056,11 +1051,11 @@ public function JoinAssociationPathExpression() ); } - $this->match(Lexer::T_DOT); - $this->match(Lexer::T_IDENTIFIER); + $this->match(TokenType::T_DOT); + $this->match(TokenType::T_IDENTIFIER); assert($this->lexer->token !== null); - $field = $this->lexer->token['value']; + $field = $this->lexer->token->value; // Validate association field $class = $this->getMetadataForDqlAlias($identVariable); @@ -1089,16 +1084,16 @@ public function PathExpression($expectedTypes) $field = null; assert($this->lexer->token !== null); - if ($this->lexer->isNextToken(Lexer::T_DOT)) { - $this->match(Lexer::T_DOT); - $this->match(Lexer::T_IDENTIFIER); + if ($this->lexer->isNextToken(TokenType::T_DOT)) { + $this->match(TokenType::T_DOT); + $this->match(TokenType::T_IDENTIFIER); - $field = $this->lexer->token['value']; + $field = $this->lexer->token->value; - while ($this->lexer->isNextToken(Lexer::T_DOT)) { - $this->match(Lexer::T_DOT); - $this->match(Lexer::T_IDENTIFIER); - $field .= '.' . $this->lexer->token['value']; + while ($this->lexer->isNextToken(TokenType::T_DOT)) { + $this->match(TokenType::T_DOT); + $this->match(TokenType::T_IDENTIFIER); + $field .= '.' . $this->lexer->token->value; } } @@ -1179,11 +1174,11 @@ public function CollectionValuedPathExpression() public function SelectClause() { $isDistinct = false; - $this->match(Lexer::T_SELECT); + $this->match(TokenType::T_SELECT); // Check for DISTINCT - if ($this->lexer->isNextToken(Lexer::T_DISTINCT)) { - $this->match(Lexer::T_DISTINCT); + if ($this->lexer->isNextToken(TokenType::T_DISTINCT)) { + $this->match(TokenType::T_DISTINCT); $isDistinct = true; } @@ -1192,8 +1187,8 @@ public function SelectClause() $selectExpressions = []; $selectExpressions[] = $this->SelectExpression(); - while ($this->lexer->isNextToken(Lexer::T_COMMA)) { - $this->match(Lexer::T_COMMA); + while ($this->lexer->isNextToken(TokenType::T_COMMA)) { + $this->match(TokenType::T_COMMA); $selectExpressions[] = $this->SelectExpression(); } @@ -1209,10 +1204,10 @@ public function SelectClause() public function SimpleSelectClause() { $isDistinct = false; - $this->match(Lexer::T_SELECT); + $this->match(TokenType::T_SELECT); - if ($this->lexer->isNextToken(Lexer::T_DISTINCT)) { - $this->match(Lexer::T_DISTINCT); + if ($this->lexer->isNextToken(TokenType::T_DISTINCT)) { + $this->match(TokenType::T_DISTINCT); $isDistinct = true; } @@ -1227,7 +1222,7 @@ public function SimpleSelectClause() */ public function UpdateClause() { - $this->match(Lexer::T_UPDATE); + $this->match(TokenType::T_UPDATE); assert($this->lexer->lookahead !== null); $token = $this->lexer->lookahead; @@ -1235,8 +1230,8 @@ public function UpdateClause() $this->validateAbstractSchemaName($abstractSchemaName); - if ($this->lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); + if ($this->lexer->isNextToken(TokenType::T_AS)) { + $this->match(TokenType::T_AS); } $aliasIdentificationVariable = $this->AliasIdentificationVariable(); @@ -1255,13 +1250,13 @@ public function UpdateClause() $this->queryComponents[$aliasIdentificationVariable] = $queryComponent; - $this->match(Lexer::T_SET); + $this->match(TokenType::T_SET); $updateItems = []; $updateItems[] = $this->UpdateItem(); - while ($this->lexer->isNextToken(Lexer::T_COMMA)) { - $this->match(Lexer::T_COMMA); + while ($this->lexer->isNextToken(TokenType::T_COMMA)) { + $this->match(TokenType::T_COMMA); $updateItems[] = $this->UpdateItem(); } @@ -1279,10 +1274,10 @@ public function UpdateClause() */ public function DeleteClause() { - $this->match(Lexer::T_DELETE); + $this->match(TokenType::T_DELETE); - if ($this->lexer->isNextToken(Lexer::T_FROM)) { - $this->match(Lexer::T_FROM); + if ($this->lexer->isNextToken(TokenType::T_FROM)) { + $this->match(TokenType::T_FROM); } assert($this->lexer->lookahead !== null); @@ -1293,11 +1288,11 @@ public function DeleteClause() $deleteClause = new AST\DeleteClause($abstractSchemaName); - if ($this->lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); + if ($this->lexer->isNextToken(TokenType::T_AS)) { + $this->match(TokenType::T_AS); } - $aliasIdentificationVariable = $this->lexer->isNextToken(Lexer::T_IDENTIFIER) + $aliasIdentificationVariable = $this->lexer->isNextToken(TokenType::T_IDENTIFIER) ? $this->AliasIdentificationVariable() : 'alias_should_have_been_set'; @@ -1326,13 +1321,13 @@ public function DeleteClause() */ public function FromClause() { - $this->match(Lexer::T_FROM); + $this->match(TokenType::T_FROM); $identificationVariableDeclarations = []; $identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration(); - while ($this->lexer->isNextToken(Lexer::T_COMMA)) { - $this->match(Lexer::T_COMMA); + while ($this->lexer->isNextToken(TokenType::T_COMMA)) { + $this->match(TokenType::T_COMMA); $identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration(); } @@ -1347,13 +1342,13 @@ public function FromClause() */ public function SubselectFromClause() { - $this->match(Lexer::T_FROM); + $this->match(TokenType::T_FROM); $identificationVariables = []; $identificationVariables[] = $this->SubselectIdentificationVariableDeclaration(); - while ($this->lexer->isNextToken(Lexer::T_COMMA)) { - $this->match(Lexer::T_COMMA); + while ($this->lexer->isNextToken(TokenType::T_COMMA)) { + $this->match(TokenType::T_COMMA); $identificationVariables[] = $this->SubselectIdentificationVariableDeclaration(); } @@ -1368,7 +1363,7 @@ public function SubselectFromClause() */ public function WhereClause() { - $this->match(Lexer::T_WHERE); + $this->match(TokenType::T_WHERE); return new AST\WhereClause($this->ConditionalExpression()); } @@ -1380,7 +1375,7 @@ public function WhereClause() */ public function HavingClause() { - $this->match(Lexer::T_HAVING); + $this->match(TokenType::T_HAVING); return new AST\HavingClause($this->ConditionalExpression()); } @@ -1392,13 +1387,13 @@ public function HavingClause() */ public function GroupByClause() { - $this->match(Lexer::T_GROUP); - $this->match(Lexer::T_BY); + $this->match(TokenType::T_GROUP); + $this->match(TokenType::T_BY); $groupByItems = [$this->GroupByItem()]; - while ($this->lexer->isNextToken(Lexer::T_COMMA)) { - $this->match(Lexer::T_COMMA); + while ($this->lexer->isNextToken(TokenType::T_COMMA)) { + $this->match(TokenType::T_COMMA); $groupByItems[] = $this->GroupByItem(); } @@ -1413,14 +1408,14 @@ public function GroupByClause() */ public function OrderByClause() { - $this->match(Lexer::T_ORDER); - $this->match(Lexer::T_BY); + $this->match(TokenType::T_ORDER); + $this->match(TokenType::T_BY); $orderByItems = []; $orderByItems[] = $this->OrderByItem(); - while ($this->lexer->isNextToken(Lexer::T_COMMA)) { - $this->match(Lexer::T_COMMA); + while ($this->lexer->isNextToken(TokenType::T_COMMA)) { + $this->match(TokenType::T_COMMA); $orderByItems[] = $this->OrderByItem(); } @@ -1440,10 +1435,10 @@ public function Subselect() $subselect = new AST\Subselect($this->SimpleSelectClause(), $this->SubselectFromClause()); - $subselect->whereClause = $this->lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null; - $subselect->groupByClause = $this->lexer->isNextToken(Lexer::T_GROUP) ? $this->GroupByClause() : null; - $subselect->havingClause = $this->lexer->isNextToken(Lexer::T_HAVING) ? $this->HavingClause() : null; - $subselect->orderByClause = $this->lexer->isNextToken(Lexer::T_ORDER) ? $this->OrderByClause() : null; + $subselect->whereClause = $this->lexer->isNextToken(TokenType::T_WHERE) ? $this->WhereClause() : null; + $subselect->groupByClause = $this->lexer->isNextToken(TokenType::T_GROUP) ? $this->GroupByClause() : null; + $subselect->havingClause = $this->lexer->isNextToken(TokenType::T_HAVING) ? $this->HavingClause() : null; + $subselect->orderByClause = $this->lexer->isNextToken(TokenType::T_ORDER) ? $this->OrderByClause() : null; // Decrease query nesting level $this->nestingLevel--; @@ -1460,7 +1455,7 @@ public function UpdateItem() { $pathExpr = $this->SingleValuedPathExpression(); - $this->match(Lexer::T_EQUALS); + $this->match(TokenType::T_EQUALS); return new AST\UpdateItem($pathExpr, $this->NewValue()); } @@ -1475,13 +1470,13 @@ public function GroupByItem() // We need to check if we are in a IdentificationVariable or SingleValuedPathExpression $glimpse = $this->lexer->glimpse(); - if ($glimpse !== null && $glimpse['type'] === Lexer::T_DOT) { + if ($glimpse !== null && $glimpse->type === TokenType::T_DOT) { return $this->SingleValuedPathExpression(); } assert($this->lexer->lookahead !== null); // Still need to decide between IdentificationVariable or ResultVariable - $lookaheadValue = $this->lexer->lookahead['value']; + $lookaheadValue = $this->lexer->lookahead->value; if (! isset($this->queryComponents[$lookaheadValue])) { $this->semanticalError('Cannot group by undefined identification or result variable.'); @@ -1517,7 +1512,7 @@ public function OrderByItem() $expr = $this->SimpleArithmeticExpression(); break; - case $glimpse !== null && $glimpse['type'] === Lexer::T_DOT: + case $glimpse !== null && $glimpse->type === TokenType::T_DOT: $expr = $this->SingleValuedPathExpression(); break; @@ -1525,7 +1520,7 @@ public function OrderByItem() $expr = $this->ScalarExpression(); break; - case $this->lexer->lookahead['type'] === Lexer::T_CASE: + case $this->lexer->lookahead->type === TokenType::T_CASE: $expr = $this->CaseExpression(); break; @@ -1542,13 +1537,13 @@ public function OrderByItem() $item = new AST\OrderByItem($expr); switch (true) { - case $this->lexer->isNextToken(Lexer::T_DESC): - $this->match(Lexer::T_DESC); + case $this->lexer->isNextToken(TokenType::T_DESC): + $this->match(TokenType::T_DESC); $type = 'DESC'; break; - case $this->lexer->isNextToken(Lexer::T_ASC): - $this->match(Lexer::T_ASC); + case $this->lexer->isNextToken(TokenType::T_ASC): + $this->match(TokenType::T_ASC); break; default: @@ -1575,17 +1570,17 @@ public function OrderByItem() */ public function NewValue() { - if ($this->lexer->isNextToken(Lexer::T_NULL)) { - $this->match(Lexer::T_NULL); + if ($this->lexer->isNextToken(TokenType::T_NULL)) { + $this->match(TokenType::T_NULL); return null; } - if ($this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { - $this->match(Lexer::T_INPUT_PARAMETER); + if ($this->lexer->isNextToken(TokenType::T_INPUT_PARAMETER)) { + $this->match(TokenType::T_INPUT_PARAMETER); assert($this->lexer->token !== null); - return new AST\InputParameter($this->lexer->token['value']); + return new AST\InputParameter($this->lexer->token->value); } return $this->ArithmeticExpression(); @@ -1600,16 +1595,16 @@ public function IdentificationVariableDeclaration() { $joins = []; $rangeVariableDeclaration = $this->RangeVariableDeclaration(); - $indexBy = $this->lexer->isNextToken(Lexer::T_INDEX) + $indexBy = $this->lexer->isNextToken(TokenType::T_INDEX) ? $this->IndexBy() : null; $rangeVariableDeclaration->isRoot = true; while ( - $this->lexer->isNextToken(Lexer::T_LEFT) || - $this->lexer->isNextToken(Lexer::T_INNER) || - $this->lexer->isNextToken(Lexer::T_JOIN) + $this->lexer->isNextToken(TokenType::T_LEFT) || + $this->lexer->isNextToken(TokenType::T_INNER) || + $this->lexer->isNextToken(TokenType::T_JOIN) ) { $joins[] = $this->Join(); } @@ -1644,11 +1639,11 @@ public function SubselectIdentificationVariableDeclaration() $glimpse = $this->lexer->glimpse(); - if ($glimpse['type'] == Lexer::T_DOT) { + if ($glimpse->type == TokenType::T_DOT) { $associationPathExpression = $this->AssociationPathExpression(); - if ($this->lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); + if ($this->lexer->isNextToken(TokenType::T_AS)) { + $this->match(TokenType::T_AS); } $aliasIdentificationVariable = $this->AliasIdentificationVariable(); @@ -1692,34 +1687,34 @@ public function Join() $joinType = AST\Join::JOIN_TYPE_INNER; switch (true) { - case $this->lexer->isNextToken(Lexer::T_LEFT): - $this->match(Lexer::T_LEFT); + case $this->lexer->isNextToken(TokenType::T_LEFT): + $this->match(TokenType::T_LEFT); $joinType = AST\Join::JOIN_TYPE_LEFT; // Possible LEFT OUTER join - if ($this->lexer->isNextToken(Lexer::T_OUTER)) { - $this->match(Lexer::T_OUTER); + if ($this->lexer->isNextToken(TokenType::T_OUTER)) { + $this->match(TokenType::T_OUTER); $joinType = AST\Join::JOIN_TYPE_LEFTOUTER; } break; - case $this->lexer->isNextToken(Lexer::T_INNER): - $this->match(Lexer::T_INNER); + case $this->lexer->isNextToken(TokenType::T_INNER): + $this->match(TokenType::T_INNER); break; default: // Do nothing } - $this->match(Lexer::T_JOIN); + $this->match(TokenType::T_JOIN); $next = $this->lexer->glimpse(); assert($next !== null); - $joinDeclaration = $next['type'] === Lexer::T_DOT ? $this->JoinAssociationDeclaration() : $this->RangeVariableDeclaration(); - $adhocConditions = $this->lexer->isNextToken(Lexer::T_WITH); + $joinDeclaration = $next->type === TokenType::T_DOT ? $this->JoinAssociationDeclaration() : $this->RangeVariableDeclaration(); + $adhocConditions = $this->lexer->isNextToken(TokenType::T_WITH); $join = new AST\Join($joinType, $joinDeclaration); // Describe non-root join declaration @@ -1729,7 +1724,7 @@ public function Join() // Check for ad-hoc Join conditions if ($adhocConditions) { - $this->match(Lexer::T_WITH); + $this->match(TokenType::T_WITH); $join->conditionalExpression = $this->ConditionalExpression(); } @@ -1746,7 +1741,7 @@ public function Join() */ public function RangeVariableDeclaration() { - if ($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS) && $this->lexer->glimpse()['type'] === Lexer::T_SELECT) { + if ($this->lexer->isNextToken(TokenType::T_OPEN_PARENTHESIS) && $this->lexer->glimpse()->type === TokenType::T_SELECT) { $this->semanticalError('Subquery is not supported here', $this->lexer->token); } @@ -1754,8 +1749,8 @@ public function RangeVariableDeclaration() $this->validateAbstractSchemaName($abstractSchemaName); - if ($this->lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); + if ($this->lexer->isNextToken(TokenType::T_AS)) { + $this->match(TokenType::T_AS); } assert($this->lexer->lookahead !== null); @@ -1787,14 +1782,14 @@ public function JoinAssociationDeclaration() { $joinAssociationPathExpression = $this->JoinAssociationPathExpression(); - if ($this->lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); + if ($this->lexer->isNextToken(TokenType::T_AS)) { + $this->match(TokenType::T_AS); } assert($this->lexer->lookahead !== null); $aliasIdentificationVariable = $this->AliasIdentificationVariable(); - $indexBy = $this->lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null; + $indexBy = $this->lexer->isNextToken(TokenType::T_INDEX) ? $this->IndexBy() : null; $identificationVariable = $joinAssociationPathExpression->identificationVariable; $field = $joinAssociationPathExpression->associationField; @@ -1831,44 +1826,44 @@ public function PartialObjectExpression() 'PARTIAL syntax in DQL is deprecated.', ); - $this->match(Lexer::T_PARTIAL); + $this->match(TokenType::T_PARTIAL); $partialFieldSet = []; $identificationVariable = $this->IdentificationVariable(); - $this->match(Lexer::T_DOT); - $this->match(Lexer::T_OPEN_CURLY_BRACE); - $this->match(Lexer::T_IDENTIFIER); + $this->match(TokenType::T_DOT); + $this->match(TokenType::T_OPEN_CURLY_BRACE); + $this->match(TokenType::T_IDENTIFIER); assert($this->lexer->token !== null); - $field = $this->lexer->token['value']; + $field = $this->lexer->token->value; // First field in partial expression might be embeddable property - while ($this->lexer->isNextToken(Lexer::T_DOT)) { - $this->match(Lexer::T_DOT); - $this->match(Lexer::T_IDENTIFIER); - $field .= '.' . $this->lexer->token['value']; + while ($this->lexer->isNextToken(TokenType::T_DOT)) { + $this->match(TokenType::T_DOT); + $this->match(TokenType::T_IDENTIFIER); + $field .= '.' . $this->lexer->token->value; } $partialFieldSet[] = $field; - while ($this->lexer->isNextToken(Lexer::T_COMMA)) { - $this->match(Lexer::T_COMMA); - $this->match(Lexer::T_IDENTIFIER); + while ($this->lexer->isNextToken(TokenType::T_COMMA)) { + $this->match(TokenType::T_COMMA); + $this->match(TokenType::T_IDENTIFIER); - $field = $this->lexer->token['value']; + $field = $this->lexer->token->value; - while ($this->lexer->isNextToken(Lexer::T_DOT)) { - $this->match(Lexer::T_DOT); - $this->match(Lexer::T_IDENTIFIER); - $field .= '.' . $this->lexer->token['value']; + while ($this->lexer->isNextToken(TokenType::T_DOT)) { + $this->match(TokenType::T_DOT); + $this->match(TokenType::T_IDENTIFIER); + $field .= '.' . $this->lexer->token->value; } $partialFieldSet[] = $field; } - $this->match(Lexer::T_CLOSE_CURLY_BRACE); + $this->match(TokenType::T_CLOSE_CURLY_BRACE); $partialObjectExpression = new AST\PartialObjectExpression($identificationVariable, $partialFieldSet); @@ -1889,22 +1884,22 @@ public function PartialObjectExpression() */ public function NewObjectExpression() { - $this->match(Lexer::T_NEW); + $this->match(TokenType::T_NEW); $className = $this->AbstractSchemaName(); // note that this is not yet validated $token = $this->lexer->token; - $this->match(Lexer::T_OPEN_PARENTHESIS); + $this->match(TokenType::T_OPEN_PARENTHESIS); $args[] = $this->NewObjectArg(); - while ($this->lexer->isNextToken(Lexer::T_COMMA)) { - $this->match(Lexer::T_COMMA); + while ($this->lexer->isNextToken(TokenType::T_COMMA)) { + $this->match(TokenType::T_COMMA); $args[] = $this->NewObjectArg(); } - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); $expression = new AST\NewObjectExpression($className, $args); @@ -1930,10 +1925,10 @@ public function NewObjectArg() $peek = $this->lexer->glimpse(); assert($peek !== null); - if ($token['type'] === Lexer::T_OPEN_PARENTHESIS && $peek['type'] === Lexer::T_SELECT) { - $this->match(Lexer::T_OPEN_PARENTHESIS); + if ($token->type === TokenType::T_OPEN_PARENTHESIS && $peek->type === TokenType::T_SELECT) { + $this->match(TokenType::T_OPEN_PARENTHESIS); $expression = $this->Subselect(); - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); return $expression; } @@ -1948,8 +1943,8 @@ public function NewObjectArg() */ public function IndexBy() { - $this->match(Lexer::T_INDEX); - $this->match(Lexer::T_BY); + $this->match(TokenType::T_INDEX); + $this->match(TokenType::T_BY); $pathExpr = $this->SingleValuedPathExpression(); // Add the INDEX BY info to the query component @@ -1969,27 +1964,27 @@ public function ScalarExpression() { assert($this->lexer->token !== null); assert($this->lexer->lookahead !== null); - $lookahead = $this->lexer->lookahead['type']; + $lookahead = $this->lexer->lookahead->type; $peek = $this->lexer->glimpse(); switch (true) { - case $lookahead === Lexer::T_INTEGER: - case $lookahead === Lexer::T_FLOAT: + case $lookahead === TokenType::T_INTEGER: + case $lookahead === TokenType::T_FLOAT: // SimpleArithmeticExpression : (- u.value ) or ( + u.value ) or ( - 1 ) or ( + 1 ) - case $lookahead === Lexer::T_MINUS: - case $lookahead === Lexer::T_PLUS: + case $lookahead === TokenType::T_MINUS: + case $lookahead === TokenType::T_PLUS: return $this->SimpleArithmeticExpression(); - case $lookahead === Lexer::T_STRING: + case $lookahead === TokenType::T_STRING: return $this->StringPrimary(); - case $lookahead === Lexer::T_TRUE: - case $lookahead === Lexer::T_FALSE: + case $lookahead === TokenType::T_TRUE: + case $lookahead === TokenType::T_FALSE: $this->match($lookahead); - return new AST\Literal(AST\Literal::BOOLEAN, $this->lexer->token['value']); + return new AST\Literal(AST\Literal::BOOLEAN, $this->lexer->token->value); - case $lookahead === Lexer::T_INPUT_PARAMETER: + case $lookahead === TokenType::T_INPUT_PARAMETER: switch (true) { case $this->isMathOperator($peek): // :param + u.value @@ -1998,14 +1993,14 @@ public function ScalarExpression() default: return $this->InputParameter(); } - case $lookahead === Lexer::T_CASE: - case $lookahead === Lexer::T_COALESCE: - case $lookahead === Lexer::T_NULLIF: + case $lookahead === TokenType::T_CASE: + case $lookahead === TokenType::T_COALESCE: + case $lookahead === TokenType::T_NULLIF: // Since NULLIF and COALESCE can be identified as a function, // we need to check these before checking for FunctionDeclaration return $this->CaseExpression(); - case $lookahead === Lexer::T_OPEN_PARENTHESIS: + case $lookahead === TokenType::T_OPEN_PARENTHESIS: return $this->SimpleArithmeticExpression(); // this check must be done before checking for a filed path expression @@ -2024,7 +2019,7 @@ public function ScalarExpression() break; // it is no function, so it must be a field path - case $lookahead === Lexer::T_IDENTIFIER: + case $lookahead === TokenType::T_IDENTIFIER: $this->lexer->peek(); // lookahead => '.' $this->lexer->peek(); // lookahead => token after '.' $peek = $this->lexer->peek(); // lookahead => token after the token after the '.' @@ -2056,21 +2051,21 @@ public function ScalarExpression() public function CaseExpression() { assert($this->lexer->lookahead !== null); - $lookahead = $this->lexer->lookahead['type']; + $lookahead = $this->lexer->lookahead->type; switch ($lookahead) { - case Lexer::T_NULLIF: + case TokenType::T_NULLIF: return $this->NullIfExpression(); - case Lexer::T_COALESCE: + case TokenType::T_COALESCE: return $this->CoalesceExpression(); - case Lexer::T_CASE: + case TokenType::T_CASE: $this->lexer->resetPeek(); $peek = $this->lexer->peek(); assert($peek !== null); - if ($peek['type'] === Lexer::T_WHEN) { + if ($peek->type === TokenType::T_WHEN) { return $this->GeneralCaseExpression(); } @@ -2091,20 +2086,20 @@ public function CaseExpression() */ public function CoalesceExpression() { - $this->match(Lexer::T_COALESCE); - $this->match(Lexer::T_OPEN_PARENTHESIS); + $this->match(TokenType::T_COALESCE); + $this->match(TokenType::T_OPEN_PARENTHESIS); // Process ScalarExpressions (1..N) $scalarExpressions = []; $scalarExpressions[] = $this->ScalarExpression(); - while ($this->lexer->isNextToken(Lexer::T_COMMA)) { - $this->match(Lexer::T_COMMA); + while ($this->lexer->isNextToken(TokenType::T_COMMA)) { + $this->match(TokenType::T_COMMA); $scalarExpressions[] = $this->ScalarExpression(); } - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); return new AST\CoalesceExpression($scalarExpressions); } @@ -2116,14 +2111,14 @@ public function CoalesceExpression() */ public function NullIfExpression() { - $this->match(Lexer::T_NULLIF); - $this->match(Lexer::T_OPEN_PARENTHESIS); + $this->match(TokenType::T_NULLIF); + $this->match(TokenType::T_OPEN_PARENTHESIS); $firstExpression = $this->ScalarExpression(); - $this->match(Lexer::T_COMMA); + $this->match(TokenType::T_COMMA); $secondExpression = $this->ScalarExpression(); - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); return new AST\NullIfExpression($firstExpression, $secondExpression); } @@ -2135,18 +2130,18 @@ public function NullIfExpression() */ public function GeneralCaseExpression() { - $this->match(Lexer::T_CASE); + $this->match(TokenType::T_CASE); // Process WhenClause (1..N) $whenClauses = []; do { $whenClauses[] = $this->WhenClause(); - } while ($this->lexer->isNextToken(Lexer::T_WHEN)); + } while ($this->lexer->isNextToken(TokenType::T_WHEN)); - $this->match(Lexer::T_ELSE); + $this->match(TokenType::T_ELSE); $scalarExpression = $this->ScalarExpression(); - $this->match(Lexer::T_END); + $this->match(TokenType::T_END); return new AST\GeneralCaseExpression($whenClauses, $scalarExpression); } @@ -2159,7 +2154,7 @@ public function GeneralCaseExpression() */ public function SimpleCaseExpression() { - $this->match(Lexer::T_CASE); + $this->match(TokenType::T_CASE); $caseOperand = $this->StateFieldPathExpression(); // Process SimpleWhenClause (1..N) @@ -2167,11 +2162,11 @@ public function SimpleCaseExpression() do { $simpleWhenClauses[] = $this->SimpleWhenClause(); - } while ($this->lexer->isNextToken(Lexer::T_WHEN)); + } while ($this->lexer->isNextToken(TokenType::T_WHEN)); - $this->match(Lexer::T_ELSE); + $this->match(TokenType::T_ELSE); $scalarExpression = $this->ScalarExpression(); - $this->match(Lexer::T_END); + $this->match(TokenType::T_END); return new AST\SimpleCaseExpression($caseOperand, $simpleWhenClauses, $scalarExpression); } @@ -2183,9 +2178,9 @@ public function SimpleCaseExpression() */ public function WhenClause() { - $this->match(Lexer::T_WHEN); + $this->match(TokenType::T_WHEN); $conditionalExpression = $this->ConditionalExpression(); - $this->match(Lexer::T_THEN); + $this->match(TokenType::T_THEN); return new AST\WhenClause($conditionalExpression, $this->ScalarExpression()); } @@ -2197,9 +2192,9 @@ public function WhenClause() */ public function SimpleWhenClause() { - $this->match(Lexer::T_WHEN); + $this->match(TokenType::T_WHEN); $conditionalExpression = $this->ScalarExpression(); - $this->match(Lexer::T_THEN); + $this->match(TokenType::T_THEN); return new AST\SimpleWhenClause($conditionalExpression, $this->ScalarExpression()); } @@ -2218,24 +2213,24 @@ public function SelectExpression() $expression = null; $identVariable = null; $peek = $this->lexer->glimpse(); - $lookaheadType = $this->lexer->lookahead['type']; + $lookaheadType = $this->lexer->lookahead->type; assert($peek !== null); switch (true) { // ScalarExpression (u.name) - case $lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] === Lexer::T_DOT: + case $lookaheadType === TokenType::T_IDENTIFIER && $peek->type === TokenType::T_DOT: $expression = $this->ScalarExpression(); break; // IdentificationVariable (u) - case $lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] !== Lexer::T_OPEN_PARENTHESIS: + case $lookaheadType === TokenType::T_IDENTIFIER && $peek->type !== TokenType::T_OPEN_PARENTHESIS: $expression = $identVariable = $this->IdentificationVariable(); break; // CaseExpression (CASE ... or NULLIF(...) or COALESCE(...)) - case $lookaheadType === Lexer::T_CASE: - case $lookaheadType === Lexer::T_COALESCE: - case $lookaheadType === Lexer::T_NULLIF: + case $lookaheadType === TokenType::T_CASE: + case $lookaheadType === TokenType::T_COALESCE: + case $lookaheadType === TokenType::T_NULLIF: $expression = $this->CaseExpression(); break; @@ -2258,31 +2253,31 @@ public function SelectExpression() break; // PartialObjectExpression (PARTIAL u.{id, name}) - case $lookaheadType === Lexer::T_PARTIAL: + case $lookaheadType === TokenType::T_PARTIAL: $expression = $this->PartialObjectExpression(); $identVariable = $expression->identificationVariable; break; // Subselect - case $lookaheadType === Lexer::T_OPEN_PARENTHESIS && $peek['type'] === Lexer::T_SELECT: - $this->match(Lexer::T_OPEN_PARENTHESIS); + case $lookaheadType === TokenType::T_OPEN_PARENTHESIS && $peek->type === TokenType::T_SELECT: + $this->match(TokenType::T_OPEN_PARENTHESIS); $expression = $this->Subselect(); - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); break; // Shortcut: ScalarExpression => SimpleArithmeticExpression - case $lookaheadType === Lexer::T_OPEN_PARENTHESIS: - case $lookaheadType === Lexer::T_INTEGER: - case $lookaheadType === Lexer::T_STRING: - case $lookaheadType === Lexer::T_FLOAT: + case $lookaheadType === TokenType::T_OPEN_PARENTHESIS: + case $lookaheadType === TokenType::T_INTEGER: + case $lookaheadType === TokenType::T_STRING: + case $lookaheadType === TokenType::T_FLOAT: // SimpleArithmeticExpression : (- u.value ) or ( + u.value ) - case $lookaheadType === Lexer::T_MINUS: - case $lookaheadType === Lexer::T_PLUS: + case $lookaheadType === TokenType::T_MINUS: + case $lookaheadType === TokenType::T_PLUS: $expression = $this->SimpleArithmeticExpression(); break; // NewObjectExpression (New ClassName(id, name)) - case $lookaheadType === Lexer::T_NEW: + case $lookaheadType === TokenType::T_NEW: $expression = $this->NewObjectExpression(); break; @@ -2296,23 +2291,23 @@ public function SelectExpression() // [["AS"] ["HIDDEN"] AliasResultVariable] $mustHaveAliasResultVariable = false; - if ($this->lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); + if ($this->lexer->isNextToken(TokenType::T_AS)) { + $this->match(TokenType::T_AS); $mustHaveAliasResultVariable = true; } $hiddenAliasResultVariable = false; - if ($this->lexer->isNextToken(Lexer::T_HIDDEN)) { - $this->match(Lexer::T_HIDDEN); + if ($this->lexer->isNextToken(TokenType::T_HIDDEN)) { + $this->match(TokenType::T_HIDDEN); $hiddenAliasResultVariable = true; } $aliasResultVariable = null; - if ($mustHaveAliasResultVariable || $this->lexer->isNextToken(Lexer::T_IDENTIFIER)) { + if ($mustHaveAliasResultVariable || $this->lexer->isNextToken(TokenType::T_IDENTIFIER)) { assert($expression instanceof AST\Node || is_string($expression)); $token = $this->lexer->lookahead; $aliasResultVariable = $this->AliasResultVariable(); @@ -2350,15 +2345,15 @@ public function SimpleSelectExpression() $peek = $this->lexer->glimpse(); assert($peek !== null); - switch ($this->lexer->lookahead['type']) { - case Lexer::T_IDENTIFIER: + switch ($this->lexer->lookahead->type) { + case TokenType::T_IDENTIFIER: switch (true) { - case $peek['type'] === Lexer::T_DOT: + case $peek->type === TokenType::T_DOT: $expression = $this->StateFieldPathExpression(); return new AST\SimpleSelectExpression($expression); - case $peek['type'] !== Lexer::T_OPEN_PARENTHESIS: + case $peek->type !== TokenType::T_OPEN_PARENTHESIS: $expression = $this->IdentificationVariable(); return new AST\SimpleSelectExpression($expression); @@ -2370,7 +2365,7 @@ public function SimpleSelectExpression() } // COUNT(u.id) - if ($this->isAggregateFunction($this->lexer->lookahead['type'])) { + if ($this->isAggregateFunction($this->lexer->lookahead->type)) { return new AST\SimpleSelectExpression($this->AggregateExpression()); } @@ -2383,8 +2378,8 @@ public function SimpleSelectExpression() break; - case Lexer::T_OPEN_PARENTHESIS: - if ($peek['type'] !== Lexer::T_SELECT) { + case TokenType::T_OPEN_PARENTHESIS: + if ($peek->type !== TokenType::T_SELECT) { // Shortcut: ScalarExpression => SimpleArithmeticExpression $expression = $this->SimpleArithmeticExpression(); @@ -2392,9 +2387,9 @@ public function SimpleSelectExpression() } // Subselect - $this->match(Lexer::T_OPEN_PARENTHESIS); + $this->match(TokenType::T_OPEN_PARENTHESIS); $expression = $this->Subselect(); - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); return new AST\SimpleSelectExpression($expression); @@ -2407,11 +2402,11 @@ public function SimpleSelectExpression() $expression = $this->ScalarExpression(); $expr = new AST\SimpleSelectExpression($expression); - if ($this->lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); + if ($this->lexer->isNextToken(TokenType::T_AS)) { + $this->match(TokenType::T_AS); } - if ($this->lexer->isNextToken(Lexer::T_IDENTIFIER)) { + if ($this->lexer->isNextToken(TokenType::T_IDENTIFIER)) { $token = $this->lexer->lookahead; $resultVariable = $this->AliasResultVariable(); $expr->fieldIdentificationVariable = $resultVariable; @@ -2437,8 +2432,8 @@ public function ConditionalExpression() $conditionalTerms = []; $conditionalTerms[] = $this->ConditionalTerm(); - while ($this->lexer->isNextToken(Lexer::T_OR)) { - $this->match(Lexer::T_OR); + while ($this->lexer->isNextToken(TokenType::T_OR)) { + $this->match(TokenType::T_OR); $conditionalTerms[] = $this->ConditionalTerm(); } @@ -2462,8 +2457,8 @@ public function ConditionalTerm() $conditionalFactors = []; $conditionalFactors[] = $this->ConditionalFactor(); - while ($this->lexer->isNextToken(Lexer::T_AND)) { - $this->match(Lexer::T_AND); + while ($this->lexer->isNextToken(TokenType::T_AND)) { + $this->match(TokenType::T_AND); $conditionalFactors[] = $this->ConditionalFactor(); } @@ -2486,8 +2481,8 @@ public function ConditionalFactor() { $not = false; - if ($this->lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); + if ($this->lexer->isNextToken(TokenType::T_NOT)) { + $this->match(TokenType::T_NOT); $not = true; } @@ -2512,7 +2507,7 @@ public function ConditionalPrimary() { $condPrimary = new AST\ConditionalPrimary(); - if (! $this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) { + if (! $this->lexer->isNextToken(TokenType::T_OPEN_PARENTHESIS)) { $condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression(); return $condPrimary; @@ -2523,8 +2518,8 @@ public function ConditionalPrimary() if ( $peek !== null && ( - in_array($peek['value'], ['=', '<', '<=', '<>', '>', '>=', '!='], true) || - in_array($peek['type'], [Lexer::T_NOT, Lexer::T_BETWEEN, Lexer::T_LIKE, Lexer::T_IN, Lexer::T_IS, Lexer::T_EXISTS], true) || + in_array($peek->value, ['=', '<', '<=', '<>', '>', '>=', '!='], true) || + in_array($peek->type, [TokenType::T_NOT, TokenType::T_BETWEEN, TokenType::T_LIKE, TokenType::T_IN, TokenType::T_IS, TokenType::T_EXISTS], true) || $this->isMathOperator($peek) ) ) { @@ -2533,9 +2528,9 @@ public function ConditionalPrimary() return $condPrimary; } - $this->match(Lexer::T_OPEN_PARENTHESIS); + $this->match(TokenType::T_OPEN_PARENTHESIS); $condPrimary->conditionalExpression = $this->ConditionalExpression(); - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); return $condPrimary; } @@ -2560,7 +2555,7 @@ public function ConditionalPrimary() public function SimpleConditionalExpression() { assert($this->lexer->lookahead !== null); - if ($this->lexer->isNextToken(Lexer::T_EXISTS)) { + if ($this->lexer->isNextToken(TokenType::T_EXISTS)) { return $this->ExistsExpression(); } @@ -2568,28 +2563,28 @@ public function SimpleConditionalExpression() $peek = $this->lexer->glimpse(); $lookahead = $token; - if ($this->lexer->isNextToken(Lexer::T_NOT)) { + if ($this->lexer->isNextToken(TokenType::T_NOT)) { $token = $this->lexer->glimpse(); } assert($token !== null); assert($peek !== null); - if ($token['type'] === Lexer::T_IDENTIFIER || $token['type'] === Lexer::T_INPUT_PARAMETER || $this->isFunction()) { + if ($token->type === TokenType::T_IDENTIFIER || $token->type === TokenType::T_INPUT_PARAMETER || $this->isFunction()) { // Peek beyond the matching closing parenthesis. $beyond = $this->lexer->peek(); - switch ($peek['value']) { + switch ($peek->value) { case '(': // Peeks beyond the matched closing parenthesis. $token = $this->peekBeyondClosingParenthesis(false); assert($token !== null); - if ($token['type'] === Lexer::T_NOT) { + if ($token->type === TokenType::T_NOT) { $token = $this->lexer->peek(); assert($token !== null); } - if ($token['type'] === Lexer::T_IS) { + if ($token->type === TokenType::T_IS) { $lookahead = $this->lexer->peek(); } @@ -2599,7 +2594,7 @@ public function SimpleConditionalExpression() // Peek beyond the PathExpression or InputParameter. $token = $beyond; - while ($token['value'] === '.') { + while ($token->value === '.') { $this->lexer->peek(); $token = $this->lexer->peek(); @@ -2608,7 +2603,7 @@ public function SimpleConditionalExpression() // Also peek beyond a NOT if there is one. assert($token !== null); - if ($token['type'] === Lexer::T_NOT) { + if ($token->type === TokenType::T_NOT) { $token = $this->lexer->peek(); assert($token !== null); } @@ -2619,39 +2614,39 @@ public function SimpleConditionalExpression() assert($lookahead !== null); // Also peek beyond a NOT if there is one. - if ($lookahead['type'] === Lexer::T_NOT) { + if ($lookahead->type === TokenType::T_NOT) { $lookahead = $this->lexer->peek(); } $this->lexer->resetPeek(); } - if ($token['type'] === Lexer::T_BETWEEN) { + if ($token->type === TokenType::T_BETWEEN) { return $this->BetweenExpression(); } - if ($token['type'] === Lexer::T_LIKE) { + if ($token->type === TokenType::T_LIKE) { return $this->LikeExpression(); } - if ($token['type'] === Lexer::T_IN) { + if ($token->type === TokenType::T_IN) { return $this->InExpression(); } - if ($token['type'] === Lexer::T_INSTANCE) { + if ($token->type === TokenType::T_INSTANCE) { return $this->InstanceOfExpression(); } - if ($token['type'] === Lexer::T_MEMBER) { + if ($token->type === TokenType::T_MEMBER) { return $this->CollectionMemberExpression(); } assert($lookahead !== null); - if ($token['type'] === Lexer::T_IS && $lookahead['type'] === Lexer::T_NULL) { + if ($token->type === TokenType::T_IS && $lookahead->type === TokenType::T_NULL) { return $this->NullComparisonExpression(); } - if ($token['type'] === Lexer::T_IS && $lookahead['type'] === Lexer::T_EMPTY) { + if ($token->type === TokenType::T_IS && $lookahead->type === TokenType::T_EMPTY) { return $this->EmptyCollectionComparisonExpression(); } @@ -2666,15 +2661,15 @@ public function SimpleConditionalExpression() public function EmptyCollectionComparisonExpression() { $pathExpression = $this->CollectionValuedPathExpression(); - $this->match(Lexer::T_IS); + $this->match(TokenType::T_IS); $not = false; - if ($this->lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); + if ($this->lexer->isNextToken(TokenType::T_NOT)) { + $this->match(TokenType::T_NOT); $not = true; } - $this->match(Lexer::T_EMPTY); + $this->match(TokenType::T_EMPTY); return new AST\EmptyCollectionComparisonExpression( $pathExpression, @@ -2695,16 +2690,16 @@ public function CollectionMemberExpression() $not = false; $entityExpr = $this->EntityExpression(); - if ($this->lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); + if ($this->lexer->isNextToken(TokenType::T_NOT)) { + $this->match(TokenType::T_NOT); $not = true; } - $this->match(Lexer::T_MEMBER); + $this->match(TokenType::T_MEMBER); - if ($this->lexer->isNextToken(Lexer::T_OF)) { - $this->match(Lexer::T_OF); + if ($this->lexer->isNextToken(TokenType::T_OF)) { + $this->match(TokenType::T_OF); } return new AST\CollectionMemberExpression( @@ -2723,27 +2718,27 @@ public function Literal() { assert($this->lexer->lookahead !== null); assert($this->lexer->token !== null); - switch ($this->lexer->lookahead['type']) { - case Lexer::T_STRING: - $this->match(Lexer::T_STRING); + switch ($this->lexer->lookahead->type) { + case TokenType::T_STRING: + $this->match(TokenType::T_STRING); - return new AST\Literal(AST\Literal::STRING, $this->lexer->token['value']); + return new AST\Literal(AST\Literal::STRING, $this->lexer->token->value); - case Lexer::T_INTEGER: - case Lexer::T_FLOAT: + case TokenType::T_INTEGER: + case TokenType::T_FLOAT: $this->match( - $this->lexer->isNextToken(Lexer::T_INTEGER) ? Lexer::T_INTEGER : Lexer::T_FLOAT, + $this->lexer->isNextToken(TokenType::T_INTEGER) ? TokenType::T_INTEGER : TokenType::T_FLOAT, ); - return new AST\Literal(AST\Literal::NUMERIC, $this->lexer->token['value']); + return new AST\Literal(AST\Literal::NUMERIC, $this->lexer->token->value); - case Lexer::T_TRUE: - case Lexer::T_FALSE: + case TokenType::T_TRUE: + case TokenType::T_FALSE: $this->match( - $this->lexer->isNextToken(Lexer::T_TRUE) ? Lexer::T_TRUE : Lexer::T_FALSE, + $this->lexer->isNextToken(TokenType::T_TRUE) ? TokenType::T_TRUE : TokenType::T_FALSE, ); - return new AST\Literal(AST\Literal::BOOLEAN, $this->lexer->token['value']); + return new AST\Literal(AST\Literal::BOOLEAN, $this->lexer->token->value); default: $this->syntaxError('Literal'); @@ -2758,7 +2753,7 @@ public function Literal() public function InParameter() { assert($this->lexer->lookahead !== null); - if ($this->lexer->lookahead['type'] === Lexer::T_INPUT_PARAMETER) { + if ($this->lexer->lookahead->type === TokenType::T_INPUT_PARAMETER) { return $this->InputParameter(); } @@ -2772,10 +2767,10 @@ public function InParameter() */ public function InputParameter() { - $this->match(Lexer::T_INPUT_PARAMETER); + $this->match(TokenType::T_INPUT_PARAMETER); assert($this->lexer->token !== null); - return new AST\InputParameter($this->lexer->token['value']); + return new AST\InputParameter($this->lexer->token->value); } /** @@ -2787,14 +2782,14 @@ public function ArithmeticExpression() { $expr = new AST\ArithmeticExpression(); - if ($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) { + if ($this->lexer->isNextToken(TokenType::T_OPEN_PARENTHESIS)) { $peek = $this->lexer->glimpse(); assert($peek !== null); - if ($peek['type'] === Lexer::T_SELECT) { - $this->match(Lexer::T_OPEN_PARENTHESIS); + if ($peek->type === TokenType::T_SELECT) { + $this->match(TokenType::T_OPEN_PARENTHESIS); $expr->subselect = $this->Subselect(); - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); return $expr; } @@ -2815,11 +2810,11 @@ public function SimpleArithmeticExpression() $terms = []; $terms[] = $this->ArithmeticTerm(); - while (($isPlus = $this->lexer->isNextToken(Lexer::T_PLUS)) || $this->lexer->isNextToken(Lexer::T_MINUS)) { - $this->match($isPlus ? Lexer::T_PLUS : Lexer::T_MINUS); + while (($isPlus = $this->lexer->isNextToken(TokenType::T_PLUS)) || $this->lexer->isNextToken(TokenType::T_MINUS)) { + $this->match($isPlus ? TokenType::T_PLUS : TokenType::T_MINUS); assert($this->lexer->token !== null); - $terms[] = $this->lexer->token['value']; + $terms[] = $this->lexer->token->value; $terms[] = $this->ArithmeticTerm(); } @@ -2842,11 +2837,11 @@ public function ArithmeticTerm() $factors = []; $factors[] = $this->ArithmeticFactor(); - while (($isMult = $this->lexer->isNextToken(Lexer::T_MULTIPLY)) || $this->lexer->isNextToken(Lexer::T_DIVIDE)) { - $this->match($isMult ? Lexer::T_MULTIPLY : Lexer::T_DIVIDE); + while (($isMult = $this->lexer->isNextToken(TokenType::T_MULTIPLY)) || $this->lexer->isNextToken(TokenType::T_DIVIDE)) { + $this->match($isMult ? TokenType::T_MULTIPLY : TokenType::T_DIVIDE); assert($this->lexer->token !== null); - $factors[] = $this->lexer->token['value']; + $factors[] = $this->lexer->token->value; $factors[] = $this->ArithmeticFactor(); } @@ -2868,9 +2863,9 @@ public function ArithmeticFactor() { $sign = null; - $isPlus = $this->lexer->isNextToken(Lexer::T_PLUS); - if ($isPlus || $this->lexer->isNextToken(Lexer::T_MINUS)) { - $this->match($isPlus ? Lexer::T_PLUS : Lexer::T_MINUS); + $isPlus = $this->lexer->isNextToken(TokenType::T_PLUS); + if ($isPlus || $this->lexer->isNextToken(TokenType::T_MINUS)) { + $this->match($isPlus ? TokenType::T_PLUS : TokenType::T_MINUS); $sign = $isPlus; } @@ -2895,47 +2890,47 @@ public function ArithmeticFactor() */ public function ArithmeticPrimary() { - if ($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) { - $this->match(Lexer::T_OPEN_PARENTHESIS); + if ($this->lexer->isNextToken(TokenType::T_OPEN_PARENTHESIS)) { + $this->match(TokenType::T_OPEN_PARENTHESIS); $expr = $this->SimpleArithmeticExpression(); - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); return new AST\ParenthesisExpression($expr); } assert($this->lexer->lookahead !== null); - switch ($this->lexer->lookahead['type']) { - case Lexer::T_COALESCE: - case Lexer::T_NULLIF: - case Lexer::T_CASE: + switch ($this->lexer->lookahead->type) { + case TokenType::T_COALESCE: + case TokenType::T_NULLIF: + case TokenType::T_CASE: return $this->CaseExpression(); - case Lexer::T_IDENTIFIER: + case TokenType::T_IDENTIFIER: $peek = $this->lexer->glimpse(); - if ($peek !== null && $peek['value'] === '(') { + if ($peek !== null && $peek->value === '(') { return $this->FunctionDeclaration(); } - if ($peek !== null && $peek['value'] === '.') { + if ($peek !== null && $peek->value === '.') { return $this->SingleValuedPathExpression(); } - if (isset($this->queryComponents[$this->lexer->lookahead['value']]['resultVariable'])) { + if (isset($this->queryComponents[$this->lexer->lookahead->value]['resultVariable'])) { return $this->ResultVariable(); } return $this->StateFieldPathExpression(); - case Lexer::T_INPUT_PARAMETER: + case TokenType::T_INPUT_PARAMETER: return $this->InputParameter(); default: $peek = $this->lexer->glimpse(); - if ($peek !== null && $peek['value'] === '(') { + if ($peek !== null && $peek->value === '(') { return $this->FunctionDeclaration(); } @@ -2954,10 +2949,10 @@ public function StringExpression() assert($peek !== null); // Subselect - if ($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS) && $peek['type'] === Lexer::T_SELECT) { - $this->match(Lexer::T_OPEN_PARENTHESIS); + if ($this->lexer->isNextToken(TokenType::T_OPEN_PARENTHESIS) && $peek->type === TokenType::T_SELECT) { + $this->match(TokenType::T_OPEN_PARENTHESIS); $expr = $this->Subselect(); - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); return $expr; } @@ -2965,8 +2960,8 @@ public function StringExpression() assert($this->lexer->lookahead !== null); // ResultVariable (string) if ( - $this->lexer->isNextToken(Lexer::T_IDENTIFIER) && - isset($this->queryComponents[$this->lexer->lookahead['value']]['resultVariable']) + $this->lexer->isNextToken(TokenType::T_IDENTIFIER) && + isset($this->queryComponents[$this->lexer->lookahead->value]['resultVariable']) ) { return $this->ResultVariable(); } @@ -2982,18 +2977,18 @@ public function StringExpression() public function StringPrimary() { assert($this->lexer->lookahead !== null); - $lookaheadType = $this->lexer->lookahead['type']; + $lookaheadType = $this->lexer->lookahead->type; switch ($lookaheadType) { - case Lexer::T_IDENTIFIER: + case TokenType::T_IDENTIFIER: $peek = $this->lexer->glimpse(); assert($peek !== null); - if ($peek['value'] === '.') { + if ($peek->value === '.') { return $this->StateFieldPathExpression(); } - if ($peek['value'] === '(') { + if ($peek->value === '(') { // do NOT directly go to FunctionsReturningString() because it doesn't check for custom functions. return $this->FunctionDeclaration(); } @@ -3001,18 +2996,18 @@ public function StringPrimary() $this->syntaxError("'.' or '('"); break; - case Lexer::T_STRING: - $this->match(Lexer::T_STRING); + case TokenType::T_STRING: + $this->match(TokenType::T_STRING); assert($this->lexer->token !== null); - return new AST\Literal(AST\Literal::STRING, $this->lexer->token['value']); + return new AST\Literal(AST\Literal::STRING, $this->lexer->token->value); - case Lexer::T_INPUT_PARAMETER: + case TokenType::T_INPUT_PARAMETER: return $this->InputParameter(); - case Lexer::T_CASE: - case Lexer::T_COALESCE: - case Lexer::T_NULLIF: + case TokenType::T_CASE: + case TokenType::T_COALESCE: + case TokenType::T_NULLIF: return $this->CaseExpression(); default: @@ -3037,7 +3032,7 @@ public function EntityExpression() $glimpse = $this->lexer->glimpse(); assert($glimpse !== null); - if ($this->lexer->isNextToken(Lexer::T_IDENTIFIER) && $glimpse['value'] === '.') { + if ($this->lexer->isNextToken(TokenType::T_IDENTIFIER) && $glimpse->value === '.') { return $this->SingleValuedAssociationPathExpression(); } @@ -3051,7 +3046,7 @@ public function EntityExpression() */ public function SimpleEntityExpression() { - if ($this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { + if ($this->lexer->isNextToken(TokenType::T_INPUT_PARAMETER)) { return $this->InputParameter(); } @@ -3067,26 +3062,26 @@ public function SimpleEntityExpression() public function AggregateExpression() { assert($this->lexer->lookahead !== null); - $lookaheadType = $this->lexer->lookahead['type']; + $lookaheadType = $this->lexer->lookahead->type; $isDistinct = false; - if (! in_array($lookaheadType, [Lexer::T_COUNT, Lexer::T_AVG, Lexer::T_MAX, Lexer::T_MIN, Lexer::T_SUM], true)) { + if (! in_array($lookaheadType, [TokenType::T_COUNT, TokenType::T_AVG, TokenType::T_MAX, TokenType::T_MIN, TokenType::T_SUM], true)) { $this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT'); } $this->match($lookaheadType); assert($this->lexer->token !== null); - $functionName = $this->lexer->token['value']; - $this->match(Lexer::T_OPEN_PARENTHESIS); + $functionName = $this->lexer->token->value; + $this->match(TokenType::T_OPEN_PARENTHESIS); - if ($this->lexer->isNextToken(Lexer::T_DISTINCT)) { - $this->match(Lexer::T_DISTINCT); + if ($this->lexer->isNextToken(TokenType::T_DISTINCT)) { + $this->match(TokenType::T_DISTINCT); $isDistinct = true; } $pathExp = $this->SimpleArithmeticExpression(); - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); return new AST\AggregateExpression($functionName, $pathExp, $isDistinct); } @@ -3099,20 +3094,20 @@ public function AggregateExpression() public function QuantifiedExpression() { assert($this->lexer->lookahead !== null); - $lookaheadType = $this->lexer->lookahead['type']; - $value = $this->lexer->lookahead['value']; + $lookaheadType = $this->lexer->lookahead->type; + $value = $this->lexer->lookahead->value; - if (! in_array($lookaheadType, [Lexer::T_ALL, Lexer::T_ANY, Lexer::T_SOME], true)) { + if (! in_array($lookaheadType, [TokenType::T_ALL, TokenType::T_ANY, TokenType::T_SOME], true)) { $this->syntaxError('ALL, ANY or SOME'); } $this->match($lookaheadType); - $this->match(Lexer::T_OPEN_PARENTHESIS); + $this->match(TokenType::T_OPEN_PARENTHESIS); $qExpr = new AST\QuantifiedExpression($this->Subselect()); $qExpr->type = $value; - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); return $qExpr; } @@ -3127,14 +3122,14 @@ public function BetweenExpression() $not = false; $arithExpr1 = $this->ArithmeticExpression(); - if ($this->lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); + if ($this->lexer->isNextToken(TokenType::T_NOT)) { + $this->match(TokenType::T_NOT); $not = true; } - $this->match(Lexer::T_BETWEEN); + $this->match(TokenType::T_BETWEEN); $arithExpr2 = $this->ArithmeticExpression(); - $this->match(Lexer::T_AND); + $this->match(TokenType::T_AND); $arithExpr3 = $this->ArithmeticExpression(); return new AST\BetweenExpression($arithExpr1, $arithExpr2, $arithExpr3, $not); @@ -3168,15 +3163,15 @@ public function InExpression() $expression = $this->ArithmeticExpression(); $not = false; - if ($this->lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); + if ($this->lexer->isNextToken(TokenType::T_NOT)) { + $this->match(TokenType::T_NOT); $not = true; } - $this->match(Lexer::T_IN); - $this->match(Lexer::T_OPEN_PARENTHESIS); + $this->match(TokenType::T_IN); + $this->match(TokenType::T_OPEN_PARENTHESIS); - if ($this->lexer->isNextToken(Lexer::T_SELECT)) { + if ($this->lexer->isNextToken(TokenType::T_SELECT)) { $inExpression = new AST\InSubselectExpression( $expression, $this->Subselect(), @@ -3185,8 +3180,8 @@ public function InExpression() } else { $literals = [$this->InParameter()]; - while ($this->lexer->isNextToken(Lexer::T_COMMA)) { - $this->match(Lexer::T_COMMA); + while ($this->lexer->isNextToken(TokenType::T_COMMA)) { + $this->match(TokenType::T_COMMA); $literals[] = $this->InParameter(); } @@ -3197,7 +3192,7 @@ public function InExpression() ); } - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); return $inExpression; } @@ -3212,15 +3207,15 @@ public function InstanceOfExpression() $identificationVariable = $this->IdentificationVariable(); $not = false; - if ($this->lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); + if ($this->lexer->isNextToken(TokenType::T_NOT)) { + $this->match(TokenType::T_NOT); $not = true; } - $this->match(Lexer::T_INSTANCE); - $this->match(Lexer::T_OF); + $this->match(TokenType::T_INSTANCE); + $this->match(TokenType::T_OF); - $exprValues = $this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS) + $exprValues = $this->lexer->isNextToken(TokenType::T_OPEN_PARENTHESIS) ? $this->InstanceOfParameterList() : [$this->InstanceOfParameter()]; @@ -3234,17 +3229,17 @@ public function InstanceOfExpression() /** @return non-empty-list */ public function InstanceOfParameterList(): array { - $this->match(Lexer::T_OPEN_PARENTHESIS); + $this->match(TokenType::T_OPEN_PARENTHESIS); $exprValues = [$this->InstanceOfParameter()]; - while ($this->lexer->isNextToken(Lexer::T_COMMA)) { - $this->match(Lexer::T_COMMA); + while ($this->lexer->isNextToken(TokenType::T_COMMA)) { + $this->match(TokenType::T_COMMA); $exprValues[] = $this->InstanceOfParameter(); } - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); return $exprValues; } @@ -3256,11 +3251,11 @@ public function InstanceOfParameterList(): array */ public function InstanceOfParameter() { - if ($this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { - $this->match(Lexer::T_INPUT_PARAMETER); + if ($this->lexer->isNextToken(TokenType::T_INPUT_PARAMETER)) { + $this->match(TokenType::T_INPUT_PARAMETER); assert($this->lexer->token !== null); - return new AST\InputParameter($this->lexer->token['value']); + return new AST\InputParameter($this->lexer->token->value); } $abstractSchemaName = $this->AbstractSchemaName(); @@ -3280,29 +3275,29 @@ public function LikeExpression() $stringExpr = $this->StringExpression(); $not = false; - if ($this->lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); + if ($this->lexer->isNextToken(TokenType::T_NOT)) { + $this->match(TokenType::T_NOT); $not = true; } - $this->match(Lexer::T_LIKE); + $this->match(TokenType::T_LIKE); - if ($this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { - $this->match(Lexer::T_INPUT_PARAMETER); + if ($this->lexer->isNextToken(TokenType::T_INPUT_PARAMETER)) { + $this->match(TokenType::T_INPUT_PARAMETER); assert($this->lexer->token !== null); - $stringPattern = new AST\InputParameter($this->lexer->token['value']); + $stringPattern = new AST\InputParameter($this->lexer->token->value); } else { $stringPattern = $this->StringPrimary(); } $escapeChar = null; - if ($this->lexer->lookahead !== null && $this->lexer->lookahead['type'] === Lexer::T_ESCAPE) { - $this->match(Lexer::T_ESCAPE); - $this->match(Lexer::T_STRING); + if ($this->lexer->lookahead !== null && $this->lexer->lookahead->type === TokenType::T_ESCAPE) { + $this->match(TokenType::T_ESCAPE); + $this->match(TokenType::T_STRING); assert($this->lexer->token !== null); - $escapeChar = new AST\Literal(AST\Literal::STRING, $this->lexer->token['value']); + $escapeChar = new AST\Literal(AST\Literal::STRING, $this->lexer->token->value); } return new AST\LikeExpression($stringExpr, $stringPattern, $escapeChar, $not); @@ -3316,18 +3311,18 @@ public function LikeExpression() public function NullComparisonExpression() { switch (true) { - case $this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER): - $this->match(Lexer::T_INPUT_PARAMETER); + case $this->lexer->isNextToken(TokenType::T_INPUT_PARAMETER): + $this->match(TokenType::T_INPUT_PARAMETER); assert($this->lexer->token !== null); - $expr = new AST\InputParameter($this->lexer->token['value']); + $expr = new AST\InputParameter($this->lexer->token->value); break; - case $this->lexer->isNextToken(Lexer::T_NULLIF): + case $this->lexer->isNextToken(TokenType::T_NULLIF): $expr = $this->NullIfExpression(); break; - case $this->lexer->isNextToken(Lexer::T_COALESCE): + case $this->lexer->isNextToken(TokenType::T_COALESCE): $expr = $this->CoalesceExpression(); break; @@ -3340,7 +3335,7 @@ public function NullComparisonExpression() $glimpse = $this->lexer->glimpse(); assert($glimpse !== null); - if ($glimpse['type'] === Lexer::T_DOT) { + if ($glimpse->type === TokenType::T_DOT) { $expr = $this->SingleValuedPathExpression(); // Leave switch statement @@ -3348,7 +3343,7 @@ public function NullComparisonExpression() } assert($this->lexer->lookahead !== null); - $lookaheadValue = $this->lexer->lookahead['value']; + $lookaheadValue = $this->lexer->lookahead->value; // Validate existing component if (! isset($this->queryComponents[$lookaheadValue])) { @@ -3370,16 +3365,16 @@ public function NullComparisonExpression() break; } - $this->match(Lexer::T_IS); + $this->match(TokenType::T_IS); $not = false; - if ($this->lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); + if ($this->lexer->isNextToken(TokenType::T_NOT)) { + $this->match(TokenType::T_NOT); $not = true; } - $this->match(Lexer::T_NULL); + $this->match(TokenType::T_NULL); return new AST\NullComparisonExpression($expr, $not); } @@ -3393,17 +3388,17 @@ public function ExistsExpression() { $not = false; - if ($this->lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); + if ($this->lexer->isNextToken(TokenType::T_NOT)) { + $this->match(TokenType::T_NOT); $not = true; } - $this->match(Lexer::T_EXISTS); - $this->match(Lexer::T_OPEN_PARENTHESIS); + $this->match(TokenType::T_EXISTS); + $this->match(TokenType::T_OPEN_PARENTHESIS); $subselect = $this->Subselect(); - $this->match(Lexer::T_CLOSE_PARENTHESIS); + $this->match(TokenType::T_CLOSE_PARENTHESIS); return new AST\ExistsExpression($subselect, $not); } @@ -3416,40 +3411,40 @@ public function ExistsExpression() public function ComparisonOperator() { assert($this->lexer->lookahead !== null); - switch ($this->lexer->lookahead['value']) { + switch ($this->lexer->lookahead->value) { case '=': - $this->match(Lexer::T_EQUALS); + $this->match(TokenType::T_EQUALS); return '='; case '<': - $this->match(Lexer::T_LOWER_THAN); + $this->match(TokenType::T_LOWER_THAN); $operator = '<'; - if ($this->lexer->isNextToken(Lexer::T_EQUALS)) { - $this->match(Lexer::T_EQUALS); + if ($this->lexer->isNextToken(TokenType::T_EQUALS)) { + $this->match(TokenType::T_EQUALS); $operator .= '='; - } elseif ($this->lexer->isNextToken(Lexer::T_GREATER_THAN)) { - $this->match(Lexer::T_GREATER_THAN); + } elseif ($this->lexer->isNextToken(TokenType::T_GREATER_THAN)) { + $this->match(TokenType::T_GREATER_THAN); $operator .= '>'; } return $operator; case '>': - $this->match(Lexer::T_GREATER_THAN); + $this->match(TokenType::T_GREATER_THAN); $operator = '>'; - if ($this->lexer->isNextToken(Lexer::T_EQUALS)) { - $this->match(Lexer::T_EQUALS); + if ($this->lexer->isNextToken(TokenType::T_EQUALS)) { + $this->match(TokenType::T_EQUALS); $operator .= '='; } return $operator; case '!': - $this->match(Lexer::T_NEGATE); - $this->match(Lexer::T_EQUALS); + $this->match(TokenType::T_NEGATE); + $this->match(TokenType::T_EQUALS); return '<>'; @@ -3467,7 +3462,7 @@ public function FunctionDeclaration() { assert($this->lexer->lookahead !== null); $token = $this->lexer->lookahead; - $funcName = strtolower($token['value']); + $funcName = strtolower($token->value); $customFunctionDeclaration = $this->CustomFunctionDeclaration(); @@ -3497,7 +3492,7 @@ private function CustomFunctionDeclaration(): Functions\FunctionNode|null { assert($this->lexer->lookahead !== null); $token = $this->lexer->lookahead; - $funcName = strtolower($token['value']); + $funcName = strtolower($token->value); // Check for custom functions afterwards $config = $this->em->getConfiguration(); @@ -3534,7 +3529,7 @@ private function CustomFunctionDeclaration(): Functions\FunctionNode|null public function FunctionsReturningNumerics() { assert($this->lexer->lookahead !== null); - $funcNameLower = strtolower($this->lexer->lookahead['value']); + $funcNameLower = strtolower($this->lexer->lookahead->value); $funcClass = self::$numericFunctions[$funcNameLower]; $function = new $funcClass($funcNameLower); @@ -3548,7 +3543,7 @@ public function CustomFunctionsReturningNumerics() { assert($this->lexer->lookahead !== null); // getCustomNumericFunction is case-insensitive - $functionName = strtolower($this->lexer->lookahead['value']); + $functionName = strtolower($this->lexer->lookahead->value); $functionClass = $this->em->getConfiguration()->getCustomNumericFunction($functionName); assert($functionClass !== null); @@ -3575,7 +3570,7 @@ public function CustomFunctionsReturningNumerics() public function FunctionsReturningDatetime() { assert($this->lexer->lookahead !== null); - $funcNameLower = strtolower($this->lexer->lookahead['value']); + $funcNameLower = strtolower($this->lexer->lookahead->value); $funcClass = self::$datetimeFunctions[$funcNameLower]; $function = new $funcClass($funcNameLower); @@ -3589,7 +3584,7 @@ public function CustomFunctionsReturningDatetime() { assert($this->lexer->lookahead !== null); // getCustomDatetimeFunction is case-insensitive - $functionName = $this->lexer->lookahead['value']; + $functionName = $this->lexer->lookahead->value; $functionClass = $this->em->getConfiguration()->getCustomDatetimeFunction($functionName); assert($functionClass !== null); @@ -3617,7 +3612,7 @@ public function CustomFunctionsReturningDatetime() public function FunctionsReturningStrings() { assert($this->lexer->lookahead !== null); - $funcNameLower = strtolower($this->lexer->lookahead['value']); + $funcNameLower = strtolower($this->lexer->lookahead->value); $funcClass = self::$stringFunctions[$funcNameLower]; $function = new $funcClass($funcNameLower); @@ -3631,7 +3626,7 @@ public function CustomFunctionsReturningStrings() { assert($this->lexer->lookahead !== null); // getCustomStringFunction is case-insensitive - $functionName = $this->lexer->lookahead['value']; + $functionName = $this->lexer->lookahead->value; $functionClass = $this->em->getConfiguration()->getCustomStringFunction($functionName); assert($functionClass !== null); diff --git a/lib/Doctrine/ORM/Query/TokenType.php b/lib/Doctrine/ORM/Query/TokenType.php new file mode 100644 index 00000000000..bf1c351c2a6 --- /dev/null +++ b/lib/Doctrine/ORM/Query/TokenType.php @@ -0,0 +1,92 @@ += 100 + case T_FULLY_QUALIFIED_NAME = 101; + case T_IDENTIFIER = 102; + + // All keyword tokens should be >= 200 + case T_ALL = 200; + case T_AND = 201; + case T_ANY = 202; + case T_AS = 203; + case T_ASC = 204; + case T_AVG = 205; + case T_BETWEEN = 206; + case T_BOTH = 207; + case T_BY = 208; + case T_CASE = 209; + case T_COALESCE = 210; + case T_COUNT = 211; + case T_DELETE = 212; + case T_DESC = 213; + case T_DISTINCT = 214; + case T_ELSE = 215; + case T_EMPTY = 216; + case T_END = 217; + case T_ESCAPE = 218; + case T_EXISTS = 219; + case T_FALSE = 220; + case T_FROM = 221; + case T_GROUP = 222; + case T_HAVING = 223; + case T_HIDDEN = 224; + case T_IN = 225; + case T_INDEX = 226; + case T_INNER = 227; + case T_INSTANCE = 228; + case T_IS = 229; + case T_JOIN = 230; + case T_LEADING = 231; + case T_LEFT = 232; + case T_LIKE = 233; + case T_MAX = 234; + case T_MEMBER = 235; + case T_MIN = 236; + case T_NEW = 237; + case T_NOT = 238; + case T_NULL = 239; + case T_NULLIF = 240; + case T_OF = 241; + case T_OR = 242; + case T_ORDER = 243; + case T_OUTER = 244; + case T_PARTIAL = 245; + case T_SELECT = 246; + case T_SET = 247; + case T_SOME = 248; + case T_SUM = 249; + case T_THEN = 250; + case T_TRAILING = 251; + case T_TRUE = 252; + case T_UPDATE = 253; + case T_WHEN = 254; + case T_WHERE = 255; + case T_WITH = 256; +} diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index b1b3f200e2d..bee4d410305 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -266,7 +266,7 @@ parameters: path: lib/Doctrine/ORM/Query/Parser.php - - message: "#^Method Doctrine\\\\ORM\\\\Query\\\\Parser\\:\\:peekBeyondClosingParenthesis\\(\\) never returns array so it can be removed from the return type\\.$#" + message: "#^Method Doctrine\\\\ORM\\\\Query\\\\Parser\\:\\:ArithmeticTerm\\(\\) should return Doctrine\\\\ORM\\\\Query\\\\AST\\\\ArithmeticTerm but returns Doctrine\\\\ORM\\\\Query\\\\AST\\\\ArithmeticFactor\\|string\\.$#" count: 1 path: lib/Doctrine/ORM/Query/Parser.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index e84881876eb..2c67f40d950 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1217,6 +1217,10 @@ $stringPattern + + $this->lexer->lookahead !== null && $this->lexer->lookahead->type === TokenType::T_ESCAPE + $token->type === TokenType::T_OPEN_PARENTHESIS + AST\SelectStatement|AST\UpdateStatement|AST\DeleteStatement @@ -1274,28 +1278,26 @@ $this->ConditionalExpression() $this->SimpleArithmeticExpression() - + $dql $this->query->getDQL() + $token->value - - $this->lexer->glimpse()['type'] - $token['value'] - - - $this->lexer->glimpse() - $token + + $lookaheadType->value + $lookaheadType->value + $this->lexer->glimpse()->type + $token->value + $token->value + + getNumberOfRequiredParameters $args - - $this->lexer->lookahead !== null - - + $AST instanceof AST\SelectStatement - $token === Lexer::T_IDENTIFIER diff --git a/tests/Doctrine/Tests/ORM/Functional/CustomFunctionsTest.php b/tests/Doctrine/Tests/ORM/Functional/CustomFunctionsTest.php index 4b21059fedc..8c71f8d1f43 100644 --- a/tests/Doctrine/Tests/ORM/Functional/CustomFunctionsTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/CustomFunctionsTest.php @@ -7,9 +7,9 @@ use Doctrine\ORM\Query\AST\AggregateExpression; use Doctrine\ORM\Query\AST\Functions\FunctionNode; use Doctrine\ORM\Query\AST\PathExpression; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; use Doctrine\Tests\Models\CMS\CmsUser; use Doctrine\Tests\OrmFunctionalTestCase; @@ -71,10 +71,10 @@ class NoOp extends FunctionNode public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->field = $parser->ArithmeticPrimary(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } public function getSql(SqlWalker $sqlWalker): string diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7286Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7286Test.php index c56f66e13a4..52e3132b6d3 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7286Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7286Test.php @@ -10,9 +10,9 @@ use Doctrine\ORM\Mapping\Id; use Doctrine\ORM\Query\AST\Functions\FunctionNode; use Doctrine\ORM\Query\AST\Node; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; use Doctrine\Tests\OrmFunctionalTestCase; final class GH7286Test extends OrmFunctionalTestCase @@ -100,14 +100,14 @@ class GH7286CustomConcat extends FunctionNode public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->first = $parser->StringPrimary(); - $parser->match(Lexer::T_COMMA); + $parser->match(TokenType::T_COMMA); $this->second = $parser->StringPrimary(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } public function getSql(SqlWalker $walker): string diff --git a/tests/Doctrine/Tests/ORM/Query/LexerTest.php b/tests/Doctrine/Tests/ORM/Query/LexerTest.php index c5f4a3ccf03..a2240719bec 100644 --- a/tests/Doctrine/Tests/ORM/Query/LexerTest.php +++ b/tests/Doctrine/Tests/ORM/Query/LexerTest.php @@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Query; use Doctrine\ORM\Query\Lexer; +use Doctrine\ORM\Query\TokenType; use Doctrine\Tests\OrmTestCase; class LexerTest extends OrmTestCase @@ -34,7 +35,7 @@ public function testScannerRecognizesTerminalString(): void $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_ALL, $token['type']); + self::assertEquals(TokenType::T_ALL, $token['type']); } public function testScannerRecognizesDecimalInteger(): void @@ -42,7 +43,7 @@ public function testScannerRecognizesDecimalInteger(): void $lexer = new Lexer('1234'); $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_INTEGER, $token['type']); + self::assertEquals(TokenType::T_INTEGER, $token['type']); self::assertEquals(1234, $token['value']); } @@ -51,7 +52,7 @@ public function testScannerRecognizesFloat(): void $lexer = new Lexer('1.234'); $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_FLOAT, $token['type']); + self::assertEquals(TokenType::T_FLOAT, $token['type']); self::assertEquals(1.234, $token['value']); } @@ -60,7 +61,7 @@ public function testScannerRecognizesFloatWithExponent(): void $lexer = new Lexer('1.2e3'); $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_FLOAT, $token['type']); + self::assertEquals(TokenType::T_FLOAT, $token['type']); self::assertEquals(1.2e3, $token['value']); } @@ -69,7 +70,7 @@ public function testScannerRecognizesFloatWithExponent2(): void $lexer = new Lexer('0.2e3'); $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_FLOAT, $token['type']); + self::assertEquals(TokenType::T_FLOAT, $token['type']); self::assertEquals(.2e3, $token['value']); } @@ -78,7 +79,7 @@ public function testScannerRecognizesFloatWithNegativeExponent(): void $lexer = new Lexer('7E-10'); $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_FLOAT, $token['type']); + self::assertEquals(TokenType::T_FLOAT, $token['type']); self::assertEquals(7E-10, $token['value']); } @@ -87,7 +88,7 @@ public function testScannerRecognizesFloatBig(): void $lexer = new Lexer('123456789.01'); $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_FLOAT, $token['type']); + self::assertEquals(TokenType::T_FLOAT, $token['type']); self::assertEquals(1.2345678901e8, $token['value']); } @@ -96,12 +97,12 @@ public function testScannerRecognizesFloatContainingWhitespace(): void $lexer = new Lexer('- 1.234e2'); $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_MINUS, $token['type']); + self::assertEquals(TokenType::T_MINUS, $token['type']); self::assertEquals('-', $token['value']); $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_FLOAT, $token['type']); + self::assertEquals(TokenType::T_FLOAT, $token['type']); self::assertNotEquals(-1.234e2, $token['value']); self::assertEquals(1.234e2, $token['value']); } @@ -111,7 +112,7 @@ public function testScannerRecognizesStringContainingWhitespace(): void $lexer = new Lexer("'This is a string.'"); $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_STRING, $token['type']); + self::assertEquals(TokenType::T_STRING, $token['type']); self::assertEquals('This is a string.', $token['value']); } @@ -120,7 +121,7 @@ public function testScannerRecognizesStringContainingSingleQuotes(): void $lexer = new Lexer("'abc''defg'''"); $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_STRING, $token['type']); + self::assertEquals(TokenType::T_STRING, $token['type']); self::assertEquals("abc'defg'", $token['value']); } @@ -129,7 +130,7 @@ public function testScannerRecognizesInputParameter(): void $lexer = new Lexer('?1'); $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_INPUT_PARAMETER, $token['type']); + self::assertEquals(TokenType::T_INPUT_PARAMETER, $token['type']); self::assertEquals('?1', $token['value']); } @@ -138,7 +139,7 @@ public function testScannerRecognizesNamedInputParameter(): void $lexer = new Lexer(':name'); $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_INPUT_PARAMETER, $token['type']); + self::assertEquals(TokenType::T_INPUT_PARAMETER, $token['type']); self::assertEquals(':name', $token['value']); } @@ -147,7 +148,7 @@ public function testScannerRecognizesNamedInputParameterStartingWithUnderscore() $lexer = new Lexer(':_name'); $lexer->moveNext(); $token = $lexer->lookahead; - self::assertEquals(Lexer::T_INPUT_PARAMETER, $token['type']); + self::assertEquals(TokenType::T_INPUT_PARAMETER, $token['type']); self::assertEquals(':_name', $token['value']); } @@ -159,57 +160,57 @@ public function testScannerTokenizesASimpleQueryCorrectly(): void $tokens = [ [ 'value' => 'SELECT', - 'type' => Lexer::T_SELECT, + 'type' => TokenType::T_SELECT, 'position' => 0, ], [ 'value' => 'u', - 'type' => Lexer::T_IDENTIFIER, + 'type' => TokenType::T_IDENTIFIER, 'position' => 7, ], [ 'value' => 'FROM', - 'type' => Lexer::T_FROM, + 'type' => TokenType::T_FROM, 'position' => 9, ], [ 'value' => 'My\Namespace\User', - 'type' => Lexer::T_FULLY_QUALIFIED_NAME, + 'type' => TokenType::T_FULLY_QUALIFIED_NAME, 'position' => 14, ], [ 'value' => 'u', - 'type' => Lexer::T_IDENTIFIER, + 'type' => TokenType::T_IDENTIFIER, 'position' => 32, ], [ 'value' => 'WHERE', - 'type' => Lexer::T_WHERE, + 'type' => TokenType::T_WHERE, 'position' => 34, ], [ 'value' => 'u', - 'type' => Lexer::T_IDENTIFIER, + 'type' => TokenType::T_IDENTIFIER, 'position' => 40, ], [ 'value' => '.', - 'type' => Lexer::T_DOT, + 'type' => TokenType::T_DOT, 'position' => 41, ], [ 'value' => 'name', - 'type' => Lexer::T_IDENTIFIER, + 'type' => TokenType::T_IDENTIFIER, 'position' => 42, ], [ 'value' => '=', - 'type' => Lexer::T_EQUALS, + 'type' => TokenType::T_EQUALS, 'position' => 47, ], [ 'value' => "Jack O'Neil", - 'type' => Lexer::T_STRING, + 'type' => TokenType::T_STRING, 'position' => 49, ], ]; @@ -229,13 +230,13 @@ public function testScannerTokenizesASimpleQueryCorrectly(): void public function provideTokens(): array { return [ - [Lexer::T_IDENTIFIER, 'u'], // one char - [Lexer::T_IDENTIFIER, 'someIdentifier'], - [Lexer::T_IDENTIFIER, 's0m31d3nt1f13r'], // including digits - [Lexer::T_IDENTIFIER, 'some_identifier'], // including underscore - [Lexer::T_IDENTIFIER, '_some_identifier'], // starts with underscore - [Lexer::T_IDENTIFIER, 'comma'], // name of a token class with value < 100 (whitebox test) - [Lexer::T_FULLY_QUALIFIED_NAME, 'Some\Class'], // DQL class reference + [TokenType::T_IDENTIFIER, 'u'], // one char + [TokenType::T_IDENTIFIER, 'someIdentifier'], + [TokenType::T_IDENTIFIER, 's0m31d3nt1f13r'], // including digits + [TokenType::T_IDENTIFIER, 'some_identifier'], // including underscore + [TokenType::T_IDENTIFIER, '_some_identifier'], // starts with underscore + [TokenType::T_IDENTIFIER, 'comma'], // name of a token class with value < 100 (whitebox test) + [TokenType::T_FULLY_QUALIFIED_NAME, 'Some\Class'], // DQL class reference ]; } } diff --git a/tests/Doctrine/Tests/ORM/Query/ParserTest.php b/tests/Doctrine/Tests/ORM/Query/ParserTest.php index 2a2a15f9f62..a52e967b5fa 100644 --- a/tests/Doctrine/Tests/ORM/Query/ParserTest.php +++ b/tests/Doctrine/Tests/ORM/Query/ParserTest.php @@ -5,9 +5,9 @@ namespace Doctrine\Tests\ORM\Query; use Doctrine\ORM\Query; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\QueryException; +use Doctrine\ORM\Query\TokenType; use Doctrine\Tests\Models\CMS\CmsUser; use Doctrine\Tests\OrmTestCase; use stdClass; @@ -52,7 +52,7 @@ public function testAbstractSchemaNameSupportsIdentifier(): void * @covers Doctrine\ORM\Query\Parser::match * @group DDC-3701 */ - public function testMatch(int $expectedToken, string $inputString): void + public function testMatch(TokenType $expectedToken, string $inputString): void { $parser = $this->createParser($inputString); @@ -66,7 +66,7 @@ public function testMatch(int $expectedToken, string $inputString): void * @covers Doctrine\ORM\Query\Parser::match * @group DDC-3701 */ - public function testMatchFailure(int $expectedToken, string $inputString): void + public function testMatchFailure(TokenType $expectedToken, string $inputString): void { $this->expectException(QueryException::class); @@ -87,11 +87,11 @@ public function validMatches() * but in LexerTest. */ return [ - [Lexer::T_WHERE, 'where'], // keyword - [Lexer::T_DOT, '.'], // token that cannot be an identifier - [Lexer::T_IDENTIFIER, 'someIdentifier'], - [Lexer::T_IDENTIFIER, 'from'], // also a terminal string (the "FROM" keyword) as in DDC-505 - [Lexer::T_IDENTIFIER, 'comma'], + [TokenType::T_WHERE, 'where'], // keyword + [TokenType::T_DOT, '.'], // token that cannot be an identifier + [TokenType::T_IDENTIFIER, 'someIdentifier'], + [TokenType::T_IDENTIFIER, 'from'], // also a terminal string (the "FROM" keyword) as in DDC-505 + [TokenType::T_IDENTIFIER, 'comma'], // not even a terminal string, but the name of a constant in the Lexer (whitebox test) ]; } @@ -100,14 +100,14 @@ public function validMatches() public function invalidMatches(): array { return [ - [Lexer::T_DOT, 'ALL'], // ALL is a terminal string (reserved keyword) and also possibly an identifier - [Lexer::T_DOT, ','], // "," is a token on its own, but cannot be used as identifier - [Lexer::T_WHERE, 'WITH'], // as in DDC-3697 - [Lexer::T_WHERE, '.'], + [TokenType::T_DOT, 'ALL'], // ALL is a terminal string (reserved keyword) and also possibly an identifier + [TokenType::T_DOT, ','], // "," is a token on its own, but cannot be used as identifier + [TokenType::T_WHERE, 'WITH'], // as in DDC-3697 + [TokenType::T_WHERE, '.'], // The following are qualified or aliased names and must not be accepted where only an Identifier is expected - [Lexer::T_IDENTIFIER, '\\Some\\Class'], - [Lexer::T_IDENTIFIER, 'Some\\Class'], + [TokenType::T_IDENTIFIER, '\\Some\\Class'], + [TokenType::T_IDENTIFIER, 'Some\\Class'], ]; } @@ -126,7 +126,7 @@ public function testNullLookahead(): void $parser = new Parser($query); $this->expectException(QueryException::class); - $parser->match(Lexer::T_SELECT); + $parser->match(TokenType::T_SELECT); } private function createParser(string $dql): Parser diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index 3ce84c59f24..d2f9b2be064 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -18,10 +18,10 @@ use Doctrine\ORM\Query as ORMQuery; use Doctrine\ORM\Query\AST\Functions\FunctionNode; use Doctrine\ORM\Query\AST\SimpleArithmeticExpression; -use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\QueryException; use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; use Doctrine\Tests\DbalTypes\NegativeToPositiveType; use Doctrine\Tests\Models\CMS\CmsGroup; use Doctrine\Tests\Models\CMS\CmsPhonenumber; @@ -2186,12 +2186,12 @@ public function parse(Parser $parser): void { $lexer = $parser->getLexer(); - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } } #[Entity]