diff --git a/src/Latte/Compiler/Nodes/Php/Expression/FiltersCallNode.php b/src/Latte/Compiler/Nodes/Php/Expression/FiltersCallNode.php index e107dbcc5..f9790814c 100644 --- a/src/Latte/Compiler/Nodes/Php/Expression/FiltersCallNode.php +++ b/src/Latte/Compiler/Nodes/Php/Expression/FiltersCallNode.php @@ -29,11 +29,7 @@ public function __construct( public function print(PrintContext $context): string { - $expr = $this->expr->print($context); - foreach ($this->filters as $filter) { - $expr = $filter->printSimple($context, $expr); - } - return $expr; + return FilterNode::printFilters($context, $this->filters, $this->expr->print($context)); } diff --git a/src/Latte/Compiler/Nodes/Php/FilterNode.php b/src/Latte/Compiler/Nodes/Php/FilterNode.php index 666f67c72..047677e73 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,7 +34,24 @@ public function print(PrintContext $context): string } - public function printSimple(PrintContext $context, string $expr): string + /** + * @param self[] $filters + */ + public static function printFilters(PrintContext $context, array $filters, string $expr): string + { + $filter = array_shift($filters); + if (!$filter) { + return $expr; + } + return $filter->nullsafe + ? '(($ʟ_fv = ' . $expr . ') === null ? null : ' + . self::printFilters($context, $filters, $filter->printSimple($context, '$ʟ_fv')) + . ')' + : self::printFilters($context, $filters, $filter->printSimple($context, $expr)); + } + + + private function printSimple(PrintContext $context, string $expr): string { return '($this->filters->' . $context->objectProperty($this->name) . ')(' . $expr @@ -43,6 +62,9 @@ public function printSimple(PrintContext $context, string $expr): string 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..46c89c078 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; + $filters = []; 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); + $filters[] = $filter; } } + $expr = FilterNode::printFilters($context, $filters, $expr); $escaper = $context->getEscaper(); if ($check) { diff --git a/src/Latte/Compiler/TagLexer.php b/src/Latte/Compiler/TagLexer.php index 38bbf014e..ea2d79b75 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 9d395806b..bb843293d 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, 64, 64, 64, 411, 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, 26, + 26, 399, 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, 0, - 0, 0, 268, 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, 0, 0, 100, 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 = [ - 34, 35, -267, 32, -267, 36, -50, 37, 179, 180, 38, 39, 40, 41, 42, 43, 44, -48, 1, 193, - 45, 555, 556, 205, -47, 537, 381, -220, 16, 553, 285, 520, 242, 243, 196, 0, 286, 287, 7, -47, - -218, 288, 289, 208, 535, 178, 537, -220, -220, -220, 539, 538, 561, 559, 560, 55, 56, 57, -8190, 46, - -218, -218, -218, 416, 11, 224, 290, 15, 197, -218, 198, 539, 538, 24, 564, 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, -267, 191, 381, 418, -267, 417, 234, 82, -8190, -8190, -8190, -8191, -8191, -8191, -8191, - 73, 74, 75, 76, 362, 363, 361, 360, 359, 444, 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, -265, 172, - -265, 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, 639, 296, 25, 108, 640, -215, 297, 368, 235, 236, 367, 373, - 298, 299, 427, -22, 18, 360, 359, -8190, -8190, -8190, -8190, -8190, 26, -215, -215, -215, -8190, -8190, -8190, 372, - 20, -263, -215, -263, 427, -8190, 366, -8190, -8190, -8190, 418, -8190, 417, 362, 363, 361, 207, -182, -52, 194, - 47, 96, -221, 201, 14, 296, -78, 360, 359, -182, 297, 368, 235, 236, 367, 373, 298, 299, 360, 359, - 97, -265, -221, -221, -221, -265, 31, 109, 27, 30, -181, -181, 372, 379, -23, 380, 362, 363, 361, 366, - 427, -17, -181, -181, -16, 19, 212, 213, 214, 209, 210, 211, 194, 47, 172, 241, 201, -221, 296, 98, - 105, 360, 359, 297, 368, 235, 236, 367, 373, 298, 299, 100, 74, 75, 76, 372, 290, -221, -221, -221, - 192, 28, 366, 418, -263, 417, -181, 199, -263, 362, 363, 361, 1, 427, 200, 194, 47, 250, -181, 201, - 381, 296, 195, 553, 381, 82, 297, 368, 235, 236, 367, 373, 298, 299, 360, 359, 289, 103, 322, 381, - -8190, 278, 641, 565, 101, -8190, -8190, -8190, 372, 566, -8190, -190, 345, 50, 164, 366, 427, 51, 240, 224, - 290, -250, -249, -8190, 290, -8190, -8190, -8190, 194, 47, 21, 391, 201, 226, 296, 33, 260, 3, 177, 297, - 368, 235, 236, 367, 373, 298, 299, -248, 54, 362, 363, 361, -224, 245, 246, 247, -217, 48, 49, 17, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, -223, 360, 359, -217, -217, -217, -222, - -8190, -8190, -8190, 2, 4, -217, 5, 381, 372, 628, 362, 363, 361, 6, 8, 366, 9, -224, -8190, 10, - -8190, -8190, 29, 466, 468, 52, 23, 183, 194, 47, -216, 53, 201, -215, 296, 196, 189, 190, 239, 297, - 368, 235, 236, 367, 373, 298, 299, 275, 277, 372, -216, -216, -216, -215, -215, -215, 366, 101, 508, -216, - 551, 428, -215, 523, 529, 531, 533, 583, -29, 365, 364, -223, 259, 376, 503, 377, -8190, -8190, -8190, 330, - 369, 368, 371, 370, 367, 373, 374, 375, 360, 359, 334, -8190, -8190, -8190, -8190, 542, -8190, -8190, -8190, 509, - -8190, -8190, -8190, -8191, -8191, -8191, -8191, -8191, 608, 418, 104, 417, -8190, -8190, -8190, 636, 638, -29, 392, 550, - 637, 1, 519, 342, 635, 592, 250, 606, 580, 381, -8190, 353, 553, 596, 631, 347, 0, 554, 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, + 34, 35, -8190, -8190, -8190, 36, 32, 37, 180, 181, 38, 39, 40, 41, 42, 43, 44, -50, 1, 194, + 45, 558, 559, 206, -8190, 540, 383, 383, 12, 556, 287, -48, 246, 247, -47, 523, 288, 289, -8190, -8190, + 567, 290, 291, 209, -8190, -8190, -8190, -78, 13, -78, 542, 541, 564, 562, 563, 55, 56, 57, -183, 198, + 46, -182, -8190, 99, -8190, -8190, -8190, 226, 292, 292, 197, -183, 0, 24, -182, 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, 556, 82, -8190, -8190, -8190, -8191, -8191, -8191, -8191, 73, + 74, 75, 76, 291, 383, 362, 361, 642, 14, 11, -8190, 643, -8190, -8190, -8190, -8190, -8190, -8190, 199, 374, + -8190, 50, 197, 420, -78, 419, 368, -221, 226, 292, -78, 15, -52, -78, 364, 365, 363, 22, 51, 195, + 47, 102, 538, 202, 540, 298, 292, -221, -221, -221, 299, 370, 236, 237, 369, 375, 300, 301, 362, 361, + 192, 418, -8190, -8190, -8190, -268, 16, -268, 25, 542, 541, 383, 374, 631, 381, 235, 382, 172, 385, 368, + -8190, 429, -8190, -8190, -8190, -8190, 173, 364, 365, 363, 23, 184, 195, 47, -222, 420, 202, 419, 298, -8190, + -266, 96, -266, 299, 370, 236, 237, 369, 375, 300, 301, 362, 361, 100, -222, -222, -222, -22, -47, 292, + 381, 26, 382, -182, 179, 374, 97, 77, 78, 79, 80, 81, 368, 196, 429, 106, -182, 74, 75, 76, + 364, 365, 363, 109, 82, 195, 47, 362, 361, 202, -218, 298, -8190, -8190, 107, -222, 299, 370, 236, 237, + 369, 375, 300, 301, 362, 361, 108, 447, -268, 30, -218, -218, -218, -268, 27, -222, -222, -222, 374, -218, + -264, 18, -264, 20, -182, 368, -23, 429, -17, 210, 211, 212, -225, 364, 365, 363, -16, -182, 195, 47, + -217, 196, 202, -266, 298, -8190, -8190, -8190, -266, 299, 370, 236, 237, 369, 375, 300, 301, 362, 361, 197, + -217, -217, -217, -8190, 82, -8190, -8190, 28, 19, -217, 98, 374, -8190, -8190, -8190, -8190, -8190, -8190, 368, 228, + 429, 105, -224, 193, 201, 103, 364, 365, 363, 324, -8190, 195, 47, -219, 104, 202, -216, 298, 644, 250, + 251, 252, 299, 370, 236, 237, 369, 375, 300, 301, 362, 361, 383, -219, -219, -219, -216, -216, -216, -8190, + 101, 172, -219, -264, 374, -216, 280, 208, -264, 347, 173, 368, 420, 429, 419, 33, 245, 3, 178, -191, + 568, -29, 569, -251, 195, 47, 277, 164, 202, 243, 298, 21, 393, -250, 557, 299, 370, 236, 237, 369, + 375, 300, 301, 553, 0, 364, 365, 363, -249, -225, -224, 31, -223, 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, 639, 583, 279, 511, 554, 469, 471, + 430, 526, 506, 195, 47, 532, 534, 202, -216, 298, 536, 586, -29, 332, 299, 370, 236, 237, 369, 375, + 300, 301, 336, 545, 374, 512, 611, 200, -216, -216, -216, 368, 101, 54, 263, 355, 641, -216, 394, 640, + 522, 344, 638, 595, 367, 366, 609, 599, 378, 0, 379, -8190, -8190, -8190, 634, 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, 556, 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, 261, 261, 31, 261, 8191, 8191, 261, 8191, 8191, 8191, 29, 8191, 8191, 8191, 29, 8191, 8191, 8191, 8191, - 8191, 39, 29, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 213, 213, 213, 8191, 8191, 8191, 8191, 8191, 8191, 8191, + 8191, 262, 262, 31, 262, 8191, 8191, 262, 8191, 8191, 8191, 29, 8191, 8191, 8191, 29, 8191, 8191, 8191, 8191, + 8191, 39, 29, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 214, 214, 214, 8191, 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, 262, 262, 8191, 8191, 8191, 8191, 8191, 8191, 8191, - 8191, 8191, 1, 268, 269, 83, 77, 214, 264, 266, 79, 82, 80, 43, 44, 56, 118, 120, 152, 119, - 94, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 92, 93, 164, 153, 151, 150, - 116, 117, 123, 91, 8191, 121, 122, 140, 141, 138, 139, 142, 8191, 143, 144, 145, 146, 8191, 8191, 8191, - 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 124, 69, 69, 69, 8191, 8191, 11, 8191, 8191, 8191, 8191, 8191, - 8191, 204, 130, 131, 133, 204, 203, 148, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 209, 113, 115, - 187, 125, 126, 95, 8191, 8191, 8191, 208, 8191, 276, 215, 215, 215, 215, 34, 34, 34, 8191, 87, 34, - 8191, 8191, 34, 34, 34, 8191, 8191, 8191, 8191, 193, 221, 215, 136, 8191, 127, 128, 129, 57, 8191, 8191, - 8191, 191, 180, 8191, 2, 28, 28, 28, 8191, 234, 235, 236, 28, 28, 28, 168, 36, 71, 28, 28, - 71, 8191, 8191, 28, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 198, 8191, 219, 232, 183, 15, 20, 21, - 8191, 198, 217, 134, 135, 137, 156, 157, 158, 159, 160, 161, 162, 259, 8191, 255, 186, 8191, 8191, 215, - 8191, 8191, 275, 8191, 215, 132, 8191, 194, 239, 8191, 216, 215, 260, 8191, 8191, 8191, 59, 60, 8191, 8191, - 8191, 8191, 195, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 55, 8191, 8191, 8191, + 8191, 8191, 29, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 263, 263, 8191, 8191, 8191, 8191, 8191, 8191, 8191, + 8191, 8191, 1, 269, 270, 83, 77, 215, 265, 267, 79, 82, 80, 43, 44, 56, 119, 121, 153, 120, + 95, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 93, 94, 165, 154, 152, 151, + 117, 118, 124, 92, 8191, 122, 123, 141, 142, 139, 140, 143, 8191, 8191, 144, 145, 146, 147, 8191, 8191, + 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 125, 69, 69, 69, 8191, 8191, 11, 8191, 8191, 8191, 8191, + 8191, 8191, 205, 131, 132, 134, 205, 204, 149, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 210, 114, + 116, 188, 126, 127, 96, 216, 8191, 8191, 8191, 209, 8191, 277, 216, 216, 216, 34, 34, 34, 8191, 88, + 88, 8191, 34, 8191, 8191, 8191, 34, 34, 34, 2, 8191, 8191, 8191, 194, 222, 216, 137, 8191, 128, 129, + 130, 57, 8191, 8191, 192, 181, 8191, 28, 28, 28, 8191, 235, 236, 237, 28, 28, 28, 169, 36, 71, + 28, 28, 71, 8191, 8191, 28, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 199, 8191, 220, 233, 184, 15, + 20, 21, 8191, 199, 218, 135, 136, 138, 157, 158, 159, 160, 161, 162, 163, 260, 8191, 256, 187, 8191, + 8191, 216, 8191, 8191, 276, 8191, 216, 133, 8191, 195, 240, 8191, 217, 216, 261, 8191, 8191, 8191, 59, 60, + 8191, 8191, 8191, 8191, 196, 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, 23, 0, 0, 108, 0, 226, -59, 16, -28, 0, 223, -231, 0, 0, 0, 0, 227, - 214, 76, -13, 255, -2, 68, 0, 75, 0, 81, -76, 0, 0, -60, 4, 1, -5, 232, 0, -12, - 0, 0, 72, 0, 0, -17, 0, 0, 0, 35, 0, 0, 0, 0, -77, -44, 0, 0, 14, 25, - 112, 36, 44, -67, 0, 0, -51, 66, 0, 20, 221, 228, 57, 0, 0, + 0, 0, -1, 40, 0, 0, 108, 0, 226, 24, 22, -34, 0, 266, 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, 29, + 41, 0, 63, 0, 0, 248, 0, 0, 0, 42, 0, 0, 0, 0, 69, -44, 0, 0, 16, 27, + 7, 38, 46, -68, 0, 0, -51, -24, 0, 39, 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, 127, 127, 127, 122, 303, 304, 252, 305, 306, 307, 308, - 309, 310, 311, 312, 452, 110, 452, 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, 534, 534, 534, 415, 415, 415, 415, - 415, 225, 595, 595, 595, 536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 237, 607, 607, - 607, 607, 607, 607, 251, 331, 218, 219, 230, 319, 324, 223, 231, 232, 233, 301, 301, 552, 552, 552, - 552, 552, 552, 552, 552, 552, 632, 633, 634, 593, 593, 574, 574, 574, 574, 574, 574, 574, 574, 574, - 574, 574, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 302, 302, 302, 302, 302, 302, 302, - 302, 302, 302, 302, 229, 253, 386, 300, 300, 300, 300, 229, 229, 300, 387, 610, 439, 300, 435, 341, - 229, 229, 642, 320, 405, 443, 442, 430, 430, 396, 348, 394, 439, 229, 400, 524, 313, 313, 338, 313, - 600, 601, 313, 528, 530, 626, 408, 501, 216, 532, 582, 584, 585, 426, 525, 332, 270, 271, 597, 598, - 599, 626, 627, 264, 349, 182, 182, 0, 0, 0, 0, 0, 0, 0, 627, 0, 0, 350, 527, 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, 531, 533, 323, 111, 613, 535, 585, 587, 588, 140, 128, 129, 128, + 125, 125, 117, 138, 130, 130, 130, 130, 125, 127, 127, 127, 122, 305, 306, 256, 307, 308, 309, 310, + 311, 312, 313, 314, 455, 110, 455, 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, 537, 537, 537, 417, 417, 417, 417, + 417, 227, 398, 598, 598, 598, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 238, 610, + 610, 610, 610, 610, 610, 255, 333, 219, 220, 232, 321, 326, 224, 225, 233, 234, 303, 303, 555, 555, + 555, 555, 555, 555, 555, 555, 555, 272, 273, 600, 601, 602, 596, 596, 577, 577, 577, 577, 577, 577, + 577, 577, 577, 577, 577, 575, 575, 575, 575, 575, 575, 575, 575, 575, 575, 575, 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, 446, 445, 340, 629, 410, 350, 396, 231, 231, 645, 527, 315, 315, 428, 315, 319, 320, 315, 504, + 231, 629, 630, 318, 318, 318, 319, 320, 278, 388, 441, 334, 217, 630, 635, 636, 637, 389, 441, 335, + 354, 442, 603, 604, 528, 249, 183, 183, 351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 352, 530, 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, 239, 240, 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, 45, 45, 2, 2, 2, 2, + 2, 2, 2, 2, 37, 37, 2, 35, 35, 60, 2, 71, 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, 66, 60, 6, 54, 54, 54, 6, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 66, 70, 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, 63, 66, 66, 66, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 63, 66, 66, - 66, 66, 66, 66, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 9, 9, 9, 66, 66, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 10, 70, 13, 8, 8, 8, 8, 10, 10, 8, 13, 71, 39, 8, 11, 11, - 10, 10, 10, 20, 11, 11, 11, 37, 37, 19, 11, 11, 39, 10, 21, 11, 23, 23, 25, 23, - 69, 69, 23, 35, 35, 72, 27, 42, 62, 35, 35, 35, 35, 29, 49, 23, 67, 67, 67, 67, - 67, 72, 72, 3, 34, 6, 6, -1, -1, -1, -1, -1, -1, -1, 72, -1, -1, 10, 10, -1, + 33, 63, 19, 66, 66, 66, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 63, 66, + 66, 66, 66, 66, 66, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 67, 67, 67, 67, 67, 66, 66, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 8, 8, 8, 8, 10, 20, 8, 11, 11, 21, 8, 10, 10, + 11, 11, 11, 25, 72, 27, 11, 11, 10, 10, 10, 11, 23, 23, 29, 23, 14, 14, 23, 42, + 10, 72, 72, 54, 54, 54, 14, 14, 14, 13, 39, 23, 62, 72, 9, 9, 9, 13, 39, 45, + 45, 40, 69, 69, 49, 3, 6, 6, 34, -1, -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, 248, 357, 358, 185, 378, 326, 605, 591, 384, 265, 612, 282, 281, 451, 343, 279, 395, - 344, 399, 163, 291, 292, 335, 272, 407, 244, 424, 257, 336, 337, 262, 346, 546, 267, 429, 266, 438, - 440, 450, 261, 517, 280, 329, 521, 351, 283, 526, 581, 263, 293, 268, 543, 249, 220, 294, 227, 217, - 314, 206, 215, 625, 228, 295, 579, 269, 587, 594, 315, 611, 624, 323, 340, + -8192, 286, 126, 241, 359, 360, 186, 380, 328, 608, 594, 386, 267, 615, 284, 283, 454, 345, 281, 397, + 346, 401, 163, 293, 294, 337, 274, 409, 248, 426, 261, 338, 339, 265, 348, 549, 269, 431, 268, 440, + 443, 453, 264, 520, 282, 331, 524, 353, 285, 529, 584, 266, 295, 270, 546, 253, 221, 296, 229, 218, + 316, 207, 216, 628, 230, 297, 582, 271, 590, 597, 317, 614, 627, 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, 3, 3, 39, 40, 40, 40, 40, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 37, 20, 38, 38, 3, 3, 39, 39, 40, 40, 40, 40, 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, 41, 44, 44, 47, 48, 48, 49, 50, 50, 50, 50, 50, 50, - 54, 33, 33, 55, 55, 55, 42, 42, 42, 52, 52, 46, 46, 58, 59, 59, 24, 61, 61, 61, - 61, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 45, 45, 57, 57, 57, 57, 64, - 64, 64, 51, 51, 51, 65, 65, 65, 65, 65, 65, 65, 22, 22, 22, 22, 22, 66, 66, 69, - 68, 56, 56, 56, 56, 56, 56, 56, 53, 53, 53, 67, 67, 67, 23, 60, 70, 70, 71, 71, - 71, 71, 13, 13, 13, 13, 13, 13, 13, 13, 62, 62, 62, 62, 63, 73, 72, 72, 72, 72, - 72, 72, 72, 72, 72, 74, 74, 74, 74, + 2, 2, 2, 2, 2, 2, 2, 2, 41, 44, 44, 47, 48, 48, 49, 50, 50, 50, 50, 50, + 50, 54, 33, 33, 55, 55, 55, 42, 42, 42, 52, 52, 46, 46, 58, 59, 59, 24, 61, 61, + 61, 61, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 45, 45, 57, 57, 57, 57, + 64, 64, 64, 51, 51, 51, 65, 65, 65, 65, 65, 65, 65, 22, 22, 22, 22, 22, 66, 66, + 69, 68, 56, 56, 56, 56, 56, 56, 56, 53, 53, 53, 67, 67, 67, 23, 60, 70, 70, 71, + 71, 71, 71, 13, 13, 13, 13, 13, 13, 13, 13, 62, 62, 62, 62, 63, 73, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 74, 74, 74, 74, ]; /** 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, 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, 4, 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, 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, 4, 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, 91, 96, 97, 163, 180, 182, 186, 187, 189, 190, 192, 203, 208, 209, 214, 215, 217, 218, 219, 220, 222, 224, 225, 227, 232, 233, 237, 241, 248, 250, 251, 253, 258, 276, 288 => 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, 92, 97, 98, 164, 181, 183, 187, 188, 190, 191, 193, 204, 209, 210, 215, 216, 218, 219, 220, 221, 223, 225, 226, 228, 233, 234, 238, 242, 249, 251, 252, 254, 259, 277, 289 => 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, 88, 89, 90, 148, 169, 170, 188, 216, 223, 249, 252, 284 => fn() => $this->semValue = $this->semStack[$pos - 1], - 31, 39, 52, 73, 87, 168, 191 => fn() => $this->semValue = [], - 32, 41, 53, 75, 83, 84, 171, 257, 272 => fn() => $this->semValue = [$this->semStack[$pos]], - 33, 42, 54, 66, 68, 76, 82, 172, 256 => function () use ($pos) { + 30, 40, 51, 81, 89, 90, 91, 149, 170, 171, 189, 217, 224, 250, 253, 285 => fn() => $this->semValue = $this->semStack[$pos - 1], + 31, 39, 52, 73, 88, 169, 192 => fn() => $this->semValue = [], + 32, 41, 53, 75, 83, 84, 172, 258, 273 => fn() => $this->semValue = [$this->semStack[$pos]], + 33, 42, 54, 66, 68, 76, 82, 173, 257 => 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, 213 => fn() => $this->semValue = null, + 69, 71, 214 => 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), - 85, 270, 271 => function () use ($pos) { + 85, 271, 272 => function () use ($pos) { $this->semStack[$pos - 1][] = $this->semStack[$pos]; $this->semValue = $this->semStack[$pos - 1]; }, - 86 => fn() => $this->semValue = new Node\FilterNode($this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 92, 94 => fn() => $this->semValue = new Expression\AssignNode($this->semStack[$pos - 2], $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), - 93 => fn() => $this->semValue = new Expression\AssignNode($this->convertArrayToList($this->semStack[$pos - 2]), $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), - 95 => fn() => $this->semValue = new Expression\AssignNode($this->semStack[$pos - 3], $this->semStack[$pos], true, $this->startTokenStack[$pos - 3]->position), - 98 => fn() => $this->semValue = new Expression\CloneNode($this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 99 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '+', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 100 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '-', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->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\PostOpNode($this->semStack[$pos - 1], '++', $this->startTokenStack[$pos - 1]->position), - 113 => fn() => $this->semValue = new Expression\PreOpNode($this->semStack[$pos], '++', $this->startTokenStack[$pos - 1]->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\BinaryOpNode($this->semStack[$pos - 2], '||', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 117 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '&&', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 118 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], 'or', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 119 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], 'and', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 120 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], 'xor', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 121, 122 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '&', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 123 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '^', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 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\InNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 134 => fn() => $this->semValue = new Expression\UnaryOpNode($this->semStack[$pos], '+', $this->startTokenStack[$pos - 1]->position), - 135 => fn() => $this->semValue = new Expression\UnaryOpNode($this->semStack[$pos], '-', $this->startTokenStack[$pos - 1]->position), - 136 => fn() => $this->semValue = new Expression\NotNode($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\BinaryOpNode($this->semStack[$pos - 2], '===', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 139 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '!==', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->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\InstanceofNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 149 => fn() => $this->semValue = new Expression\FiltersCallNode($this->semStack[$pos - 2], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), - 150 => fn() => $this->semValue = new Expression\TernaryNode($this->semStack[$pos - 4], $this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 4]->position), - 151 => fn() => $this->semValue = new Expression\TernaryNode($this->semStack[$pos - 3], null, $this->semStack[$pos], $this->startTokenStack[$pos - 3]->position), - 152 => fn() => $this->semValue = new Expression\TernaryNode($this->semStack[$pos - 2], $this->semStack[$pos], null, $this->startTokenStack[$pos - 2]->position), - 153 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '??', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 154 => fn() => $this->semValue = new Expression\IssetNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), - 155 => fn() => $this->semValue = new Expression\EmptyNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), - 156 => fn() => $this->semValue = new Expression\CastNode('int', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 157 => fn() => $this->semValue = new Expression\CastNode('float', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 158 => fn() => $this->semValue = new Expression\CastNode('string', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 159 => fn() => $this->semValue = new Expression\CastNode('array', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 160 => fn() => $this->semValue = new Expression\CastNode('object', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 161 => fn() => $this->semValue = new Expression\CastNode('bool', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 162 => fn() => $this->semValue = new Expression\ErrorSuppressNode($this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), - 164 => 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), - 165 => 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), - 166 => 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), - 167 => fn() => $this->semValue = new Expression\NewNode($this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 173 => fn() => $this->semValue = new Node\ClosureUseNode($this->semStack[$pos], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 1]->position), - 174, 176 => fn() => $this->semValue = $this->checkFunctionName(new Expression\FunctionCallNode($this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position)), - 175, 177 => fn() => $this->semValue = $this->checkFunctionName(new Expression\FunctionCallableNode($this->semStack[$pos - 3], $this->startTokenStack[$pos - 3]->position)), - 178 => fn() => $this->semValue = new Expression\StaticMethodCallNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 3]->position), - 179 => fn() => $this->semValue = new Expression\StaticMethodCallableNode($this->semStack[$pos - 5], $this->semStack[$pos - 3], $this->startTokenStack[$pos - 5]->position), - 181, 183, 184 => fn() => $this->semValue = new Node\NameNode($this->semStack[$pos], Node\NameNode::KindNormal, $this->startTokenStack[$pos]->position), - 185 => fn() => $this->semValue = new Node\NameNode($this->semStack[$pos], Node\NameNode::KindFullyQualified, $this->startTokenStack[$pos]->position), - 193 => fn() => $this->semValue = new Expression\ConstantFetchNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 194 => fn() => $this->semValue = new Expression\ClassConstantFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 195 => fn() => $this->semValue = new Expression\ClassConstantFetchNode($this->semStack[$pos - 4], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 4]->position), - 196 => fn() => $this->semValue = new Expression\ArrayNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 2]->position), - 197 => fn() => $this->semValue = new Expression\ArrayNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), - 198 => function () use ($pos) { + 86 => fn() => $this->semValue = new Node\FilterNode($this->semStack[$pos - 1], $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), + 87 => fn() => $this->semValue = new Node\FilterNode($this->semStack[$pos - 1], $this->semStack[$pos], true, $this->startTokenStack[$pos - 2]->position), + 93, 95 => fn() => $this->semValue = new Expression\AssignNode($this->semStack[$pos - 2], $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), + 94 => fn() => $this->semValue = new Expression\AssignNode($this->convertArrayToList($this->semStack[$pos - 2]), $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), + 96 => fn() => $this->semValue = new Expression\AssignNode($this->semStack[$pos - 3], $this->semStack[$pos], true, $this->startTokenStack[$pos - 3]->position), + 99 => fn() => $this->semValue = new Expression\CloneNode($this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 100 => fn() => $this->semValue = new Expression\AssignOpNode($this->semStack[$pos - 2], '+', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->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\PostOpNode($this->semStack[$pos - 1], '++', $this->startTokenStack[$pos - 1]->position), + 114 => fn() => $this->semValue = new Expression\PreOpNode($this->semStack[$pos], '++', $this->startTokenStack[$pos - 1]->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\BinaryOpNode($this->semStack[$pos - 2], '||', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->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], 'or', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 120 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], 'and', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 121 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], 'xor', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 122, 123 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '&', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 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\InNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 135 => fn() => $this->semValue = new Expression\UnaryOpNode($this->semStack[$pos], '+', $this->startTokenStack[$pos - 1]->position), + 136 => fn() => $this->semValue = new Expression\UnaryOpNode($this->semStack[$pos], '-', $this->startTokenStack[$pos - 1]->position), + 137 => fn() => $this->semValue = new Expression\NotNode($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\BinaryOpNode($this->semStack[$pos - 2], '===', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->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\InstanceofNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 150 => fn() => $this->semValue = new Expression\FiltersCallNode($this->semStack[$pos - 2], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), + 151 => fn() => $this->semValue = new Expression\TernaryNode($this->semStack[$pos - 4], $this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 4]->position), + 152 => fn() => $this->semValue = new Expression\TernaryNode($this->semStack[$pos - 3], null, $this->semStack[$pos], $this->startTokenStack[$pos - 3]->position), + 153 => fn() => $this->semValue = new Expression\TernaryNode($this->semStack[$pos - 2], $this->semStack[$pos], null, $this->startTokenStack[$pos - 2]->position), + 154 => fn() => $this->semValue = new Expression\BinaryOpNode($this->semStack[$pos - 2], '??', $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 155 => fn() => $this->semValue = new Expression\IssetNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), + 156 => fn() => $this->semValue = new Expression\EmptyNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), + 157 => fn() => $this->semValue = new Expression\CastNode('int', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 158 => fn() => $this->semValue = new Expression\CastNode('float', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 159 => fn() => $this->semValue = new Expression\CastNode('string', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 160 => fn() => $this->semValue = new Expression\CastNode('array', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 161 => fn() => $this->semValue = new Expression\CastNode('object', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 162 => fn() => $this->semValue = new Expression\CastNode('bool', $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 163 => fn() => $this->semValue = new Expression\ErrorSuppressNode($this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 165 => 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), + 166 => 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), + 167 => 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), + 168 => fn() => $this->semValue = new Expression\NewNode($this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 174 => fn() => $this->semValue = new Node\ClosureUseNode($this->semStack[$pos], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 1]->position), + 175, 177 => fn() => $this->semValue = $this->checkFunctionName(new Expression\FunctionCallNode($this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position)), + 176, 178 => fn() => $this->semValue = $this->checkFunctionName(new Expression\FunctionCallableNode($this->semStack[$pos - 3], $this->startTokenStack[$pos - 3]->position)), + 179 => fn() => $this->semValue = new Expression\StaticMethodCallNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->semStack[$pos], $this->startTokenStack[$pos - 3]->position), + 180 => fn() => $this->semValue = new Expression\StaticMethodCallableNode($this->semStack[$pos - 5], $this->semStack[$pos - 3], $this->startTokenStack[$pos - 5]->position), + 182, 184, 185 => fn() => $this->semValue = new Node\NameNode($this->semStack[$pos], Node\NameNode::KindNormal, $this->startTokenStack[$pos]->position), + 186 => fn() => $this->semValue = new Node\NameNode($this->semStack[$pos], Node\NameNode::KindFullyQualified, $this->startTokenStack[$pos]->position), + 194 => fn() => $this->semValue = new Expression\ConstantFetchNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 195 => fn() => $this->semValue = new Expression\ClassConstantFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 196 => fn() => $this->semValue = new Expression\ClassConstantFetchNode($this->semStack[$pos - 4], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 4]->position), + 197 => fn() => $this->semValue = new Expression\ArrayNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 2]->position), + 198 => fn() => $this->semValue = new Expression\ArrayNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), + 199 => function () use ($pos) { $this->semValue = $this->semStack[$pos]; $this->shortArrays->attach($this->semValue); }, - 199 => fn() => $this->semValue = Scalar\StringNode::parse($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 200 => fn() => $this->semValue = Scalar\InterpolatedStringNode::parse($this->semStack[$pos - 1], $this->startTokenStack[$pos - 2]->position), - 201 => fn() => $this->semValue = Scalar\IntegerNode::parse($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 202 => fn() => $this->semValue = Scalar\FloatNode::parse($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 204, 285 => fn() => $this->semValue = new Scalar\StringNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 205 => fn() => $this->semValue = new Scalar\BooleanNode(true, $this->startTokenStack[$pos]->position), - 206 => fn() => $this->semValue = new Scalar\BooleanNode(false, $this->startTokenStack[$pos]->position), - 207 => fn() => $this->semValue = new Scalar\NullNode($this->startTokenStack[$pos]->position), - 210 => 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), - 211 => fn() => $this->semValue = $this->parseDocString($this->semStack[$pos - 1], [], $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position, $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), - 221 => fn() => $this->semValue = new Expression\ConstantFetchNode(new Node\NameNode($this->semStack[$pos], Node\NameNode::KindNormal, $this->startTokenStack[$pos]->position), $this->startTokenStack[$pos]->position), - 226, 242, 277 => fn() => $this->semValue = new Expression\ArrayAccessNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), - 228 => fn() => $this->semValue = new Expression\MethodCallNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->semStack[$pos], false, $this->startTokenStack[$pos - 3]->position), - 229 => fn() => $this->semValue = new Expression\MethodCallableNode($this->semStack[$pos - 5], $this->semStack[$pos - 3], $this->startTokenStack[$pos - 5]->position), - 230 => fn() => $this->semValue = new Expression\MethodCallNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->semStack[$pos], true, $this->startTokenStack[$pos - 3]->position), - 231 => 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), - 234, 243, 278 => fn() => $this->semValue = new Expression\PropertyFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), - 235, 244, 279 => fn() => $this->semValue = new Expression\PropertyFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], true, $this->startTokenStack[$pos - 2]->position), - 236, 245, 280 => 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), - 238 => fn() => $this->semValue = new Expression\VariableNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), - 239 => function () use ($pos) { + 200 => fn() => $this->semValue = Scalar\StringNode::parse($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 201 => fn() => $this->semValue = Scalar\InterpolatedStringNode::parse($this->semStack[$pos - 1], $this->startTokenStack[$pos - 2]->position), + 202 => fn() => $this->semValue = Scalar\IntegerNode::parse($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 203 => fn() => $this->semValue = Scalar\FloatNode::parse($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 205, 286 => fn() => $this->semValue = new Scalar\StringNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 206 => fn() => $this->semValue = new Scalar\BooleanNode(true, $this->startTokenStack[$pos]->position), + 207 => fn() => $this->semValue = new Scalar\BooleanNode(false, $this->startTokenStack[$pos]->position), + 208 => fn() => $this->semValue = new Scalar\NullNode($this->startTokenStack[$pos]->position), + 211 => 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), + 212 => fn() => $this->semValue = $this->parseDocString($this->semStack[$pos - 1], [], $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position, $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), + 222 => fn() => $this->semValue = new Expression\ConstantFetchNode(new Node\NameNode($this->semStack[$pos], Node\NameNode::KindNormal, $this->startTokenStack[$pos]->position), $this->startTokenStack[$pos]->position), + 227, 243, 278 => fn() => $this->semValue = new Expression\ArrayAccessNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), + 229 => fn() => $this->semValue = new Expression\MethodCallNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->semStack[$pos], false, $this->startTokenStack[$pos - 3]->position), + 230 => fn() => $this->semValue = new Expression\MethodCallableNode($this->semStack[$pos - 5], $this->semStack[$pos - 3], $this->startTokenStack[$pos - 5]->position), + 231 => fn() => $this->semValue = new Expression\MethodCallNode($this->semStack[$pos - 3], $this->semStack[$pos - 1], $this->semStack[$pos], true, $this->startTokenStack[$pos - 3]->position), + 232 => 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), + 235, 244, 279 => fn() => $this->semValue = new Expression\PropertyFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], false, $this->startTokenStack[$pos - 2]->position), + 236, 245, 280 => fn() => $this->semValue = new Expression\PropertyFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], true, $this->startTokenStack[$pos - 2]->position), + 237, 246, 281 => 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), + 239 => fn() => $this->semValue = new Expression\VariableNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position), + 240 => function () use ($pos) { $var = $this->semStack[$pos]->name; $this->semValue = \is_string($var) ? new Node\VarLikeIdentifierNode($var, $this->startTokenStack[$pos]->position) : $var; }, - 240, 246, 247 => fn() => $this->semValue = new Expression\StaticPropertyFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), - 254 => fn() => $this->semValue = $this->convertArrayToList(new Expression\ArrayNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position)), - 255 => function () use ($pos) { + 241, 247, 248 => fn() => $this->semValue = new Expression\StaticPropertyFetchNode($this->semStack[$pos - 2], $this->semStack[$pos], $this->startTokenStack[$pos - 2]->position), + 255 => fn() => $this->semValue = $this->convertArrayToList(new Expression\ArrayNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 3]->position)), + 256 => 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); } }, - 259 => fn() => $this->semValue = new Node\ArrayItemNode(new Expression\TemporaryNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), null, false, false, $this->startTokenStack[$pos]->position), - 260 => 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), - 261 => fn() => $this->semValue = new Node\ArrayItemNode(new Expression\TemporaryNode(null), null, false, false, $this->startTokenStack[$pos]->position), - 262 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], null, false, false, $this->startTokenStack[$pos]->position), - 263 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], null, true, false, $this->startTokenStack[$pos - 1]->position), - 264, 266 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], $this->semStack[$pos - 2], false, false, $this->startTokenStack[$pos - 2]->position), - 265, 267 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], $this->semStack[$pos - 3], true, false, $this->startTokenStack[$pos - 3]->position), - 268, 269 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], null, false, true, $this->startTokenStack[$pos - 1]->position), - 273 => fn() => $this->semValue = [$this->semStack[$pos - 1], $this->semStack[$pos]], - 274 => fn() => $this->semValue = new Node\InterpolatedStringPartNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 275 => fn() => $this->semValue = new Expression\VariableNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 281, 282 => fn() => $this->semValue = new Expression\VariableNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 2]->position), - 283 => fn() => $this->semValue = new Expression\ArrayAccessNode($this->semStack[$pos - 4], $this->semStack[$pos - 2], $this->startTokenStack[$pos - 5]->position), - 286 => fn() => $this->semValue = TagParser::parseOffset($this->semStack[$pos], $this->startTokenStack[$pos]->position), - 287 => fn() => $this->semValue = TagParser::parseOffset('-' . $this->semStack[$pos], $this->startTokenStack[$pos - 1]->position), + 260 => fn() => $this->semValue = new Node\ArrayItemNode(new Expression\TemporaryNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), null, false, false, $this->startTokenStack[$pos]->position), + 261 => 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), + 262 => fn() => $this->semValue = new Node\ArrayItemNode(new Expression\TemporaryNode(null), null, false, false, $this->startTokenStack[$pos]->position), + 263 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], null, false, false, $this->startTokenStack[$pos]->position), + 264 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], null, true, false, $this->startTokenStack[$pos - 1]->position), + 265, 267 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], $this->semStack[$pos - 2], false, false, $this->startTokenStack[$pos - 2]->position), + 266, 268 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], $this->semStack[$pos - 3], true, false, $this->startTokenStack[$pos - 3]->position), + 269, 270 => fn() => $this->semValue = new Node\ArrayItemNode($this->semStack[$pos], null, false, true, $this->startTokenStack[$pos - 1]->position), + 274 => fn() => $this->semValue = [$this->semStack[$pos - 1], $this->semStack[$pos]], + 275 => fn() => $this->semValue = new Node\InterpolatedStringPartNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 276 => fn() => $this->semValue = new Expression\VariableNode($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 282, 283 => fn() => $this->semValue = new Expression\VariableNode($this->semStack[$pos - 1], $this->startTokenStack[$pos - 2]->position), + 284 => fn() => $this->semValue = new Expression\ArrayAccessNode($this->semStack[$pos - 4], $this->semStack[$pos - 2], $this->startTokenStack[$pos - 5]->position), + 287 => fn() => $this->semValue = TagParser::parseOffset($this->semStack[$pos], $this->startTokenStack[$pos]->position), + 288 => 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 46c607234..6227bdb92 100644 --- a/tests/phpParser/filters.phpt +++ b/tests/phpParser/filters.phpt @@ -38,6 +38,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:1 (offset 0) | | key: null @@ -61,12 +62,14 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode | | | | | | name: 'upper' | | | | | | position: 2:11 (offset 22) | | | | | args: array (0) + | | | | | nullsafe: false | | | | | position: 2:10 (offset 21) | | | | 1 => Latte\Compiler\Nodes\Php\FilterNode | | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode | | | | | | name: 'truncate' | | | | | | position: 2:17 (offset 28) | | | | | args: array (0) + | | | | | nullsafe: false | | | | | position: 2:16 (offset 27) | | | position: 2:1 (offset 12) | | key: null @@ -102,12 +105,14 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode | | | | | | | unpack: false | | | | | | | name: null | | | | | | | position: 3:20 (offset 58) + | | | | | nullsafe: false | | | | | position: 3:5 (offset 43) | | | | 1 => Latte\Compiler\Nodes\Php\FilterNode | | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode | | | | | | name: 'trim' | | | | | | position: 3:23 (offset 61) | | | | | args: array (0) + | | | | | nullsafe: false | | | | | position: 3:22 (offset 60) | | | position: 3:1 (offset 39) | | key: null @@ -146,18 +151,21 @@ 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:20 (offset 87) | | | | | | | byRef: false | | | | | | | unpack: false | | | | | | | name: null | | | | | | | position: 4:20 (offset 87) + | | | | | nullsafe: false | | | | | position: 4:5 (offset 72) | | | | 1 => Latte\Compiler\Nodes\Php\FilterNode | | | | | name: Latte\Compiler\Nodes\Php\IdentifierNode | | | | | | name: 'trim' | | | | | | position: 4:31 (offset 98) | | | | | args: array (0) + | | | | | nullsafe: false | | | | | position: 4:30 (offset 97) | | | position: 4:1 (offset 68) | | 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:1 (offset 105) | | key: null @@ -234,6 +243,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:1 (offset 137) | | key: null diff --git a/tests/phpParser/filtersNullsafe.phpt b/tests/phpParser/filtersNullsafe.phpt new file mode 100644 index 000000000..ffda22f0e --- /dev/null +++ b/tests/phpParser/filtersNullsafe.phpt @@ -0,0 +1,253 @@ + Latte\Compiler\Nodes\Php\ArrayItemNode + | | value: Latte\Compiler\Nodes\Php\Expression\FiltersCallNode + | | | expr: Latte\Compiler\Nodes\Php\Expression\VariableNode + | | | | name: 'a' + | | | | position: 1:2 (offset 1) + | | | filters: array (1) + | | | | 0 => 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:1 (offset 0) + | | key: null + | | byRef: false + | | unpack: false + | | position: 1:1 (offset 0) + | 1 => Latte\Compiler\Nodes\Php\ArrayItemNode + | | value: Latte\Compiler\Nodes\Php\Expression\FiltersCallNode + | | | 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) + | | | filters: array (2) + | | | | 0 => 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) + | | | | 1 => 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:1 (offset 13) + | | key: null + | | byRef: false + | | unpack: false + | | position: 2:1 (offset 13) + | 2 => Latte\Compiler\Nodes\Php\ArrayItemNode + | | value: Latte\Compiler\Nodes\Php\Expression\FiltersCallNode + | | | expr: Latte\Compiler\Nodes\Php\Expression\VariableNode + | | | | name: 'a' + | | | | position: 3:2 (offset 43) + | | | filters: array (2) + | | | | 0 => 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) + | | | | 1 => 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:1 (offset 42) + | | key: null + | | byRef: false + | | unpack: false + | | position: 3:1 (offset 42) + | 3 => Latte\Compiler\Nodes\Php\ArrayItemNode + | | value: Latte\Compiler\Nodes\Php\Expression\FiltersCallNode + | | | expr: Latte\Compiler\Nodes\Php\Expression\VariableNode + | | | | name: 'a' + | | | | position: 4:2 (offset 75) + | | | filters: array (2) + | | | | 0 => 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\FiltersCallNode + | | | | | | | | expr: Latte\Compiler\Nodes\Php\Scalar\IntegerNode + | | | | | | | | | value: 20 + | | | | | | | | | kind: 10 + | | | | | | | | | position: 4:22 (offset 95) + | | | | | | | | filters: array (1) + | | | | | | | | | 0 => 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:21 (offset 94) + | | | | | | | byRef: false + | | | | | | | unpack: false + | | | | | | | name: null + | | | | | | | position: 4:21 (offset 94) + | | | | | nullsafe: true + | | | | | position: 4:5 (offset 78) + | | | | 1 => 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:1 (offset 74) + | | key: null + | | byRef: false + | | unpack: false + | | position: 4:1 (offset 74) + | 4 => Latte\Compiler\Nodes\Php\ArrayItemNode + | | value: Latte\Compiler\Nodes\Php\Expression\FiltersCallNode + | | | expr: Latte\Compiler\Nodes\Php\Expression\VariableNode + | | | | name: 'a' + | | | | position: 5:2 (offset 113) + | | | filters: array (1) + | | | | 0 => 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:1 (offset 112) + | | key: null + | | byRef: false + | | unpack: false + | | position: 5:1 (offset 112) + | 5 => Latte\Compiler\Nodes\Php\ArrayItemNode + | | value: Latte\Compiler\Nodes\Php\Expression\FiltersCallNode + | | | expr: Latte\Compiler\Nodes\Php\Expression\VariableNode + | | | | name: 'a' + | | | | position: 6:2 (offset 146) + | | | filters: array (1) + | | | | 0 => 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:1 (offset 145) + | | 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 50f1888ff..6b909c96d 100644 --- a/tests/phpParser/modifier.phpt +++ b/tests/phpParser/modifier.phpt @@ -55,18 +55,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:16 (offset 15) | | | | 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..765894b63 --- /dev/null +++ b/tests/phpParser/modifierNullsafe.phpt @@ -0,0 +1,76 @@ +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\FiltersCallNode + | | | | | expr: Latte\Compiler\Nodes\Php\Scalar\IntegerNode + | | | | | | value: 20 + | | | | | | kind: 10 + | | | | | | position: 1:18 (offset 17) + | | | | | filters: array (1) + | | | | | | 0 => 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:17 (offset 16) + | | | | 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";