From 16eb604b3aaf9f87ecf83bdefa0c1286d61d31eb Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 14 Dec 2023 21:24:26 +0100 Subject: [PATCH] added nullsafe pipe operator ?| --- .../Nodes/Php/Expression/FilterCallNode.php | 9 +- src/Latte/Compiler/Nodes/Php/FilterNode.php | 18 +- src/Latte/Compiler/Nodes/Php/ModifierNode.php | 4 +- src/Latte/Compiler/TagLexer.php | 1 + src/Latte/Compiler/TagParserData.php | 636 +++++++++--------- src/Latte/Compiler/Token.php | 4 +- tests/common/Compiler.errors.phpt | 6 + tests/common/TagParser.parseArguments().phpt | 6 + tests/common/TagParser.parseModifier().phpt | 4 + tests/phpParser/filters.phpt | 10 + tests/phpParser/filtersNullsafe.phpt | 252 +++++++ tests/phpParser/modifier.phpt | 3 + tests/phpParser/modifierNullsafe.phpt | 75 +++ tests/tags/print.phpt | 4 +- 14 files changed, 707 insertions(+), 325 deletions(-) create mode 100644 tests/phpParser/filtersNullsafe.phpt create mode 100644 tests/phpParser/modifierNullsafe.phpt diff --git a/src/Latte/Compiler/Nodes/Php/Expression/FilterCallNode.php b/src/Latte/Compiler/Nodes/Php/Expression/FilterCallNode.php index 966a9fe01..c25aa64ce 100644 --- a/src/Latte/Compiler/Nodes/Php/Expression/FilterCallNode.php +++ b/src/Latte/Compiler/Nodes/Php/Expression/FilterCallNode.php @@ -27,7 +27,14 @@ public function __construct( public function print(PrintContext $context): string { - return $this->filter->printSimple($context, $this->expr->print($context)); + for ( + $node = $this, $outer = null; + $node->expr instanceof self; + $node = $node->expr + ) { + $outer = fn(string $expr) => $node->filter->printSimple($context, $expr, $outer); + } + return $node->filter->printSimple($context, $node->expr->print($context), $outer); } diff --git a/src/Latte/Compiler/Nodes/Php/FilterNode.php b/src/Latte/Compiler/Nodes/Php/FilterNode.php index 666f67c72..e904644e0 100644 --- a/src/Latte/Compiler/Nodes/Php/FilterNode.php +++ b/src/Latte/Compiler/Nodes/Php/FilterNode.php @@ -9,6 +9,7 @@ namespace Latte\Compiler\Nodes\Php; +use Latte\CompileException; use Latte\Compiler\Node; use Latte\Compiler\Position; use Latte\Compiler\PrintContext; @@ -20,6 +21,7 @@ public function __construct( public IdentifierNode $name, /** @var ArgumentNode[] */ public array $args = [], + public bool $nullsafe = false, public ?Position $position = null, ) { (function (ArgumentNode ...$args) {})(...$args); @@ -32,17 +34,23 @@ public function print(PrintContext $context): string } - public function printSimple(PrintContext $context, string $expr): string + public function printSimple(PrintContext $context, string $expr, ?callable $outer): string { - return '($this->filters->' . $context->objectProperty($this->name) . ')(' - . $expr - . ($this->args ? ', ' . $context->implode($this->args) : '') - . ')'; + $outer ??= fn($x) => $x; + return ($this->nullsafe ? '(($ʟ_fv = ' . $expr . ') === null ? null : ' : '') + . $outer('($this->filters->' . $context->objectProperty($this->name) . ')(' + . ($this->nullsafe ? '$ʟ_fv' : $expr) + . ($this->args ? ', ' . $context->implode($this->args) : '') + . ')') + . ($this->nullsafe ? ')' : ''); } public function printContentAware(PrintContext $context, string $expr): string { + if ($this->nullsafe) { + throw new CompileException('Nullsafe pipe is not allowed here', $this->position); + } return '$this->filters->filterContent(' . $context->encodeString($this->name->name) . ', $ʟ_fi, ' diff --git a/src/Latte/Compiler/Nodes/Php/ModifierNode.php b/src/Latte/Compiler/Nodes/Php/ModifierNode.php index a1a05e370..4f15b9611 100644 --- a/src/Latte/Compiler/Nodes/Php/ModifierNode.php +++ b/src/Latte/Compiler/Nodes/Php/ModifierNode.php @@ -49,6 +49,7 @@ public function printSimple(PrintContext $context, string $expr): string { $escape = $this->escape; $check = $this->check; + $expr = new Expression\AuxiliaryNode(fn() => $expr); foreach ($this->filters as $filter) { $name = $filter->name->name; if ($name === 'nocheck' || $name === 'noCheck') { @@ -59,9 +60,10 @@ public function printSimple(PrintContext $context, string $expr): string if ($name === 'datastream' || $name === 'dataStream') { $check = false; } - $expr = $filter->printSimple($context, $expr); + $expr = new Expression\FilterCallNode($expr, $filter); } } + $expr = $expr->print($context); $escaper = $context->getEscaper(); if ($check) { diff --git a/src/Latte/Compiler/TagLexer.php b/src/Latte/Compiler/TagLexer.php index 936c41a2f..a01ee9897 100644 --- a/src/Latte/Compiler/TagLexer.php +++ b/src/Latte/Compiler/TagLexer.php @@ -145,6 +145,7 @@ private function tokenizeCode(): void (? \*\*= )| (? \?\?= )| (? \?\? )| + (? \?\| )| (? \|\| )| (? && )| (? & (?= [ \t\r\n]* (\$|\.\.\.) ) )| diff --git a/src/Latte/Compiler/TagParserData.php b/src/Latte/Compiler/TagParserData.php index 8d00dc577..7a0d69059 100644 --- a/src/Latte/Compiler/TagParserData.php +++ b/src/Latte/Compiler/TagParserData.php @@ -26,230 +26,234 @@ abstract class TagParserData /** Rule number signifying that an unexpected token was encountered */ protected const UnexpectedTokenRule = 8191; - protected const Yy2Tblstate = 257; + protected const Yy2Tblstate = 261; /** Number of non-leaf states */ - protected const NumNonLeafStates = 354; + protected const NumNonLeafStates = 356; /** Map of lexer tokens to internal symbols */ protected const TokenToSymbol = [ - 0, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, - 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 48, 108, 113, 109, 47, 113, 113, - 102, 103, 45, 43, 2, 44, 39, 46, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 22, 106, - 35, 7, 37, 21, 59, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, - 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 61, 113, 107, 27, 113, 113, 100, 113, 113, - 113, 98, 101, 113, 113, 113, 113, 113, 113, 99, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, - 113, 113, 113, 104, 26, 105, 50, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, - 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, - 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, - 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, - 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, - 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, - 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 1, 3, 4, 5, - 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 23, 24, 25, 28, 29, 30, - 31, 32, 33, 34, 36, 38, 40, 41, 42, 49, 51, 52, 53, 54, 55, 56, 57, 58, 60, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, 90, 110, 91, 92, 93, 94, 111, 112, 95, 96, 97, + 0, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 47, 109, 114, 110, 46, 114, 114, + 102, 103, 44, 42, 2, 43, 38, 45, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 22, 107, + 34, 7, 36, 21, 58, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 60, 114, 108, 26, 114, 114, 100, 114, 114, + 114, 98, 101, 114, 114, 114, 114, 114, 114, 99, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 104, 106, 105, 49, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 1, 3, 4, 5, + 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 23, 24, 25, 27, 28, 29, + 30, 31, 32, 33, 35, 37, 39, 40, 41, 48, 50, 51, 52, 53, 54, 55, 56, 57, 59, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 111, 90, 91, 92, 93, 112, 113, 94, 95, 96, 97, ]; /** Map of states to a displacement into the self::Action table. The corresponding action for this * state/symbol pair is self::Action[self::ActionBase[$state] + $symbol]. If self::ActionBase[$state] is 0, the * action is defaulted, i.e. self::ActionDefault[$state] should be used instead. */ protected const ActionBase = [ - 297, 326, 326, 326, 326, 99, 121, 326, 273, 177, 230, 326, 406, 406, 406, 406, 406, 219, 219, 219, - 219, 287, 287, 291, 277, 401, 402, 403, 404, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, 133, 198, 214, 416, 432, 427, 436, 459, 460, 458, - 462, 468, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 137, 182, 528, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 549, 549, 549, - 437, 362, 204, 412, 38, 110, 110, 513, 513, 513, 513, 513, 447, 81, 81, 81, 81, 500, 500, 271, - 271, 271, 271, 271, 271, 271, 271, 271, 272, 135, 135, 454, 13, 275, 275, 275, 228, 228, 228, 228, - 228, 181, 108, 108, 108, 236, 355, 409, 276, 207, 207, 207, 207, 207, 207, 282, 469, -21, 132, 132, - 205, 167, 167, 132, 378, -13, 122, -34, 208, 332, 221, 143, 158, 2, 405, 259, 262, 299, 142, 219, - 470, 470, 219, 219, 219, 411, 64, 64, 64, 147, 180, 39, 293, 445, 293, 293, 293, 42, 26, -74, - 268, 352, 344, 351, 268, 62, 98, 65, 354, 357, 352, 352, 104, 65, 65, 294, 300, 298, 134, 76, - 298, 290, 290, 109, 35, 363, 360, 369, 342, 341, 304, 234, 253, 284, 281, 337, 252, 363, 360, 369, - 263, 6, 310, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 234, 452, 36, 288, 374, 375, 17, - 395, 397, 450, 296, 451, 285, 278, 305, 279, 461, 331, 24, 234, 466, 286, 384, 301, 306, 385, 292, - 467, 398, 280, 453, 140, 376, 165, 455, 185, 408, 260, 400, 465, 457, 0, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 317, 363, 363, 363, 363, 98, 151, 363, 310, 204, 257, 363, 442, 442, 442, 442, 442, 240, 240, 240, + 240, 333, 333, 303, 328, 402, 403, 407, 408, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, 304, 295, 297, 410, 420, 419, 422, 437, 438, 436, + 441, 457, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 216, 35, 352, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 349, 349, 349, + 322, 41, 179, 448, -41, 109, 109, 548, 548, 548, 548, 548, 483, 483, 81, 81, 81, 81, 536, 536, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 218, 49, 49, 318, 121, 56, 56, 56, 12, 12, 12, + 12, 12, 215, 205, 205, 205, 154, 210, 260, 334, 129, 129, 129, 129, 129, 129, 336, 325, 313, 316, + 316, 391, 230, 230, 316, 47, 123, -46, 62, 87, 229, 299, 300, 220, 185, 409, 286, 294, 329, 399, + 26, 26, 240, 456, 456, 100, 240, 240, 240, 100, 175, 175, 175, -31, -28, 238, 273, 423, 273, 273, + 273, 32, 184, -70, 376, 374, 375, 127, 159, 149, 377, 379, 376, 376, 178, 149, 149, 332, 342, 341, + 196, 155, 341, 324, 324, 193, 72, 382, 380, 383, 373, 372, 429, 214, 239, 338, 330, 350, 284, 382, + 380, 383, 326, 17, 347, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 214, 335, 107, 340, 387, + 389, 31, 393, 394, 388, 305, 431, 285, 339, 346, 321, 386, 348, 34, 214, 439, 327, 323, 421, 337, + 392, 309, 446, 397, 331, 433, 249, 390, 268, 434, 280, 430, 256, 398, 428, 435, 0, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 0, 447, 52, - 52, 52, 52, 52, 52, 52, 0, 108, 108, 108, 108, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, 108, -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, 0, 0, 0, 0, 0, - 0, 0, 378, 290, 290, 290, 290, 290, 290, 378, 378, 0, 0, 0, 0, 108, 108, 0, 0, 378, - 290, 0, 0, 0, 0, 0, 0, 0, 219, 219, 219, 378, 0, 0, 290, 290, 0, 0, 0, 268, - 0, 0, 0, 0, 0, 0, 285, 36, 285, 285, 285, + 0, 0, 0, 0, 0, 0, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 0, + 483, 52, 52, 52, 52, 52, 52, 52, 0, 0, 205, 205, 205, 205, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 205, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 0, 0, + 0, 0, 0, 0, 0, 123, 324, 324, 324, 324, 324, 324, 123, 123, 0, 0, 0, 0, 205, 205, + 0, 0, 0, 123, 324, 0, 0, 0, 0, 0, 0, 240, 240, 240, 123, 100, 0, 0, 0, 324, + 324, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 285, 107, 285, 285, 285, ]; /** Table of actions. Indexed according to self::ActionBase comment. */ protected const Action = [ - 35, 36, -269, 33, -269, 37, -50, 38, 179, 180, 39, 40, 41, 42, 43, 44, 45, -48, 1, 193, - 46, 557, 558, 205, -47, 539, 381, -222, 16, 555, 285, 522, 242, 243, 196, 0, 286, 287, 7, -47, - -220, 288, 289, 208, 537, 178, 539, -222, -222, -222, 541, 540, 563, 561, 562, 55, 56, 57, -8190, 30, - -220, -220, -220, 416, 11, 224, 290, 15, 197, -220, 198, 541, 540, 24, 566, 58, 59, 60, 22, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 102, 195, 362, 363, 361, -269, 191, 381, 418, -269, 417, 234, 82, -8190, -8190, -8190, -8191, -8191, -8191, -8191, - 73, 74, 75, 76, 362, 363, 361, 360, 359, 446, 379, -8190, 380, -8190, -8190, -8190, 383, -8190, -8190, -8190, - -8190, 372, 99, -78, 12, -78, 106, 290, 366, 360, 359, 77, 78, 79, 80, 81, 196, 195, -267, 172, - -267, 194, 47, 372, 13, 201, 339, 296, 82, -78, 366, 107, 297, 368, 235, 236, 367, 373, 298, 299, - 362, 363, 361, 194, 47, -8190, -8190, 201, 641, 296, 25, 108, 642, -217, 297, 368, 235, 236, 367, 373, - 298, 299, 427, -22, 18, 360, 359, -8190, -8190, -8190, -8190, -8190, 26, -217, -217, -217, -8190, -8190, -8190, 372, - 20, -265, -217, -265, 427, -8190, 366, -8190, -8190, -8190, 418, -8190, 417, 362, 363, 361, 207, -184, -52, 194, - 47, 96, -223, 201, 14, 296, -78, 360, 359, -184, 297, 368, 235, 236, 367, 373, 298, 299, 360, 359, - 97, -267, -223, -223, -223, -267, 32, 109, 27, 31, -183, -183, 372, 379, -23, 380, 362, 363, 361, 366, - 427, -17, -183, -183, -16, 19, 212, 213, 214, 209, 210, 211, 194, 47, 172, 241, 201, -223, 296, 98, - 105, 360, 359, 297, 368, 235, 236, 367, 373, 298, 299, 100, 74, 75, 76, 372, 290, -223, -223, -223, - 192, 28, 366, 418, -265, 417, -183, 199, -265, 362, 363, 361, 1, 427, 200, 194, 47, 250, -183, 201, - 381, 296, 195, 555, 381, 82, 297, 368, 235, 236, 367, 373, 298, 299, 360, 359, 289, 103, 322, 381, - -8190, 278, 643, 567, 101, -8190, -8190, -8190, 372, 568, -8190, -192, 345, 50, 164, 366, 427, 51, 240, 224, - 290, -252, -251, -8190, 290, -8190, -8190, -8190, 194, 47, 21, 391, 201, 226, 296, 34, 260, 3, 177, 297, - 368, 235, 236, 367, 373, 298, 299, -250, 54, 362, 363, 361, -226, 246, 247, 248, -219, 48, 49, 17, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, -225, 360, 359, -219, -219, -219, -224, - -8190, -8190, -8190, 2, 4, -219, 5, 381, 372, 630, 362, 363, 361, 6, 8, 366, 9, -226, -8190, 10, - -8190, -8190, 29, 468, 470, 52, 23, 183, 194, 47, -218, 53, 201, -217, 296, 196, 189, 190, 239, 297, - 368, 235, 236, 367, 373, 298, 299, 275, 277, 372, -218, -218, -218, -217, -217, -217, 366, 101, 510, -218, - 553, 428, -217, 525, 531, 533, 535, 585, -29, 365, 364, -225, 259, 376, 505, 377, -8190, -8190, -8190, 330, - 369, 368, 371, 370, 367, 373, 374, 375, 360, 359, 334, -8190, -8190, -8190, -8190, 544, -8190, -8190, -8190, 511, - -8190, -8190, -8190, -8191, -8191, -8191, -8191, -8191, 610, 418, 104, 417, -8190, -8190, -8190, 638, 640, -29, 392, 552, - 639, 1, 521, 342, 637, 594, 250, 608, 582, 381, -8190, 353, 555, 598, 633, 347, 0, 556, 0, 290, - 0, 0, 0, 0, 288, 289, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 50, 0, 0, 0, 0, 0, 224, 290, + 35, 36, -8190, -8190, -8190, 37, 33, 38, 180, 181, 39, 40, 41, 42, 43, 44, 45, -50, 1, 194, + 46, 560, 561, 206, -8190, 542, 383, 383, 12, 558, 287, -48, 246, 247, -47, 525, 288, 289, -8190, -8190, + 569, 290, 291, 209, -8190, -8190, -8190, -78, 13, -78, 544, 543, 566, 564, 565, 55, 56, 57, -185, 198, + 30, -184, -8190, 99, -8190, -8190, -8190, 226, 292, 292, 197, -185, 0, 24, -184, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 1, + 196, 364, 365, 363, 254, 341, 420, 383, 419, 7, 558, 82, -8190, -8190, -8190, -8191, -8191, -8191, -8191, 73, + 74, 75, 76, 291, 383, 362, 361, 644, 14, 11, -8190, 645, -8190, -8190, -8190, -8190, -8190, -8190, 199, 374, + -8190, 50, 197, 420, -78, 419, 368, -223, 226, 292, -78, 15, -52, -78, 364, 365, 363, 22, 51, 195, + 47, 102, 540, 202, 542, 298, 292, -223, -223, -223, 299, 370, 236, 237, 369, 375, 300, 301, 362, 361, + 192, 418, -8190, -8190, -8190, -270, 16, -270, 25, 544, 543, 383, 374, 633, 381, 235, 382, 172, 385, 368, + -8190, 429, -8190, -8190, -8190, -8190, 173, 364, 365, 363, 23, 184, 195, 47, -224, 420, 202, 419, 298, -8190, + -268, 96, -268, 299, 370, 236, 237, 369, 375, 300, 301, 362, 361, 100, -224, -224, -224, -22, -47, 292, + 381, 26, 382, -184, 179, 374, 97, 77, 78, 79, 80, 81, 368, 196, 429, 106, -184, 74, 75, 76, + 364, 365, 363, 109, 82, 195, 47, 362, 361, 202, -220, 298, -8190, -8190, 107, -224, 299, 370, 236, 237, + 369, 375, 300, 301, 362, 361, 108, 449, -270, 31, -220, -220, -220, -270, 27, -224, -224, -224, 374, -220, + -266, 18, -266, 20, -184, 368, -23, 429, -17, 210, 211, 212, -227, 364, 365, 363, -16, -184, 195, 47, + -219, 196, 202, -268, 298, -8190, -8190, -8190, -268, 299, 370, 236, 237, 369, 375, 300, 301, 362, 361, 197, + -219, -219, -219, -8190, 82, -8190, -8190, 28, 19, -219, 98, 374, -8190, -8190, -8190, -8190, -8190, -8190, 368, 228, + 429, 105, -226, 193, 201, 103, 364, 365, 363, 324, -8190, 195, 47, -221, 104, 202, -218, 298, 646, 250, + 251, 252, 299, 370, 236, 237, 369, 375, 300, 301, 362, 361, 383, -221, -221, -221, -218, -218, -218, -8190, + 101, 172, -221, -266, 374, -218, 280, 208, -266, 347, 173, 368, 420, 429, 419, 34, 245, 3, 178, -193, + 570, -29, 571, -253, 195, 47, 277, 164, 202, 243, 298, 21, 393, -252, 559, 299, 370, 236, 237, 369, + 375, 300, 301, 555, 0, 364, 365, 363, -251, -227, -226, 32, -225, 48, 49, 17, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 362, 361, 213, 214, 215, 2, 4, 5, 6, 8, 9, + 244, 10, 29, 374, 52, 53, 364, 365, 363, 190, 368, 191, 242, 641, 585, 279, 513, 556, 471, 473, + 430, 528, 508, 195, 47, 534, 536, 202, -218, 298, 538, 588, -29, 332, 299, 370, 236, 237, 369, 375, + 300, 301, 336, 547, 374, 514, 613, 200, -218, -218, -218, 368, 101, 54, 263, 355, 643, -218, 394, 642, + 524, 344, 640, 597, 367, 366, 611, 601, 378, 0, 379, -8190, -8190, -8190, 636, 371, 370, 373, 372, 369, + 375, 376, 377, 362, 361, 349, 292, 0, 0, -8190, 0, -8190, -8190, -8190, -8190, -8190, -8190, -8191, -8191, -8191, + -8191, -8191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 254, 0, 0, 383, 0, 0, 558, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 290, + 291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, + 0, 0, 0, 0, 0, 226, 292, ]; /** Table indexed analogously to self::Action. If self::ActionCheck[self::ActionBase[$state] + $symbol] != $symbol * then the action is defaulted, i.e. self::ActionDefault[$state] should be used instead. */ protected const ActionCheck = [ - 43, 44, 0, 77, 2, 48, 0, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0, 61, 62, - 63, 64, 65, 66, 0, 68, 69, 61, 2, 72, 73, 105, 75, 76, 21, 0, 79, 80, 2, 0, - 61, 84, 85, 86, 66, 6, 68, 81, 82, 83, 93, 94, 95, 96, 97, 3, 4, 5, 71, 102, - 81, 82, 83, 85, 2, 108, 109, 2, 26, 90, 28, 93, 94, 21, 87, 23, 24, 25, 2, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 2, 49, 3, 4, 5, 103, 2, 69, 95, 107, 97, 2, 60, 3, 4, 5, 35, 36, 37, 38, - 39, 40, 41, 42, 3, 4, 5, 28, 29, 103, 66, 21, 68, 23, 24, 25, 2, 27, 28, 29, - 3, 42, 104, 0, 2, 2, 6, 109, 49, 28, 29, 43, 44, 45, 46, 47, 21, 49, 0, 26, - 2, 62, 63, 42, 22, 66, 44, 68, 60, 26, 49, 6, 73, 74, 75, 76, 77, 78, 79, 80, - 3, 4, 5, 62, 63, 3, 4, 66, 66, 68, 91, 6, 70, 61, 73, 74, 75, 76, 77, 78, - 79, 80, 103, 22, 6, 28, 29, 3, 4, 5, 43, 44, 91, 81, 82, 83, 3, 4, 5, 42, - 6, 0, 90, 2, 103, 21, 49, 23, 24, 25, 95, 27, 97, 3, 4, 5, 103, 90, 103, 62, - 63, 7, 61, 66, 102, 68, 103, 28, 29, 102, 73, 74, 75, 76, 77, 78, 79, 80, 28, 29, - 7, 103, 81, 82, 83, 107, 61, 7, 91, 61, 90, 90, 42, 66, 22, 68, 3, 4, 5, 49, - 103, 22, 102, 102, 22, 22, 81, 82, 83, 81, 82, 83, 62, 63, 26, 90, 66, 61, 68, 22, - 22, 28, 29, 73, 74, 75, 76, 77, 78, 79, 80, 104, 40, 41, 42, 42, 109, 81, 82, 83, - 22, 91, 49, 95, 103, 97, 90, 26, 107, 3, 4, 5, 61, 103, 28, 62, 63, 66, 102, 66, - 69, 68, 49, 72, 69, 60, 73, 74, 75, 76, 77, 78, 79, 80, 28, 29, 85, 61, 67, 69, - 85, 74, 70, 87, 91, 3, 4, 5, 42, 87, 71, 90, 78, 102, 90, 49, 103, 102, 90, 108, - 109, 102, 102, 21, 109, 23, 24, 25, 62, 63, 104, 91, 66, 61, 68, 98, 99, 100, 101, 73, - 74, 75, 76, 77, 78, 79, 80, 102, 104, 3, 4, 5, 102, 81, 82, 83, 61, 91, 92, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 102, 28, 29, 81, 82, 83, 102, - 3, 4, 5, 102, 102, 90, 102, 69, 42, 71, 3, 4, 5, 102, 102, 49, 102, 102, 21, 102, - 23, 24, 102, 51, 52, 102, 88, 89, 62, 63, 61, 102, 66, 61, 68, 21, 102, 102, 102, 73, - 74, 75, 76, 77, 78, 79, 80, 103, 103, 42, 81, 82, 83, 81, 82, 83, 49, 91, 103, 90, - 103, 103, 90, 103, 103, 103, 103, 103, 103, 62, 63, 102, 104, 66, 103, 68, 3, 4, 5, 103, - 73, 74, 75, 76, 77, 78, 79, 80, 28, 29, 103, 3, 4, 5, 21, 103, 23, 24, 25, 103, - 27, 28, 29, 30, 31, 32, 33, 34, 103, 95, 22, 97, 3, 4, 5, 105, 105, 103, 105, 107, - 105, 61, 105, 105, 105, 105, 66, 105, 107, 69, 21, 106, 72, 107, 107, 107, -1, 108, -1, 109, - -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 102, -1, -1, -1, -1, -1, 108, 109, + 42, 43, 3, 4, 5, 47, 76, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 0, 60, 61, + 62, 63, 64, 65, 70, 67, 68, 68, 2, 71, 72, 0, 74, 75, 0, 105, 78, 79, 3, 4, + 86, 83, 84, 85, 3, 4, 5, 0, 22, 2, 92, 93, 94, 95, 96, 3, 4, 5, 89, 27, + 102, 89, 21, 104, 23, 24, 25, 109, 110, 110, 21, 102, 0, 21, 102, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 60, + 48, 3, 4, 5, 65, 43, 94, 68, 96, 2, 71, 59, 3, 4, 5, 34, 35, 36, 37, 38, + 39, 40, 41, 84, 68, 27, 28, 65, 102, 2, 21, 69, 23, 24, 25, 26, 27, 28, 106, 41, + 84, 102, 21, 94, 97, 96, 48, 60, 109, 110, 103, 2, 103, 106, 3, 4, 5, 2, 102, 61, + 62, 2, 65, 65, 67, 67, 110, 80, 81, 82, 72, 73, 74, 75, 76, 77, 78, 79, 27, 28, + 2, 84, 3, 4, 5, 0, 2, 2, 90, 92, 93, 68, 41, 70, 65, 2, 67, 97, 2, 48, + 21, 103, 23, 24, 25, 26, 106, 3, 4, 5, 87, 88, 61, 62, 60, 94, 65, 96, 67, 3, + 0, 7, 2, 72, 73, 74, 75, 76, 77, 78, 79, 27, 28, 104, 80, 81, 82, 22, 0, 110, + 65, 90, 67, 89, 6, 41, 7, 42, 43, 44, 45, 46, 48, 48, 103, 6, 102, 39, 40, 41, + 3, 4, 5, 7, 59, 61, 62, 27, 28, 65, 60, 67, 42, 43, 6, 60, 72, 73, 74, 75, + 76, 77, 78, 79, 27, 28, 6, 103, 103, 60, 80, 81, 82, 108, 90, 80, 81, 82, 41, 89, + 0, 6, 2, 6, 89, 48, 22, 103, 22, 80, 81, 82, 102, 3, 4, 5, 22, 102, 61, 62, + 60, 48, 65, 103, 67, 3, 4, 5, 108, 72, 73, 74, 75, 76, 77, 78, 79, 27, 28, 21, + 80, 81, 82, 21, 59, 23, 24, 90, 22, 89, 22, 41, 3, 4, 5, 3, 4, 5, 48, 60, + 103, 22, 102, 22, 27, 60, 3, 4, 5, 66, 21, 61, 62, 60, 22, 65, 60, 67, 69, 80, + 81, 82, 72, 73, 74, 75, 76, 77, 78, 79, 27, 28, 68, 80, 81, 82, 80, 81, 82, 70, + 90, 97, 89, 103, 41, 89, 73, 103, 108, 77, 106, 48, 94, 103, 96, 98, 99, 100, 101, 89, + 86, 103, 86, 102, 61, 62, 103, 89, 65, 89, 67, 104, 90, 102, 109, 72, 73, 74, 75, 76, + 77, 78, 79, 108, -1, 3, 4, 5, 102, 102, 102, 60, 102, 90, 91, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 27, 28, 80, 81, 82, 102, 102, 102, 102, 102, 102, + 89, 102, 102, 41, 102, 102, 3, 4, 5, 102, 48, 102, 102, 105, 108, 103, 103, 103, 50, 51, + 103, 103, 103, 61, 62, 103, 103, 65, 60, 67, 103, 103, 103, 103, 72, 73, 74, 75, 76, 77, + 78, 79, 103, 103, 41, 103, 103, 106, 80, 81, 82, 48, 90, 104, 104, 107, 105, 89, 105, 105, + 105, 105, 105, 105, 61, 62, 105, 108, 65, -1, 67, 3, 4, 5, 108, 72, 73, 74, 75, 76, + 77, 78, 79, 27, 28, 108, 110, -1, -1, 21, -1, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60, -1, -1, -1, + -1, 65, -1, -1, 68, -1, -1, 71, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 83, + 84, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, -1, + -1, -1, -1, -1, -1, 109, 110, ]; /** Map of states to their default action */ protected const ActionDefault = [ - 8191, 263, 263, 31, 263, 8191, 8191, 263, 8191, 8191, 8191, 29, 8191, 8191, 8191, 29, 8191, 8191, 8191, 8191, - 8191, 39, 29, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 215, 215, 215, 8191, 8191, 8191, 8191, 8191, 8191, + 8191, 264, 264, 31, 264, 8191, 8191, 264, 8191, 8191, 8191, 29, 8191, 8191, 8191, 29, 8191, 8191, 8191, 8191, + 8191, 39, 29, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 216, 216, 216, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 10, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, - 8191, 8191, 29, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 264, 264, 8191, 8191, 8191, 8191, 8191, 8191, 8191, - 8191, 8191, 1, 270, 271, 83, 77, 216, 266, 268, 79, 82, 80, 43, 44, 56, 120, 122, 154, 121, - 96, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 94, 95, 166, 155, 153, 152, - 118, 119, 125, 93, 8191, 123, 124, 142, 143, 140, 141, 144, 8191, 145, 146, 147, 148, 8191, 8191, 8191, - 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 126, 69, 69, 69, 8191, 8191, 11, 8191, 8191, 8191, 8191, 8191, - 8191, 206, 132, 133, 135, 206, 205, 150, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 211, 115, 117, - 189, 127, 128, 97, 8191, 8191, 8191, 210, 8191, 278, 217, 217, 217, 217, 34, 34, 34, 8191, 89, 34, - 8191, 8191, 34, 34, 34, 8191, 8191, 8191, 8191, 195, 223, 217, 138, 8191, 129, 130, 131, 57, 8191, 8191, - 8191, 193, 182, 8191, 2, 28, 28, 28, 8191, 236, 237, 238, 28, 28, 28, 170, 36, 71, 28, 28, - 71, 8191, 8191, 28, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 200, 8191, 221, 234, 185, 15, 20, 21, - 8191, 200, 219, 136, 137, 139, 158, 159, 160, 161, 162, 163, 164, 261, 8191, 257, 188, 8191, 8191, 217, - 8191, 8191, 277, 8191, 217, 134, 8191, 196, 241, 8191, 218, 217, 262, 8191, 8191, 8191, 59, 60, 8191, 8191, - 8191, 8191, 197, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 55, 8191, 8191, 8191, + 8191, 8191, 29, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 265, 265, 8191, 8191, 8191, 8191, 8191, 8191, 8191, + 8191, 8191, 1, 271, 272, 83, 77, 217, 267, 269, 79, 82, 80, 43, 44, 56, 121, 123, 155, 122, + 97, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 95, 96, 167, 156, 154, 153, + 119, 120, 126, 94, 8191, 124, 125, 143, 144, 141, 142, 145, 8191, 8191, 146, 147, 148, 149, 8191, 8191, + 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 127, 69, 69, 69, 8191, 8191, 11, 8191, 8191, 8191, 8191, + 8191, 8191, 207, 133, 134, 136, 207, 206, 151, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 212, 116, + 118, 190, 128, 129, 98, 218, 8191, 8191, 8191, 211, 8191, 279, 218, 218, 218, 34, 34, 34, 8191, 8191, + 90, 90, 34, 8191, 8191, 8191, 34, 34, 34, 2, 8191, 8191, 8191, 196, 224, 218, 139, 8191, 130, 131, + 132, 57, 8191, 8191, 194, 183, 8191, 28, 28, 28, 8191, 237, 238, 239, 28, 28, 28, 171, 36, 71, + 28, 28, 71, 8191, 8191, 28, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 201, 8191, 222, 235, 186, 15, + 20, 21, 8191, 201, 220, 137, 138, 140, 159, 160, 161, 162, 163, 164, 165, 262, 8191, 258, 189, 8191, + 8191, 218, 8191, 8191, 278, 8191, 218, 135, 8191, 197, 242, 8191, 219, 218, 263, 8191, 8191, 8191, 59, 60, + 8191, 8191, 8191, 8191, 198, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 55, 8191, 8191, 8191, ]; /** Map of non-terminals to a displacement into the self::Goto table. The corresponding goto state for this * non-terminal/state pair is self::Goto[self::GotoBase[$nonTerminal] + $state] (unless defaulted) */ protected const GotoBase = [ - 0, 0, -1, 0, 0, 0, 108, 0, 226, -12, 16, -28, 0, 249, -231, 0, 0, 0, 0, 225, - 219, 71, -13, 255, -2, 64, 0, 67, 0, 69, -76, 0, 0, -60, -6, 1, -5, 171, 0, 0, - 23, 0, 0, 72, 0, 0, -18, 0, 0, 0, 34, 0, 0, 0, 0, -77, -44, 0, 0, 14, - 25, 112, 36, 42, -67, 0, 0, -51, 66, 0, -15, 184, 236, 57, 0, 0, + 0, 0, -1, 0, 0, 0, 108, 0, 226, 28, 22, -34, 0, 278, 20, 0, 0, 0, 0, 120, + 203, 57, -13, 251, -2, 52, 0, 53, 0, 61, -77, 0, 0, -61, 6, -258, 104, -11, 0, 0, + 25, 24, 0, 63, 0, 0, 250, 0, 0, 0, 30, 0, 0, 0, 0, 81, -44, 0, 0, 16, + 27, 7, 38, 37, -68, 0, 0, -51, -24, 0, 41, 110, 4, 35, 0, 0, ]; /** Table of states to goto after reduction. Indexed according to self::GotoBase comment. */ protected const Goto = [ - 112, 112, 111, 112, 317, 318, 112, 273, 274, 258, 111, 317, 318, 276, 333, 352, 140, 128, 129, 128, - 125, 125, 117, 138, 130, 130, 130, 130, 125, 110, 127, 127, 127, 122, 303, 304, 252, 305, 306, 307, - 308, 309, 310, 311, 312, 454, 454, 123, 124, 113, 114, 115, 116, 118, 136, 137, 139, 157, 160, 161, - 162, 165, 166, 167, 168, 169, 170, 171, 173, 174, 175, 176, 188, 202, 203, 204, 221, 222, 254, 255, - 256, 325, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 158, 119, 120, - 130, 131, 121, 159, 132, 133, 156, 134, 135, 181, 181, 181, 181, 328, 321, 181, 316, 316, 316, 181, - 412, 419, 421, 420, 422, 184, 186, 187, 186, 415, 415, 415, 415, 536, 536, 536, 415, 415, 415, 415, - 415, 225, 597, 597, 597, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 237, 609, 609, - 609, 609, 609, 609, 251, 331, 218, 219, 230, 319, 324, 223, 231, 232, 233, 301, 301, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 430, 430, 253, 595, 595, 576, 576, 576, 576, 576, 576, 576, 576, 576, - 576, 576, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 302, 302, 302, 302, 302, 302, 302, - 302, 302, 302, 302, 229, 602, 603, 300, 300, 300, 300, 229, 229, 300, 634, 635, 636, 300, 435, 341, - 229, 229, 644, 612, 405, 445, 444, 396, 320, 400, 348, 394, 386, 229, 338, 526, 313, 313, 408, 313, - 387, 426, 313, 530, 532, 628, 216, 503, 439, 534, 584, 586, 587, 527, 349, 332, 270, 271, 599, 600, - 601, 628, 629, 440, 0, 182, 182, 441, 0, 0, 0, 0, 0, 0, 629, 0, 0, 350, 529, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 112, 112, 111, 112, 432, 432, 112, 533, 535, 323, 111, 615, 537, 587, 589, 590, 140, 128, 129, 128, + 125, 125, 117, 138, 130, 130, 130, 130, 125, 110, 127, 127, 127, 122, 305, 306, 256, 307, 308, 309, + 310, 311, 312, 313, 314, 457, 457, 123, 124, 113, 114, 115, 116, 118, 136, 137, 139, 157, 160, 161, + 162, 165, 166, 167, 168, 169, 170, 171, 174, 175, 176, 177, 189, 203, 204, 205, 222, 223, 258, 259, + 260, 327, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 158, 119, 120, + 130, 131, 121, 159, 132, 133, 156, 134, 135, 182, 182, 182, 182, 330, 257, 182, 275, 276, 262, 182, + 414, 423, 421, 422, 424, 185, 187, 188, 187, 417, 417, 417, 417, 539, 539, 539, 417, 417, 417, 417, + 417, 227, 398, 600, 600, 600, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 238, 612, + 612, 612, 612, 612, 612, 255, 333, 219, 220, 232, 321, 326, 224, 225, 233, 234, 303, 303, 557, 557, + 557, 557, 557, 557, 557, 557, 557, 272, 273, 602, 603, 604, 598, 598, 579, 579, 579, 579, 579, 579, + 579, 579, 579, 579, 579, 577, 577, 577, 577, 577, 577, 577, 577, 577, 577, 577, 304, 304, 304, 304, + 304, 304, 304, 304, 304, 304, 304, 302, 302, 302, 302, 231, 322, 302, 437, 343, 402, 302, 231, 231, + 407, 448, 447, 340, 631, 410, 350, 396, 231, 231, 647, 529, 315, 315, 428, 315, 319, 320, 315, 506, + 231, 631, 632, 217, 441, 444, 319, 320, 278, 0, 442, 334, 530, 632, 443, 318, 318, 318, 637, 638, + 639, 388, 335, 354, 605, 606, 183, 183, 351, 389, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 352, 532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 389, 389, 389, 0, 0, 389, 0, 0, 389, 389, 389, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 391, 391, 391, 0, 0, 0, 0, 391, 0, 0, 0, 391, 391, 391, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 327, 0, 0, 0, 0, 0, 0, 0, 238, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 329, 0, 0, 0, 0, 0, 0, 0, 240, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 403, 403, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 405, 405, ]; /** Table indexed analogously to self::Goto. If self::GotoCheck[self::GotoBase[$nonTerminal] + $state] != $nonTerminal * then the goto state is defaulted, i.e. self::GotoDefault[$nonTerminal] should be used. */ protected const GotoCheck = [ - 2, 2, 2, 2, 14, 14, 2, 36, 36, 36, 2, 14, 14, 14, 46, 46, 2, 2, 2, 2, + 2, 2, 2, 2, 37, 37, 2, 35, 35, 61, 2, 72, 35, 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 67, 61, 6, 55, 55, 55, 6, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 67, 71, 6, 36, 36, 36, 6, 30, 30, 30, 30, 30, 6, 6, 6, 6, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, - 33, 64, 67, 67, 67, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 64, 67, 67, - 67, 67, 67, 67, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 37, 37, 71, 67, 67, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 10, 70, 70, 8, 8, 8, 8, 10, 10, 8, 9, 9, 9, 8, 11, 11, - 10, 10, 10, 72, 11, 11, 11, 19, 20, 21, 11, 11, 13, 10, 25, 11, 23, 23, 27, 23, - 13, 29, 23, 35, 35, 73, 63, 43, 40, 35, 35, 35, 35, 50, 34, 23, 68, 68, 68, 68, - 68, 73, 73, 40, -1, 6, 6, 40, -1, -1, -1, -1, -1, -1, 73, -1, -1, 10, 10, -1, + 33, 64, 19, 67, 67, 67, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 64, 67, + 67, 67, 67, 67, 67, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 68, 68, 68, 68, 68, 67, 67, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 8, 8, 8, 8, 10, 20, 8, 11, 11, 21, 8, 10, 10, + 11, 11, 11, 25, 73, 27, 11, 11, 10, 10, 10, 11, 23, 23, 29, 23, 14, 14, 23, 43, + 10, 73, 73, 63, 40, 41, 14, 14, 14, -1, 40, 23, 50, 73, 40, 55, 55, 55, 9, 9, + 9, 13, 46, 46, 70, 70, 6, 6, 34, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 10, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 6, 6, 6, -1, -1, -1, -1, 6, -1, -1, -1, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 6, 6, 6, -1, -1, 6, -1, -1, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1, 8, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 23, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 23, ]; /** Map of non-terminals to the default state to goto after their reduction */ protected const GotoDefault = [ - -8192, 284, 126, 264, 357, 358, 185, 378, 326, 607, 593, 384, 265, 614, 282, 281, 453, 343, 279, 395, - 344, 399, 163, 291, 292, 335, 272, 407, 244, 424, 257, 336, 337, 262, 346, 548, 267, 429, 266, 245, - 438, 442, 452, 261, 519, 280, 329, 523, 351, 283, 528, 583, 263, 293, 268, 545, 249, 220, 294, 227, - 217, 314, 206, 215, 627, 228, 295, 581, 269, 589, 596, 315, 613, 626, 323, 340, + -8192, 286, 126, 249, 359, 360, 186, 380, 328, 610, 596, 386, 267, 617, 284, 283, 456, 345, 281, 397, + 346, 401, 163, 293, 294, 337, 274, 409, 248, 426, 261, 338, 339, 265, 348, 551, 269, 431, 268, 239, + 440, 445, 455, 264, 522, 282, 331, 526, 353, 285, 531, 586, 266, 295, 270, 548, 253, 221, 296, 229, + 218, 316, 207, 216, 630, 230, 297, 584, 271, 592, 599, 317, 616, 629, 325, 342, ]; /** Map of rules to the non-terminal on their left-hand side, i.e. the non-terminal to use for @@ -259,17 +263,17 @@ abstract class TagParserData 7, 7, 8, 8, 8, 9, 9, 10, 11, 11, 4, 4, 12, 12, 14, 14, 15, 15, 16, 17, 17, 18, 18, 19, 19, 5, 5, 21, 21, 21, 21, 25, 25, 26, 26, 27, 27, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 32, 32, 28, 28, 34, 34, 35, 35, 36, 36, 37, 37, 37, - 37, 20, 38, 38, 39, 39, 3, 3, 40, 41, 41, 41, 41, 2, 2, 2, 2, 2, 2, 2, + 37, 20, 38, 38, 39, 39, 3, 3, 40, 40, 41, 41, 41, 41, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 42, 45, 45, 48, 49, 49, 50, 51, 51, 51, 51, - 51, 51, 55, 33, 33, 56, 56, 56, 43, 43, 43, 53, 53, 47, 47, 59, 60, 60, 24, 62, - 62, 62, 62, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 46, 46, 58, 58, 58, - 58, 65, 65, 65, 52, 52, 52, 66, 66, 66, 66, 66, 66, 66, 22, 22, 22, 22, 22, 67, - 67, 70, 69, 57, 57, 57, 57, 57, 57, 57, 54, 54, 54, 68, 68, 68, 23, 61, 71, 71, - 72, 72, 72, 72, 13, 13, 13, 13, 13, 13, 13, 13, 63, 63, 63, 63, 64, 74, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 75, 75, 75, 75, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 42, 45, 45, 48, 49, 49, 50, 51, 51, 51, + 51, 51, 51, 55, 33, 33, 56, 56, 56, 43, 43, 43, 53, 53, 47, 47, 59, 60, 60, 24, + 62, 62, 62, 62, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 46, 46, 58, 58, + 58, 58, 65, 65, 65, 52, 52, 52, 66, 66, 66, 66, 66, 66, 66, 22, 22, 22, 22, 22, + 67, 67, 70, 69, 57, 57, 57, 57, 57, 57, 57, 54, 54, 54, 68, 68, 68, 23, 61, 71, + 71, 72, 72, 72, 72, 13, 13, 13, 13, 13, 13, 13, 13, 63, 63, 63, 63, 64, 74, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 75, 75, 75, 75, ]; /** Map of rules to the length of their right-hand side, which is the number of elements that have to @@ -279,17 +283,17 @@ abstract class TagParserData 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 2, 0, 1, 3, 0, 1, 0, 1, 7, 0, 2, 1, 3, 3, 4, 1, 3, 1, 2, 1, 1, 2, 0, 1, 3, 4, 6, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 0, 1, 0, 2, 2, 4, 1, 3, 1, 2, 2, - 3, 2, 3, 1, 2, 2, 1, 2, 3, 0, 3, 3, 3, 1, 3, 3, 3, 4, 1, 1, - 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 3, 3, 4, 4, 2, 2, - 2, 2, 2, 2, 2, 1, 8, 12, 9, 3, 0, 4, 2, 1, 3, 2, 2, 4, 2, 4, - 4, 6, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 0, 1, 1, 3, 5, 3, 4, - 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 3, 0, 1, 1, 3, 1, - 1, 1, 1, 1, 1, 3, 1, 1, 4, 1, 4, 6, 4, 4, 1, 1, 3, 3, 3, 1, - 4, 1, 3, 1, 4, 3, 3, 3, 3, 3, 1, 3, 1, 1, 3, 1, 4, 1, 3, 1, - 1, 1, 3, 0, 1, 2, 3, 4, 3, 4, 2, 2, 2, 2, 1, 2, 1, 1, 1, 4, - 3, 3, 3, 3, 3, 6, 3, 1, 1, 2, 1, + 3, 2, 3, 1, 2, 2, 1, 2, 3, 3, 0, 3, 3, 3, 1, 3, 3, 3, 4, 1, + 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 3, 3, 4, 4, 2, + 2, 2, 2, 2, 2, 2, 1, 8, 12, 9, 3, 0, 4, 2, 1, 3, 2, 2, 4, 2, + 4, 4, 6, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 0, 1, 1, 3, 5, 3, + 4, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 3, 0, 1, 1, 3, + 1, 1, 1, 1, 1, 1, 3, 1, 1, 4, 1, 4, 6, 4, 4, 1, 1, 3, 3, 3, + 1, 4, 1, 3, 1, 4, 3, 3, 3, 3, 3, 1, 3, 1, 1, 3, 1, 4, 1, 3, + 1, 1, 1, 3, 0, 1, 2, 3, 4, 3, 4, 2, 2, 2, 2, 1, 2, 1, 1, 1, + 4, 3, 3, 3, 3, 3, 6, 3, 1, 1, 2, 1, ]; /** Map of symbols to their names */ @@ -320,7 +324,6 @@ abstract class TagParserData "'??'", "'||'", "'&&'", - "'|'", "'^'", "'&'", "'&'", @@ -392,6 +395,7 @@ abstract class TagParserData "'null'", "'true'", "'false'", + "'?|'", "'e'", "'m'", "'a'", @@ -400,6 +404,7 @@ abstract class TagParserData "')'", "'{'", "'}'", + "'|'", "';'", "']'", "'\"'", @@ -422,15 +427,15 @@ abstract class TagParserData protected function reduce(int $rule, int $pos): void { (match ($rule) { - 0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 28, 29, 57, 70, 72, 93, 98, 99, 165, 182, 184, 188, 189, 191, 192, 194, 205, 210, 211, 216, 217, 219, 220, 221, 222, 224, 226, 227, 229, 234, 235, 239, 243, 250, 252, 253, 255, 260, 278, 290 => fn() => $this->semValue = $this->semStack[$pos], + 0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 28, 29, 57, 70, 72, 94, 99, 100, 166, 183, 185, 189, 190, 192, 193, 195, 206, 211, 212, 217, 218, 220, 221, 222, 223, 225, 227, 228, 230, 235, 236, 240, 244, 251, 253, 254, 256, 261, 279, 291 => fn() => $this->semValue = $this->semStack[$pos], 2 => fn() => $this->semValue = new Node\ModifierNode($this->semStack[$pos], position: $this->startTokenStack[$pos]->position), 3 => fn() => $this->semValue = new Expression\ArrayNode($this->semStack[$pos], position: $this->startTokenStack[$pos]->position), 22, 23, 24, 25, 26, 62, 63, 64 => fn() => $this->semValue = new Node\IdentifierNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), 27 => fn() => $this->semValue = new Expression\VariableNode(substr($this->semStack[$pos], 1), $this->startTokenStack[$pos]->position), - 30, 40, 51, 81, 90, 91, 92, 150, 151, 171, 172, 190, 218, 225, 251, 254, 286 => fn() => $this->semValue = $this->semStack[$pos - 1], - 31, 39, 52, 73, 89, 170, 193 => fn() => $this->semValue = [], - 32, 41, 53, 75, 83, 86, 173, 259, 274 => fn() => $this->semValue = [$this->semStack[$pos]], - 33, 42, 54, 66, 68, 76, 82, 174, 258 => function () use ($pos) { + 30, 40, 51, 81, 91, 92, 93, 151, 152, 172, 173, 191, 219, 226, 252, 255, 287 => fn() => $this->semValue = $this->semStack[$pos - 1], + 31, 39, 52, 73, 90, 171, 194 => fn() => $this->semValue = [], + 32, 41, 53, 75, 83, 86, 174, 260, 275 => fn() => $this->semValue = [$this->semStack[$pos]], + 33, 42, 54, 66, 68, 76, 82, 175, 259 => function () use ($pos) { $this->semStack[$pos - 2][] = $this->semStack[$pos]; $this->semValue = $this->semStack[$pos - 2]; }, @@ -451,133 +456,134 @@ protected function reduce(int $rule, int $pos): void 60 => fn() => $this->semValue = new Node\IntersectionTypeNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), 61 => fn() => $this->semValue = TagParser::handleBuiltinTypes($this->semStack[$pos]), 65, 67 => fn() => $this->semValue = [$this->semStack[$pos - 2], $this->semStack[$pos]], - 69, 71, 215 => fn() => $this->semValue = null, + 69, 71, 216 => fn() => $this->semValue = null, 74 => fn() => $this->semValue = $this->semStack[$pos - 2], 77 => fn() => $this->semValue = new Node\ArgumentNode($this->semStack[$pos], false, false, null, $this->startTokenStack[$pos]->position), 78 => fn() => $this->semValue = new Node\ArgumentNode($this->semStack[$pos], true, false, null, $this->startTokenStack[$pos - 1]->position), 79 => fn() => $this->semValue = new Node\ArgumentNode($this->semStack[$pos], false, true, null, $this->startTokenStack[$pos - 1]->position), 80 => fn() => $this->semValue = new Node\ArgumentNode($this->semStack[$pos], false, false, $this->semStack[$pos - 2], $this->startTokenStack[$pos - 2]->position), 84, 85 => fn() => $this->semValue = new Expression\FilterCallNode($this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 87, 272, 273 => function () use ($pos) { + 87, 273, 274 => function () use ($pos) { $this->semStack[$pos - 1][] = $this->semStack[$pos]; $this->semValue = $this->semStack[$pos - 1]; }, - 88 => fn() => $this->semValue = new Node\FilterNode($this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 94, 96 => fn() => $this->semValue = new Expression\AssignNode($this->semStack[$pos - 2], $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), - 95 => fn() => $this->semValue = new Expression\AssignNode($this->convertArrayToList($this->semStack[$pos - 2]), $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), - 97 => fn() => $this->semValue = new Expression\AssignNode($this->semStack[$pos - 3], $this->semStack[$pos], true, $this->startTokenStack[$pos - 3]->position), - 100 => fn() => $this->semValue = new Expression\CloneNode($this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 101 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '+', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 102 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '-', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 103 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '*', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 104 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '/', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 105 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '.', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 106 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '%', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 107 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '&', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 108 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '|', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 109 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '^', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 110 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '<<', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 111 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '>>', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 112 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '**', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 113 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '??', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 114 => fn() => $this->semValue = new Expression\PostOpNode($this->semStack[$pos - 1], '++', $this->startTokenStack[$pos - 1]->position), - 115 => fn() => $this->semValue = new Expression\PreOpNode($this->semStack[$pos], '++', $this->startTokenStack[$pos - 1]->position), - 116 => fn() => $this->semValue = new Expression\PostOpNode($this->semStack[$pos - 1], '--', $this->startTokenStack[$pos - 1]->position), - 117 => fn() => $this->semValue = new Expression\PreOpNode($this->semStack[$pos], '--', $this->startTokenStack[$pos - 1]->position), - 118 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '||', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 119 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '&&', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 120 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], 'or', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 121 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], 'and', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 122 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], 'xor', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 123, 124 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '&', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 125 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '^', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 126 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '.', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 127 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '+', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 128 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '-', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 129 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '*', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 130 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '/', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 131 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '%', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 132 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '<<', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 133 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '>>', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 134 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '**', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 135 => fn() => $this->semValue = new Expression\InNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 136 => fn() => $this->semValue = new Expression\UnaryOpNode($this->semStack[$pos], '+', $this->startTokenStack[$pos - 1]->position), - 137 => fn() => $this->semValue = new Expression\UnaryOpNode($this->semStack[$pos], '-', $this->startTokenStack[$pos - 1]->position), - 138 => fn() => $this->semValue = new Expression\NotNode($this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 139 => fn() => $this->semValue = new Expression\UnaryOpNode($this->semStack[$pos], '~', $this->startTokenStack[$pos - 1]->position), - 140 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '===', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 141 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '!==', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 142 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '==', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 143 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '!=', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 144 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '<=>', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 145 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '<', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 146 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '<=', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 147 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '>', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 148 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '>=', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 149 => fn() => $this->semValue = new Expression\InstanceofNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 152 => fn() => $this->semValue = new Expression\TernaryNode($this->semStack[$pos - 4], $this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 4]->position), - 153 => fn() => $this->semValue = new Expression\TernaryNode($this->semStack[$pos - 3], null, $this->semStack[$pos], $this->startTokenStack[$pos - 3]->position), - 154 => fn() => $this->semValue = new Expression\TernaryNode($this->semStack[$pos - 2], $this->semStack[$pos], null, $this->startTokenStack[$pos - 2]->position), - 155 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '??', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 156 => fn() => $this->semValue = new Expression\IssetNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), - 157 => fn() => $this->semValue = new Expression\EmptyNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), - 158 => fn() => $this->semValue = new Expression\CastNode('int', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 159 => fn() => $this->semValue = new Expression\CastNode('float', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 160 => fn() => $this->semValue = new Expression\CastNode('string', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 161 => fn() => $this->semValue = new Expression\CastNode('array', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 162 => fn() => $this->semValue = new Expression\CastNode('object', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 163 => fn() => $this->semValue = new Expression\CastNode('bool', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 164 => fn() => $this->semValue = new Expression\ErrorSuppressNode($this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 166 => fn() => $this->semValue = new Expression\ClosureNode((bool) $this->semStack[$pos - 6], $this->semStack[$pos - 4], [], $this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 7]->position), - 167 => fn() => $this->semValue = new Expression\ClosureNode((bool) $this->semStack[$pos - 10], $this->semStack[$pos - 8], $this->semStack[$pos - 6], $this->semStack[$pos - 5], $this->semStack[$pos - 2], $this->startTokenStack[$pos - 11]->position), - 168 => fn() => $this->semValue = new Expression\ClosureNode((bool) $this->semStack[$pos - 7], $this->semStack[$pos - 5], $this->semStack[$pos - 3], $this->semStack[$pos - 2], null, $this->startTokenStack[$pos - 8]->position), - 169 => fn() => $this->semValue = new Expression\NewNode($this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 175 => fn() => $this->semValue = new Node\ClosureUseNode($this->semStack[$pos], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 1]->position), - 176, 178 => fn() => $this->semValue = $this->checkFunctionName(new Expression\FunctionCallNode($this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position)), - 177, 179 => fn() => $this->semValue = $this->checkFunctionName(new Expression\FunctionCallableNode($this->semStack[$pos - 3], $this->startTokenStack[$pos - 3]->position)), - 180 => fn() => $this->semValue = new Expression\StaticMethodCallNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 3]->position), - 181 => fn() => $this->semValue = new Expression\StaticMethodCallableNode($this->semStack[$pos - 5], $this->semStack[$pos - 3], $this->startTokenStack[$pos - 5]->position), - 183, 185, 186 => fn() => $this->semValue = new Node\NameNode($this->semStack[$pos], Node\NameNode::KindNormal, $this->startTokenStack[$pos]->position), - 187 => fn() => $this->semValue = new Node\NameNode($this->semStack[$pos], Node\NameNode::KindFullyQualified, $this->startTokenStack[$pos]->position), - 195 => fn() => $this->semValue = new Expression\ConstantFetchNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 196 => fn() => $this->semValue = new Expression\ClassConstantFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 197 => fn() => $this->semValue = new Expression\ClassConstantFetchNode($this->semStack[$pos - 4], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 4]->position), - 198 => fn() => $this->semValue = new Expression\ArrayNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 2]->position), - 199 => fn() => $this->semValue = new Expression\ArrayNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), - 200 => function () use ($pos) { + 88 => fn() => $this->semValue = new Node\FilterNode($this->semStack[$pos - 1], $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), + 89 => fn() => $this->semValue = new Node\FilterNode($this->semStack[$pos - 1], $this->semStack[$pos], true, $this->startTokenStack[$pos - 2]->position), + 95, 97 => fn() => $this->semValue = new Expression\AssignNode($this->semStack[$pos - 2], $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), + 96 => fn() => $this->semValue = new Expression\AssignNode($this->convertArrayToList($this->semStack[$pos - 2]), $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), + 98 => fn() => $this->semValue = new Expression\AssignNode($this->semStack[$pos - 3], $this->semStack[$pos], true, $this->startTokenStack[$pos - 3]->position), + 101 => fn() => $this->semValue = new Expression\CloneNode($this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 102 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '+', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 103 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '-', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 104 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '*', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 105 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '/', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 106 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '.', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 107 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '%', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 108 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '&', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 109 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '|', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 110 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '^', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 111 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '<<', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 112 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '>>', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 113 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '**', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 114 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '??', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 115 => fn() => $this->semValue = new Expression\PostOpNode($this->semStack[$pos - 1], '++', $this->startTokenStack[$pos - 1]->position), + 116 => fn() => $this->semValue = new Expression\PreOpNode($this->semStack[$pos], '++', $this->startTokenStack[$pos - 1]->position), + 117 => fn() => $this->semValue = new Expression\PostOpNode($this->semStack[$pos - 1], '--', $this->startTokenStack[$pos - 1]->position), + 118 => fn() => $this->semValue = new Expression\PreOpNode($this->semStack[$pos], '--', $this->startTokenStack[$pos - 1]->position), + 119 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '||', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 120 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '&&', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 121 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], 'or', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 122 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], 'and', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 123 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], 'xor', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 124, 125 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '&', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 126 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '^', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 127 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '.', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 128 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '+', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 129 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '-', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 130 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '*', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 131 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '/', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 132 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '%', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 133 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '<<', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 134 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '>>', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 135 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '**', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 136 => fn() => $this->semValue = new Expression\InNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 137 => fn() => $this->semValue = new Expression\UnaryOpNode($this->semStack[$pos], '+', $this->startTokenStack[$pos - 1]->position), + 138 => fn() => $this->semValue = new Expression\UnaryOpNode($this->semStack[$pos], '-', $this->startTokenStack[$pos - 1]->position), + 139 => fn() => $this->semValue = new Expression\NotNode($this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 140 => fn() => $this->semValue = new Expression\UnaryOpNode($this->semStack[$pos], '~', $this->startTokenStack[$pos - 1]->position), + 141 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '===', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 142 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '!==', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 143 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '==', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 144 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '!=', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 145 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '<=>', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 146 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '<', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 147 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '<=', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 148 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '>', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 149 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '>=', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 150 => fn() => $this->semValue = new Expression\InstanceofNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 153 => fn() => $this->semValue = new Expression\TernaryNode($this->semStack[$pos - 4], $this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 4]->position), + 154 => fn() => $this->semValue = new Expression\TernaryNode($this->semStack[$pos - 3], null, $this->semStack[$pos], $this->startTokenStack[$pos - 3]->position), + 155 => fn() => $this->semValue = new Expression\TernaryNode($this->semStack[$pos - 2], $this->semStack[$pos], null, $this->startTokenStack[$pos - 2]->position), + 156 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '??', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 157 => fn() => $this->semValue = new Expression\IssetNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), + 158 => fn() => $this->semValue = new Expression\EmptyNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), + 159 => fn() => $this->semValue = new Expression\CastNode('int', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 160 => fn() => $this->semValue = new Expression\CastNode('float', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 161 => fn() => $this->semValue = new Expression\CastNode('string', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 162 => fn() => $this->semValue = new Expression\CastNode('array', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 163 => fn() => $this->semValue = new Expression\CastNode('object', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 164 => fn() => $this->semValue = new Expression\CastNode('bool', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 165 => fn() => $this->semValue = new Expression\ErrorSuppressNode($this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 167 => fn() => $this->semValue = new Expression\ClosureNode((bool) $this->semStack[$pos - 6], $this->semStack[$pos - 4], [], $this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 7]->position), + 168 => fn() => $this->semValue = new Expression\ClosureNode((bool) $this->semStack[$pos - 10], $this->semStack[$pos - 8], $this->semStack[$pos - 6], $this->semStack[$pos - 5], $this->semStack[$pos - 2], $this->startTokenStack[$pos - 11]->position), + 169 => fn() => $this->semValue = new Expression\ClosureNode((bool) $this->semStack[$pos - 7], $this->semStack[$pos - 5], $this->semStack[$pos - 3], $this->semStack[$pos - 2], null, $this->startTokenStack[$pos - 8]->position), + 170 => fn() => $this->semValue = new Expression\NewNode($this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 176 => fn() => $this->semValue = new Node\ClosureUseNode($this->semStack[$pos], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 1]->position), + 177, 179 => fn() => $this->semValue = $this->checkFunctionName(new Expression\FunctionCallNode($this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position)), + 178, 180 => fn() => $this->semValue = $this->checkFunctionName(new Expression\FunctionCallableNode($this->semStack[$pos - 3], $this->startTokenStack[$pos - 3]->position)), + 181 => fn() => $this->semValue = new Expression\StaticMethodCallNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 3]->position), + 182 => fn() => $this->semValue = new Expression\StaticMethodCallableNode($this->semStack[$pos - 5], $this->semStack[$pos - 3], $this->startTokenStack[$pos - 5]->position), + 184, 186, 187 => fn() => $this->semValue = new Node\NameNode($this->semStack[$pos], Node\NameNode::KindNormal, $this->startTokenStack[$pos]->position), + 188 => fn() => $this->semValue = new Node\NameNode($this->semStack[$pos], Node\NameNode::KindFullyQualified, $this->startTokenStack[$pos]->position), + 196 => fn() => $this->semValue = new Expression\ConstantFetchNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 197 => fn() => $this->semValue = new Expression\ClassConstantFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 198 => fn() => $this->semValue = new Expression\ClassConstantFetchNode($this->semStack[$pos - 4], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 4]->position), + 199 => fn() => $this->semValue = new Expression\ArrayNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 2]->position), + 200 => fn() => $this->semValue = new Expression\ArrayNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), + 201 => function () use ($pos) { $this->semValue = $this->semStack[$pos]; $this->shortArrays->attach($this->semValue); }, - 201 => fn() => $this->semValue = Scalar\StringNode::parse($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 202 => fn() => $this->semValue = Scalar\InterpolatedStringNode::parse($this->semStack[$pos - 1], $this->startTokenStack[$pos - 2]->position), - 203 => fn() => $this->semValue = Scalar\IntegerNode::parse($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 204 => fn() => $this->semValue = Scalar\FloatNode::parse($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 206, 287 => fn() => $this->semValue = new Scalar\StringNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 207 => fn() => $this->semValue = new Scalar\BooleanNode(true, $this->startTokenStack[$pos]->position), - 208 => fn() => $this->semValue = new Scalar\BooleanNode(false, $this->startTokenStack[$pos]->position), - 209 => fn() => $this->semValue = new Scalar\NullNode($this->startTokenStack[$pos]->position), - 212 => fn() => $this->semValue = $this->parseDocString($this->semStack[$pos - 2], [$this->semStack[$pos - 1]], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position, $this->startTokenStack[$pos]->position), - 213 => fn() => $this->semValue = $this->parseDocString($this->semStack[$pos - 1], [], $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position, $this->startTokenStack[$pos]->position), - 214 => fn() => $this->semValue = $this->parseDocString($this->semStack[$pos - 2], $this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position, $this->startTokenStack[$pos]->position), - 223 => fn() => $this->semValue = new Expression\ConstantFetchNode(new Node\NameNode($this->semStack[$pos], Node\NameNode::KindNormal, $this->startTokenStack[$pos]->position), $this->startTokenStack[$pos]->position), - 228, 244, 279 => fn() => $this->semValue = new Expression\ArrayAccessNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), - 230 => fn() => $this->semValue = new Expression\MethodCallNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->semStack[$pos], false, $this->startTokenStack[$pos - 3]->position), - 231 => fn() => $this->semValue = new Expression\MethodCallableNode($this->semStack[$pos - 5], $this->semStack[$pos - 3], $this->startTokenStack[$pos - 5]->position), - 232 => fn() => $this->semValue = new Expression\MethodCallNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->semStack[$pos], true, $this->startTokenStack[$pos - 3]->position), - 233 => fn() => $this->semValue = new Expression\MethodCallNode(new Expression\BinaryOpNode($this->semStack[$pos - 3], '??', new Scalar\NullNode($this->startTokenStack[$pos - 3]->position), $this->startTokenStack[$pos - 3]->position), $this->semStack[$pos - 1], $this->semStack[$pos], true, $this->startTokenStack[$pos - 3]->position), - 236, 245, 280 => fn() => $this->semValue = new Expression\PropertyFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), - 237, 246, 281 => fn() => $this->semValue = new Expression\PropertyFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], true, $this->startTokenStack[$pos - 2]->position), - 238, 247, 282 => fn() => $this->semValue = new Expression\PropertyFetchNode(new Expression\BinaryOpNode($this->semStack[$pos - 2], '??', new Scalar\NullNode($this->startTokenStack[$pos - 2]->position), $this->startTokenStack[$pos - 2]->position), $this->semStack[$pos], true, $this->startTokenStack[$pos - 2]->position), - 240 => fn() => $this->semValue = new Expression\VariableNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), - 241 => function () use ($pos) { + 202 => fn() => $this->semValue = Scalar\StringNode::parse($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 203 => fn() => $this->semValue = Scalar\InterpolatedStringNode::parse($this->semStack[$pos - 1], $this->startTokenStack[$pos - 2]->position), + 204 => fn() => $this->semValue = Scalar\IntegerNode::parse($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 205 => fn() => $this->semValue = Scalar\FloatNode::parse($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 207, 288 => fn() => $this->semValue = new Scalar\StringNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 208 => fn() => $this->semValue = new Scalar\BooleanNode(true, $this->startTokenStack[$pos]->position), + 209 => fn() => $this->semValue = new Scalar\BooleanNode(false, $this->startTokenStack[$pos]->position), + 210 => fn() => $this->semValue = new Scalar\NullNode($this->startTokenStack[$pos]->position), + 213 => fn() => $this->semValue = $this->parseDocString($this->semStack[$pos - 2], [$this->semStack[$pos - 1]], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position, $this->startTokenStack[$pos]->position), + 214 => fn() => $this->semValue = $this->parseDocString($this->semStack[$pos - 1], [], $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position, $this->startTokenStack[$pos]->position), + 215 => fn() => $this->semValue = $this->parseDocString($this->semStack[$pos - 2], $this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position, $this->startTokenStack[$pos]->position), + 224 => fn() => $this->semValue = new Expression\ConstantFetchNode(new Node\NameNode($this->semStack[$pos], Node\NameNode::KindNormal, $this->startTokenStack[$pos]->position), $this->startTokenStack[$pos]->position), + 229, 245, 280 => fn() => $this->semValue = new Expression\ArrayAccessNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), + 231 => fn() => $this->semValue = new Expression\MethodCallNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->semStack[$pos], false, $this->startTokenStack[$pos - 3]->position), + 232 => fn() => $this->semValue = new Expression\MethodCallableNode($this->semStack[$pos - 5], $this->semStack[$pos - 3], $this->startTokenStack[$pos - 5]->position), + 233 => fn() => $this->semValue = new Expression\MethodCallNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->semStack[$pos], true, $this->startTokenStack[$pos - 3]->position), + 234 => fn() => $this->semValue = new Expression\MethodCallNode(new Expression\BinaryOpNode($this->semStack[$pos - 3], '??', new Scalar\NullNode($this->startTokenStack[$pos - 3]->position), $this->startTokenStack[$pos - 3]->position), $this->semStack[$pos - 1], $this->semStack[$pos], true, $this->startTokenStack[$pos - 3]->position), + 237, 246, 281 => fn() => $this->semValue = new Expression\PropertyFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), + 238, 247, 282 => fn() => $this->semValue = new Expression\PropertyFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], true, $this->startTokenStack[$pos - 2]->position), + 239, 248, 283 => fn() => $this->semValue = new Expression\PropertyFetchNode(new Expression\BinaryOpNode($this->semStack[$pos - 2], '??', new Scalar\NullNode($this->startTokenStack[$pos - 2]->position), $this->startTokenStack[$pos - 2]->position), $this->semStack[$pos], true, $this->startTokenStack[$pos - 2]->position), + 241 => fn() => $this->semValue = new Expression\VariableNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), + 242 => function () use ($pos) { $var = $this->semStack[$pos]->name; $this->semValue = \is_string($var) ? new Node\VarLikeIdentifierNode($var, $this->startTokenStack[$pos]->position) : $var; }, - 242, 248, 249 => fn() => $this->semValue = new Expression\StaticPropertyFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 256 => fn() => $this->semValue = $this->convertArrayToList(new Expression\ArrayNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position)), - 257 => function () use ($pos) { + 243, 249, 250 => fn() => $this->semValue = new Expression\StaticPropertyFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 257 => fn() => $this->semValue = $this->convertArrayToList(new Expression\ArrayNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position)), + 258 => function () use ($pos) { $this->semValue = $this->semStack[$pos]; $end = count($this->semValue) - 1; if ( @@ -587,21 +593,21 @@ protected function reduce(int $rule, int $pos): void array_pop($this->semValue); } }, - 261 => fn() => $this->semValue = new Node\ArrayItemNode(new Expression\TemporaryNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), null, false, false, $this->startTokenStack[$pos]->position), - 262 => fn() => $this->semValue = new Node\ArrayItemNode(new Expression\TemporaryNode($this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), $this->semStack[$pos - 2], false, false, $this->startTokenStack[$pos - 2]->position), - 263 => fn() => $this->semValue = new Node\ArrayItemNode(new Expression\TemporaryNode(null), null, false, false, $this->startTokenStack[$pos]->position), - 264 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], null, false, false, $this->startTokenStack[$pos]->position), - 265 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], null, true, false, $this->startTokenStack[$pos - 1]->position), - 266, 268 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], $this->semStack[$pos - 2], false, false, $this->startTokenStack[$pos - 2]->position), - 267, 269 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], $this->semStack[$pos - 3], true, false, $this->startTokenStack[$pos - 3]->position), - 270, 271 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], null, false, true, $this->startTokenStack[$pos - 1]->position), - 275 => fn() => $this->semValue = [$this->semStack[$pos - 1], $this->semStack[$pos]], - 276 => fn() => $this->semValue = new Node\InterpolatedStringPartNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 277 => fn() => $this->semValue = new Expression\VariableNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 283, 284 => fn() => $this->semValue = new Expression\VariableNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 2]->position), - 285 => fn() => $this->semValue = new Expression\ArrayAccessNode($this->semStack[$pos - 4], $this->semStack[$pos - 2], $this->startTokenStack[$pos - 5]->position), - 288 => fn() => $this->semValue = TagParser::parseOffset($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 289 => fn() => $this->semValue = TagParser::parseOffset('-' . $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 262 => fn() => $this->semValue = new Node\ArrayItemNode(new Expression\TemporaryNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), null, false, false, $this->startTokenStack[$pos]->position), + 263 => fn() => $this->semValue = new Node\ArrayItemNode(new Expression\TemporaryNode($this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), $this->semStack[$pos - 2], false, false, $this->startTokenStack[$pos - 2]->position), + 264 => fn() => $this->semValue = new Node\ArrayItemNode(new Expression\TemporaryNode(null), null, false, false, $this->startTokenStack[$pos]->position), + 265 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], null, false, false, $this->startTokenStack[$pos]->position), + 266 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], null, true, false, $this->startTokenStack[$pos - 1]->position), + 267, 269 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], $this->semStack[$pos - 2], false, false, $this->startTokenStack[$pos - 2]->position), + 268, 270 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], $this->semStack[$pos - 3], true, false, $this->startTokenStack[$pos - 3]->position), + 271, 272 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], null, false, true, $this->startTokenStack[$pos - 1]->position), + 276 => fn() => $this->semValue = [$this->semStack[$pos - 1], $this->semStack[$pos]], + 277 => fn() => $this->semValue = new Node\InterpolatedStringPartNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 278 => fn() => $this->semValue = new Expression\VariableNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 284, 285 => fn() => $this->semValue = new Expression\VariableNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 2]->position), + 286 => fn() => $this->semValue = new Expression\ArrayAccessNode($this->semStack[$pos - 4], $this->semStack[$pos - 2], $this->startTokenStack[$pos - 5]->position), + 289 => fn() => $this->semValue = TagParser::parseOffset($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 290 => fn() => $this->semValue = TagParser::parseOffset('-' . $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), })(); } } diff --git a/src/Latte/Compiler/Token.php b/src/Latte/Compiler/Token.php index da1562aae..6c5462d04 100644 --- a/src/Latte/Compiler/Token.php +++ b/src/Latte/Compiler/Token.php @@ -118,7 +118,8 @@ final class Token Php_Comment = 334, Php_Null = 335, Php_True = 336, - Php_False = 337; + Php_False = 337, + Php_NullsafePipe = 338; public const Names = [ self::End => '[EOF]', @@ -224,6 +225,7 @@ final class Token self::Php_Null => "'null'", self::Php_True => "'true'", self::Php_False => "'false'", + self::Php_NullsafePipe => "'?|'", ]; diff --git a/tests/common/Compiler.errors.phpt b/tests/common/Compiler.errors.phpt index be3d58d99..e9f1a0436 100644 --- a/tests/common/Compiler.errors.phpt +++ b/tests/common/Compiler.errors.phpt @@ -350,3 +350,9 @@ Assert::exception( Latte\CompileException::class, "Unexpected '', expecting for element started on line 2 at column 8 (on line 2 at column 37)", ); + +Assert::exception( + fn() => $latte->compile('{block |trim?|trim}...{/block}'), + Latte\CompileException::class, + 'Nullsafe pipe is not allowed here (on line 1 at column 13)', +); diff --git a/tests/common/TagParser.parseArguments().phpt b/tests/common/TagParser.parseArguments().phpt index 28420d5e8..3fcab3935 100644 --- a/tests/common/TagParser.parseArguments().phpt +++ b/tests/common/TagParser.parseArguments().phpt @@ -93,6 +93,12 @@ test('inline modifiers', function () { }); +test('inline nullsafe pipe', function () { + Assert::same('(($ʟ_fv = 0) === null ? null : ($this->filters->mod)($ʟ_fv))', formatArgs('(0?|mod)')); + Assert::same('(($ʟ_fv = 0) === null ? null : (($ʟ_fv = ($this->filters->mod2)(($this->filters->mod1)($ʟ_fv))) === null ? null : ($this->filters->mod3)($ʟ_fv)))', formatArgs('(0?|mod1|mod2?|mod3)')); +}); + + test('in operator', function () { Assert::same("in_array(\$a, ['a', 'b'], true), 1", formatArgs('$a in [a, b], 1')); Assert::same('$a, in_array($b->func(), [1, 2], true)', formatArgs('$a, $b->func() in [1, 2]')); diff --git a/tests/common/TagParser.parseModifier().phpt b/tests/common/TagParser.parseModifier().phpt index 9cb30fded..07f034b96 100644 --- a/tests/common/TagParser.parseModifier().phpt +++ b/tests/common/TagParser.parseModifier().phpt @@ -57,6 +57,10 @@ test('depth', function () { }); +test('nullsafe pipe', function () { + Assert::same('(($ʟ_fv = @) === null ? null : (($ʟ_fv = ($this->filters->mod2)(($this->filters->mod1)($ʟ_fv))) === null ? null : ($this->filters->mod3)($ʟ_fv)))', format('?|mod1|mod2?|mod3')); +}); + test('optionalChainingPass', function () { Assert::same( '($this->filters->mod)(@, $var?->prop?->elem[1]?->call(2)?->item)', diff --git a/tests/phpParser/filters.phpt b/tests/phpParser/filters.phpt index 454188651..a8bf4f23b 100644 --- a/tests/phpParser/filters.phpt +++ b/tests/phpParser/filters.phpt @@ -37,6 +37,7 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode | | | | | name: 'upper' | | | | | position: 1:5 (offset 4) | | | | args: array (0) + | | | | nullsafe: false | | | | position: 1:4 (offset 3) | | | position: 1:2 (offset 1) | | key: null @@ -60,6 +61,7 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode | | | | | | name: 'upper' | | | | | | position: 2:11 (offset 22) | | | | | args: array (0) + | | | | | nullsafe: false | | | | | position: 2:10 (offset 21) | | | | position: 2:2 (offset 13) | | | filter: Latte\Compiler\Nodes\Php\FilterNode @@ -67,6 +69,7 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode | | | | | name: 'truncate' | | | | | position: 2:17 (offset 28) | | | | args: array (0) + | | | | nullsafe: false | | | | position: 2:16 (offset 27) | | | position: 2:2 (offset 13) | | key: null @@ -102,6 +105,7 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode | | | | | | | unpack: false | | | | | | | name: null | | | | | | | position: 3:20 (offset 58) + | | | | | nullsafe: false | | | | | position: 3:5 (offset 43) | | | | position: 3:2 (offset 40) | | | filter: Latte\Compiler\Nodes\Php\FilterNode @@ -109,6 +113,7 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode | | | | | name: 'trim' | | | | | position: 3:23 (offset 61) | | | | args: array (0) + | | | | nullsafe: false | | | | position: 3:22 (offset 60) | | | position: 3:2 (offset 40) | | key: null @@ -146,12 +151,14 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode | | | | | | | | | | name: 'round' | | | | | | | | | | position: 4:24 (offset 91) | | | | | | | | | args: array (0) + | | | | | | | | | nullsafe: false | | | | | | | | | position: 4:23 (offset 90) | | | | | | | | position: 4:21 (offset 88) | | | | | | | byRef: false | | | | | | | unpack: false | | | | | | | name: null | | | | | | | position: 4:20 (offset 87) + | | | | | nullsafe: false | | | | | position: 4:5 (offset 72) | | | | position: 4:2 (offset 69) | | | filter: Latte\Compiler\Nodes\Php\FilterNode @@ -159,6 +166,7 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode | | | | | name: 'trim' | | | | | position: 4:31 (offset 98) | | | | args: array (0) + | | | | nullsafe: false | | | | position: 4:30 (offset 97) | | | position: 4:2 (offset 69) | | key: null @@ -196,6 +204,7 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode | | | | | | | name: 'b' | | | | | | | position: 5:23 (offset 127) | | | | | | position: 5:23 (offset 127) + | | | | nullsafe: false | | | | position: 5:5 (offset 109) | | | position: 5:2 (offset 106) | | key: null @@ -233,6 +242,7 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode | | | | | | | name: 'b' | | | | | | | position: 6:23 (offset 159) | | | | | | position: 6:23 (offset 159) + | | | | nullsafe: false | | | | position: 6:5 (offset 141) | | | position: 6:2 (offset 138) | | key: null diff --git a/tests/phpParser/filtersNullsafe.phpt b/tests/phpParser/filtersNullsafe.phpt new file mode 100644 index 000000000..9adec2395 --- /dev/null +++ b/tests/phpParser/filtersNullsafe.phpt @@ -0,0 +1,252 @@ + Latte\Compiler\Nodes\Php\ArrayItemNode + | | value: Latte\Compiler\Nodes\Php\Expression\FilterCallNode + | | | expr: Latte\Compiler\Nodes\Php\Expression\VariableNode + | | | | name: 'a' + | | | | position: 1:2 (offset 1) + | | | filter: Latte\Compiler\Nodes\Php\FilterNode + | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | name: 'upper' + | | | | | position: 1:6 (offset 5) + | | | | args: array (0) + | | | | nullsafe: true + | | | | position: 1:4 (offset 3) + | | | position: 1:2 (offset 1) + | | key: null + | | byRef: false + | | unpack: false + | | position: 1:1 (offset 0) + | 1 => Latte\Compiler\Nodes\Php\ArrayItemNode + | | value: Latte\Compiler\Nodes\Php\Expression\FilterCallNode + | | | expr: Latte\Compiler\Nodes\Php\Expression\FilterCallNode + | | | | expr: Latte\Compiler\Nodes\Php\Expression\BinaryOpNode + | | | | | left: Latte\Compiler\Nodes\Php\Expression\VariableNode + | | | | | | name: 'a' + | | | | | | position: 2:2 (offset 14) + | | | | | operator: '.' + | | | | | right: Latte\Compiler\Nodes\Php\Expression\VariableNode + | | | | | | name: 'b' + | | | | | | position: 2:7 (offset 19) + | | | | | position: 2:2 (offset 14) + | | | | filter: Latte\Compiler\Nodes\Php\FilterNode + | | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | | name: 'upper' + | | | | | | position: 2:12 (offset 24) + | | | | | args: array (0) + | | | | | nullsafe: true + | | | | | position: 2:10 (offset 22) + | | | | position: 2:2 (offset 14) + | | | filter: Latte\Compiler\Nodes\Php\FilterNode + | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | name: 'truncate' + | | | | | position: 2:19 (offset 31) + | | | | args: array (0) + | | | | nullsafe: true + | | | | position: 2:17 (offset 29) + | | | position: 2:2 (offset 14) + | | key: null + | | byRef: false + | | unpack: false + | | position: 2:1 (offset 13) + | 2 => Latte\Compiler\Nodes\Php\ArrayItemNode + | | value: Latte\Compiler\Nodes\Php\Expression\FilterCallNode + | | | expr: Latte\Compiler\Nodes\Php\Expression\FilterCallNode + | | | | expr: Latte\Compiler\Nodes\Php\Expression\VariableNode + | | | | | name: 'a' + | | | | | position: 3:2 (offset 43) + | | | | filter: Latte\Compiler\Nodes\Php\FilterNode + | | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | | name: 'truncate' + | | | | | | position: 3:7 (offset 48) + | | | | | args: array (2) + | | | | | | 0 => Latte\Compiler\Nodes\Php\ArgumentNode + | | | | | | | value: Latte\Compiler\Nodes\Php\Scalar\IntegerNode + | | | | | | | | value: 10 + | | | | | | | | kind: 10 + | | | | | | | | position: 3:17 (offset 58) + | | | | | | | byRef: false + | | | | | | | unpack: false + | | | | | | | name: null + | | | | | | | position: 3:17 (offset 58) + | | | | | | 1 => Latte\Compiler\Nodes\Php\ArgumentNode + | | | | | | | value: Latte\Compiler\Nodes\Php\Scalar\IntegerNode + | | | | | | | | value: 20 + | | | | | | | | kind: 10 + | | | | | | | | position: 3:21 (offset 62) + | | | | | | | byRef: false + | | | | | | | unpack: false + | | | | | | | name: null + | | | | | | | position: 3:21 (offset 62) + | | | | | nullsafe: true + | | | | | position: 3:5 (offset 46) + | | | | position: 3:2 (offset 43) + | | | filter: Latte\Compiler\Nodes\Php\FilterNode + | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | name: 'trim' + | | | | | position: 3:26 (offset 67) + | | | | args: array (0) + | | | | nullsafe: true + | | | | position: 3:24 (offset 65) + | | | position: 3:2 (offset 43) + | | key: null + | | byRef: false + | | unpack: false + | | position: 3:1 (offset 42) + | 3 => Latte\Compiler\Nodes\Php\ArrayItemNode + | | value: Latte\Compiler\Nodes\Php\Expression\FilterCallNode + | | | expr: Latte\Compiler\Nodes\Php\Expression\FilterCallNode + | | | | expr: Latte\Compiler\Nodes\Php\Expression\VariableNode + | | | | | name: 'a' + | | | | | position: 4:2 (offset 75) + | | | | filter: Latte\Compiler\Nodes\Php\FilterNode + | | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | | name: 'truncate' + | | | | | | position: 4:7 (offset 80) + | | | | | args: array (2) + | | | | | | 0 => Latte\Compiler\Nodes\Php\ArgumentNode + | | | | | | | value: Latte\Compiler\Nodes\Php\Scalar\IntegerNode + | | | | | | | | value: 10 + | | | | | | | | kind: 10 + | | | | | | | | position: 4:17 (offset 90) + | | | | | | | byRef: false + | | | | | | | unpack: false + | | | | | | | name: null + | | | | | | | position: 4:17 (offset 90) + | | | | | | 1 => Latte\Compiler\Nodes\Php\ArgumentNode + | | | | | | | value: Latte\Compiler\Nodes\Php\Expression\FilterCallNode + | | | | | | | | expr: Latte\Compiler\Nodes\Php\Scalar\IntegerNode + | | | | | | | | | value: 20 + | | | | | | | | | kind: 10 + | | | | | | | | | position: 4:22 (offset 95) + | | | | | | | | filter: Latte\Compiler\Nodes\Php\FilterNode + | | | | | | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | | | | | | name: 'round' + | | | | | | | | | | position: 4:25 (offset 98) + | | | | | | | | | args: array (0) + | | | | | | | | | nullsafe: false + | | | | | | | | | position: 4:24 (offset 97) + | | | | | | | | position: 4:22 (offset 95) + | | | | | | | byRef: false + | | | | | | | unpack: false + | | | | | | | name: null + | | | | | | | position: 4:21 (offset 94) + | | | | | nullsafe: true + | | | | | position: 4:5 (offset 78) + | | | | position: 4:2 (offset 75) + | | | filter: Latte\Compiler\Nodes\Php\FilterNode + | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | name: 'trim' + | | | | | position: 4:32 (offset 105) + | | | | args: array (0) + | | | | nullsafe: false + | | | | position: 4:31 (offset 104) + | | | position: 4:2 (offset 75) + | | key: null + | | byRef: false + | | unpack: false + | | position: 4:1 (offset 74) + | 4 => Latte\Compiler\Nodes\Php\ArrayItemNode + | | value: Latte\Compiler\Nodes\Php\Expression\FilterCallNode + | | | expr: Latte\Compiler\Nodes\Php\Expression\VariableNode + | | | | name: 'a' + | | | | position: 5:2 (offset 113) + | | | filter: Latte\Compiler\Nodes\Php\FilterNode + | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | name: 'truncate' + | | | | | position: 5:7 (offset 118) + | | | | args: array (2) + | | | | | 0 => Latte\Compiler\Nodes\Php\ArgumentNode + | | | | | | value: Latte\Compiler\Nodes\Php\Scalar\IntegerNode + | | | | | | | value: 10 + | | | | | | | kind: 10 + | | | | | | | position: 5:20 (offset 131) + | | | | | | byRef: false + | | | | | | unpack: false + | | | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | | | name: 'a' + | | | | | | | position: 5:17 (offset 128) + | | | | | | position: 5:17 (offset 128) + | | | | | 1 => Latte\Compiler\Nodes\Php\ArgumentNode + | | | | | | value: Latte\Compiler\Nodes\Php\Scalar\BooleanNode + | | | | | | | value: true + | | | | | | | position: 5:27 (offset 138) + | | | | | | byRef: false + | | | | | | unpack: false + | | | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | | | name: 'b' + | | | | | | | position: 5:24 (offset 135) + | | | | | | position: 5:24 (offset 135) + | | | | nullsafe: true + | | | | position: 5:5 (offset 116) + | | | position: 5:2 (offset 113) + | | key: null + | | byRef: false + | | unpack: false + | | position: 5:1 (offset 112) + | 5 => Latte\Compiler\Nodes\Php\ArrayItemNode + | | value: Latte\Compiler\Nodes\Php\Expression\FilterCallNode + | | | expr: Latte\Compiler\Nodes\Php\Expression\VariableNode + | | | | name: 'a' + | | | | position: 6:2 (offset 146) + | | | filter: Latte\Compiler\Nodes\Php\FilterNode + | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | name: 'truncate' + | | | | | position: 6:7 (offset 151) + | | | | args: array (2) + | | | | | 0 => Latte\Compiler\Nodes\Php\ArgumentNode + | | | | | | value: Latte\Compiler\Nodes\Php\Scalar\IntegerNode + | | | | | | | value: 10 + | | | | | | | kind: 10 + | | | | | | | position: 6:20 (offset 164) + | | | | | | byRef: false + | | | | | | unpack: false + | | | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | | | name: 'a' + | | | | | | | position: 6:17 (offset 161) + | | | | | | position: 6:17 (offset 161) + | | | | | 1 => Latte\Compiler\Nodes\Php\ArgumentNode + | | | | | | value: Latte\Compiler\Nodes\Php\Scalar\BooleanNode + | | | | | | | value: true + | | | | | | | position: 6:27 (offset 171) + | | | | | | byRef: false + | | | | | | unpack: false + | | | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | | | name: 'b' + | | | | | | | position: 6:24 (offset 168) + | | | | | | position: 6:24 (offset 168) + | | | | nullsafe: true + | | | | position: 6:5 (offset 149) + | | | position: 6:2 (offset 146) + | | key: null + | | byRef: false + | | unpack: false + | | position: 6:1 (offset 145) + position: 1:1 (offset 0) diff --git a/tests/phpParser/modifier.phpt b/tests/phpParser/modifier.phpt index c7de9b563..7b26a30c0 100644 --- a/tests/phpParser/modifier.phpt +++ b/tests/phpParser/modifier.phpt @@ -54,18 +54,21 @@ Latte\Compiler\Nodes\Php\ModifierNode | | | | | | | name: 'round' | | | | | | | position: 1:20 (offset 19) | | | | | | args: array (0) + | | | | | | nullsafe: false | | | | | | position: 1:19 (offset 18) | | | | | position: 1:17 (offset 16) | | | | byRef: false | | | | unpack: false | | | | name: null | | | | position: 1:16 (offset 15) + | | nullsafe: false | | position: 1:1 (offset 0) | 1 => Latte\Compiler\Nodes\Php\FilterNode | | name: Latte\Compiler\Nodes\Php\IdentifierNode | | | name: 'trim' | | | position: 1:27 (offset 26) | | args: array (0) + | | nullsafe: false | | position: 1:26 (offset 25) escape: false check: true diff --git a/tests/phpParser/modifierNullsafe.phpt b/tests/phpParser/modifierNullsafe.phpt new file mode 100644 index 000000000..8b255a35a --- /dev/null +++ b/tests/phpParser/modifierNullsafe.phpt @@ -0,0 +1,75 @@ +tokenize($code); +$parser = new Latte\Compiler\TagParser($tokens); +$node = $parser->parseModifier(); +if (!$parser->isEnd()) { + $parser->stream->throwUnexpectedException(); +} + +Assert::same( + loadContent(__FILE__, __COMPILER_HALT_OFFSET__), + exportNode($node), +); + +__halt_compiler(); +Latte\Compiler\Nodes\Php\ModifierNode + filters: array (2) + | 0 => Latte\Compiler\Nodes\Php\FilterNode + | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | name: 'truncate' + | | | position: 1:3 (offset 2) + | | args: array (2) + | | | 0 => Latte\Compiler\Nodes\Php\ArgumentNode + | | | | value: Latte\Compiler\Nodes\Php\Scalar\IntegerNode + | | | | | value: 10 + | | | | | kind: 10 + | | | | | position: 1:13 (offset 12) + | | | | byRef: false + | | | | unpack: false + | | | | name: null + | | | | position: 1:13 (offset 12) + | | | 1 => Latte\Compiler\Nodes\Php\ArgumentNode + | | | | value: Latte\Compiler\Nodes\Php\Expression\FilterCallNode + | | | | | expr: Latte\Compiler\Nodes\Php\Scalar\IntegerNode + | | | | | | value: 20 + | | | | | | kind: 10 + | | | | | | position: 1:18 (offset 17) + | | | | | filter: Latte\Compiler\Nodes\Php\FilterNode + | | | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | | | | | name: 'round' + | | | | | | | position: 1:22 (offset 21) + | | | | | | args: array (0) + | | | | | | nullsafe: true + | | | | | | position: 1:20 (offset 19) + | | | | | position: 1:18 (offset 17) + | | | | byRef: false + | | | | unpack: false + | | | | name: null + | | | | position: 1:17 (offset 16) + | | nullsafe: true + | | position: 1:1 (offset 0) + | 1 => Latte\Compiler\Nodes\Php\FilterNode + | | name: Latte\Compiler\Nodes\Php\IdentifierNode + | | | name: 'trim' + | | | position: 1:30 (offset 29) + | | args: array (0) + | | nullsafe: true + | | position: 1:28 (offset 27) + escape: false + check: true + position: 1:1 (offset 0) diff --git a/tests/tags/print.phpt b/tests/tags/print.phpt index 38a370a23..18c0be9a4 100644 --- a/tests/tags/print.phpt +++ b/tests/tags/print.phpt @@ -19,7 +19,7 @@ $template = <<<'EOD' Condition: {$hello ? yes} {=$hello ? yes} Array: {$hello ? ([a, b, c])|join} {=[a, b, $hello ? c]|join} - filter: {$hello |lower} + filter: {$hello ?|lower} {$hello |truncate:"10"|lower} {$hello |types , '' , "" , "$hello" } EOD; @@ -54,7 +54,7 @@ Assert::match( echo ' filter: '; - echo LR\Filters::escapeHtmlText(($this->filters->lower)($hello)) /* line 9 */; + echo LR\Filters::escapeHtmlText((($ʟ_fv = $hello) === null ? null : ($this->filters->lower)($ʟ_fv))) /* line 9 */; echo "\n"; echo LR\Filters::escapeHtmlText(($this->filters->lower)(($this->filters->truncate)($hello, '10'))) /* line 10 */; echo "\n";