1 %pure_parser 2 %expect 2 3 4 %right T_THROW 5 %left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE 6 %left ',' 7 %left T_LOGICAL_OR 8 %left T_LOGICAL_XOR 9 %left T_LOGICAL_AND 10 %right T_PRINT 11 %right T_YIELD 12 %right T_DOUBLE_ARROW 13 %right T_YIELD_FROM 14 %left '=' T_PLUS_EQUAL T_MINUS_EQUAL T_MUL_EQUAL T_DIV_EQUAL T_CONCAT_EQUAL T_MOD_EQUAL T_AND_EQUAL T_OR_EQUAL T_XOR_EQUAL T_SL_EQUAL T_SR_EQUAL T_POW_EQUAL T_COALESCE_EQUAL 15 %left '?' ':' 16 %right T_COALESCE 17 %left T_BOOLEAN_OR 18 %left T_BOOLEAN_AND 19 %left '|' 20 %left '^' 21 %left T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG 22 %nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL T_SPACESHIP 23 %nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL 24 #if PHP7 25 %left T_SL T_SR 26 %left '+' '-' '.' 27 #endif 28 #if PHP8 29 %left '.' 30 %left T_SL T_SR 31 %left '+' '-' 32 #endif 33 %left '*' '/' '%' 34 %right '!' 35 %nonassoc T_INSTANCEOF 36 %right '~' T_INC T_DEC T_INT_CAST T_DOUBLE_CAST T_STRING_CAST T_ARRAY_CAST T_OBJECT_CAST T_BOOL_CAST T_UNSET_CAST '@' 37 %right T_POW 38 %right '[' 39 %nonassoc T_NEW T_CLONE 40 %token T_EXIT 41 %token T_IF 42 %left T_ELSEIF 43 %left T_ELSE 44 %left T_ENDIF 45 %token T_LNUMBER 46 %token T_DNUMBER 47 %token T_STRING 48 %token T_STRING_VARNAME 49 %token T_VARIABLE 50 %token T_NUM_STRING 51 %token T_INLINE_HTML 52 %token T_ENCAPSED_AND_WHITESPACE 53 %token T_CONSTANT_ENCAPSED_STRING 54 %token T_ECHO 55 %token T_DO 56 %token T_WHILE 57 %token T_ENDWHILE 58 %token T_FOR 59 %token T_ENDFOR 60 %token T_FOREACH 61 %token T_ENDFOREACH 62 %token T_DECLARE 63 %token T_ENDDECLARE 64 %token T_AS 65 %token T_SWITCH 66 %token T_MATCH 67 %token T_ENDSWITCH 68 %token T_CASE 69 %token T_DEFAULT 70 %token T_BREAK 71 %token T_CONTINUE 72 %token T_GOTO 73 %token T_FUNCTION 74 %token T_FN 75 %token T_CONST 76 %token T_RETURN 77 %token T_TRY 78 %token T_CATCH 79 %token T_FINALLY 80 %token T_THROW 81 %token T_USE 82 %token T_INSTEADOF 83 %token T_GLOBAL 84 %right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC T_READONLY 85 %token T_VAR 86 %token T_UNSET 87 %token T_ISSET 88 %token T_EMPTY 89 %token T_HALT_COMPILER 90 %token T_CLASS 91 %token T_TRAIT 92 %token T_INTERFACE 93 %token T_ENUM 94 %token T_EXTENDS 95 %token T_IMPLEMENTS 96 %token T_OBJECT_OPERATOR 97 %token T_NULLSAFE_OBJECT_OPERATOR 98 %token T_DOUBLE_ARROW 99 %token T_LIST 100 %token T_ARRAY 101 %token T_CALLABLE 102 %token T_CLASS_C 103 %token T_TRAIT_C 104 %token T_METHOD_C 105 %token T_FUNC_C 106 %token T_LINE 107 %token T_FILE 108 %token T_START_HEREDOC 109 %token T_END_HEREDOC 110 %token T_DOLLAR_OPEN_CURLY_BRACES 111 %token T_CURLY_OPEN 112 %token T_PAAMAYIM_NEKUDOTAYIM 113 %token T_NAMESPACE 114 %token T_NS_C 115 %token T_DIR 116 %token T_NS_SEPARATOR 117 %token T_ELLIPSIS 118 %token T_NAME_FULLY_QUALIFIED 119 %token T_NAME_QUALIFIED 120 %token T_NAME_RELATIVE 121 %token T_ATTRIBUTE 122 %token T_ENUM 123 124 %% 125 126 start: 127 top_statement_list { $$ = $this->handleNamespaces($1); } 128 ; 129 130 top_statement_list_ex: 131 top_statement_list_ex top_statement { pushNormalizing($1, $2); } 132 | /* empty */ { init(); } 133 ; 134 135 top_statement_list: 136 top_statement_list_ex 137 { makeZeroLengthNop($nop); 138 if ($nop !== null) { $1[] = $nop; } $$ = $1; } 139 ; 140 141 ampersand: 142 T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG 143 | T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG 144 ; 145 146 reserved_non_modifiers: 147 T_INCLUDE | T_INCLUDE_ONCE | T_EVAL | T_REQUIRE | T_REQUIRE_ONCE | T_LOGICAL_OR | T_LOGICAL_XOR | T_LOGICAL_AND 148 | T_INSTANCEOF | T_NEW | T_CLONE | T_EXIT | T_IF | T_ELSEIF | T_ELSE | T_ENDIF | T_DO | T_WHILE 149 | T_ENDWHILE | T_FOR | T_ENDFOR | T_FOREACH | T_ENDFOREACH | T_DECLARE | T_ENDDECLARE | T_AS | T_TRY | T_CATCH 150 | T_FINALLY | T_THROW | T_USE | T_INSTEADOF | T_GLOBAL | T_VAR | T_UNSET | T_ISSET | T_EMPTY | T_CONTINUE | T_GOTO 151 | T_FUNCTION | T_CONST | T_RETURN | T_PRINT | T_YIELD | T_LIST | T_SWITCH | T_ENDSWITCH | T_CASE | T_DEFAULT 152 | T_BREAK | T_ARRAY | T_CALLABLE | T_EXTENDS | T_IMPLEMENTS | T_NAMESPACE | T_TRAIT | T_INTERFACE | T_CLASS 153 | T_CLASS_C | T_TRAIT_C | T_FUNC_C | T_METHOD_C | T_LINE | T_FILE | T_DIR | T_NS_C | T_FN 154 | T_MATCH | T_ENUM 155 | T_ECHO { $$ = $1; if ($$ === "<?=") $this->emitError(new Error('Cannot use "<?=" as an identifier', attributes())); } 156 ; 157 158 semi_reserved: 159 reserved_non_modifiers 160 | T_STATIC | T_ABSTRACT | T_FINAL | T_PRIVATE | T_PROTECTED | T_PUBLIC | T_READONLY 161 ; 162 163 identifier_maybe_reserved: 164 T_STRING { $$ = Node\Identifier[$1]; } 165 | semi_reserved { $$ = Node\Identifier[$1]; } 166 ; 167 168 identifier_not_reserved: 169 T_STRING { $$ = Node\Identifier[$1]; } 170 ; 171 172 reserved_non_modifiers_identifier: 173 reserved_non_modifiers { $$ = Node\Identifier[$1]; } 174 ; 175 176 namespace_declaration_name: 177 T_STRING { $$ = Name[$1]; } 178 | semi_reserved { $$ = Name[$1]; } 179 | T_NAME_QUALIFIED { $$ = Name[$1]; } 180 ; 181 182 namespace_name: 183 T_STRING { $$ = Name[$1]; } 184 | T_NAME_QUALIFIED { $$ = Name[$1]; } 185 ; 186 187 legacy_namespace_name: 188 namespace_name 189 | T_NAME_FULLY_QUALIFIED { $$ = Name[substr($1, 1)]; } 190 ; 191 192 plain_variable: 193 T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; } 194 ; 195 196 semi: 197 ';' { /* nothing */ } 198 | error { /* nothing */ } 199 ; 200 201 no_comma: 202 /* empty */ { /* nothing */ } 203 | ',' { $this->emitError(new Error('A trailing comma is not allowed here', attributes())); } 204 ; 205 206 optional_comma: 207 /* empty */ 208 | ',' 209 ; 210 211 attribute_decl: 212 class_name { $$ = Node\Attribute[$1, []]; } 213 | class_name argument_list { $$ = Node\Attribute[$1, $2]; } 214 ; 215 216 attribute_group: 217 attribute_decl { init($1); } 218 | attribute_group ',' attribute_decl { push($1, $3); } 219 ; 220 221 attribute: 222 T_ATTRIBUTE attribute_group optional_comma ']' { $$ = Node\AttributeGroup[$2]; } 223 ; 224 225 attributes: 226 attribute { init($1); } 227 | attributes attribute { push($1, $2); } 228 ; 229 230 optional_attributes: 231 /* empty */ { $$ = []; } 232 | attributes 233 ; 234 235 top_statement: 236 statement 237 | function_declaration_statement 238 | class_declaration_statement 239 | T_HALT_COMPILER '(' ')' ';' 240 { $$ = Stmt\HaltCompiler[$this->handleHaltCompiler()]; } 241 | T_NAMESPACE namespace_declaration_name semi 242 { $$ = Stmt\Namespace_[$2, null]; 243 $$->setAttribute('kind', Stmt\Namespace_::KIND_SEMICOLON); 244 $this->checkNamespace($$); } 245 | T_NAMESPACE namespace_declaration_name '{' top_statement_list '}' 246 { $$ = Stmt\Namespace_[$2, $4]; 247 $$->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); 248 $this->checkNamespace($$); } 249 | T_NAMESPACE '{' top_statement_list '}' 250 { $$ = Stmt\Namespace_[null, $3]; 251 $$->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); 252 $this->checkNamespace($$); } 253 | T_USE use_declarations semi { $$ = Stmt\Use_[$2, Stmt\Use_::TYPE_NORMAL]; } 254 | T_USE use_type use_declarations semi { $$ = Stmt\Use_[$3, $2]; } 255 | group_use_declaration semi 256 | T_CONST constant_declaration_list semi { $$ = Stmt\Const_[$2]; } 257 ; 258 259 use_type: 260 T_FUNCTION { $$ = Stmt\Use_::TYPE_FUNCTION; } 261 | T_CONST { $$ = Stmt\Use_::TYPE_CONSTANT; } 262 ; 263 264 group_use_declaration: 265 T_USE use_type legacy_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations '}' 266 { $$ = Stmt\GroupUse[$3, $6, $2]; } 267 | T_USE legacy_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}' 268 { $$ = Stmt\GroupUse[$2, $5, Stmt\Use_::TYPE_UNKNOWN]; } 269 ; 270 271 unprefixed_use_declarations: 272 non_empty_unprefixed_use_declarations optional_comma 273 ; 274 275 non_empty_unprefixed_use_declarations: 276 non_empty_unprefixed_use_declarations ',' unprefixed_use_declaration 277 { push($1, $3); } 278 | unprefixed_use_declaration { init($1); } 279 ; 280 281 use_declarations: 282 non_empty_use_declarations no_comma 283 ; 284 285 non_empty_use_declarations: 286 non_empty_use_declarations ',' use_declaration { push($1, $3); } 287 | use_declaration { init($1); } 288 ; 289 290 inline_use_declarations: 291 non_empty_inline_use_declarations optional_comma 292 ; 293 294 non_empty_inline_use_declarations: 295 non_empty_inline_use_declarations ',' inline_use_declaration 296 { push($1, $3); } 297 | inline_use_declaration { init($1); } 298 ; 299 300 unprefixed_use_declaration: 301 namespace_name 302 { $$ = Node\UseItem[$1, null, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #1); } 303 | namespace_name T_AS identifier_not_reserved 304 { $$ = Node\UseItem[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #3); } 305 ; 306 307 use_declaration: 308 legacy_namespace_name 309 { $$ = Node\UseItem[$1, null, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #1); } 310 | legacy_namespace_name T_AS identifier_not_reserved 311 { $$ = Node\UseItem[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #3); } 312 ; 313 314 inline_use_declaration: 315 unprefixed_use_declaration { $$ = $1; $$->type = Stmt\Use_::TYPE_NORMAL; } 316 | use_type unprefixed_use_declaration { $$ = $2; $$->type = $1; } 317 ; 318 319 constant_declaration_list: 320 non_empty_constant_declaration_list no_comma 321 ; 322 323 non_empty_constant_declaration_list: 324 non_empty_constant_declaration_list ',' constant_declaration 325 { push($1, $3); } 326 | constant_declaration { init($1); } 327 ; 328 329 constant_declaration: 330 identifier_not_reserved '=' expr { $$ = Node\Const_[$1, $3]; } 331 ; 332 333 class_const_list: 334 non_empty_class_const_list no_comma 335 ; 336 337 non_empty_class_const_list: 338 non_empty_class_const_list ',' class_const { push($1, $3); } 339 | class_const { init($1); } 340 ; 341 342 class_const: 343 T_STRING '=' expr 344 { $$ = Node\Const_[new Node\Identifier($1, stackAttributes(#1)), $3]; } 345 | semi_reserved '=' expr 346 { $$ = Node\Const_[new Node\Identifier($1, stackAttributes(#1)), $3]; } 347 ; 348 349 inner_statement_list_ex: 350 inner_statement_list_ex inner_statement { pushNormalizing($1, $2); } 351 | /* empty */ { init(); } 352 ; 353 354 inner_statement_list: 355 inner_statement_list_ex 356 { makeZeroLengthNop($nop); 357 if ($nop !== null) { $1[] = $nop; } $$ = $1; } 358 ; 359 360 inner_statement: 361 statement 362 | function_declaration_statement 363 | class_declaration_statement 364 | T_HALT_COMPILER 365 { throw new Error('__HALT_COMPILER() can only be used from the outermost scope', attributes()); } 366 ; 367 368 non_empty_statement: 369 '{' inner_statement_list '}' { $$ = Stmt\Block[$2]; } 370 | T_IF '(' expr ')' blocklike_statement elseif_list else_single 371 { $$ = Stmt\If_[$3, ['stmts' => $5, 'elseifs' => $6, 'else' => $7]]; } 372 | T_IF '(' expr ')' ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';' 373 { $$ = Stmt\If_[$3, ['stmts' => $6, 'elseifs' => $7, 'else' => $8]]; } 374 | T_WHILE '(' expr ')' while_statement { $$ = Stmt\While_[$3, $5]; } 375 | T_DO blocklike_statement T_WHILE '(' expr ')' ';' { $$ = Stmt\Do_ [$5, $2]; } 376 | T_FOR '(' for_expr ';' for_expr ';' for_expr ')' for_statement 377 { $$ = Stmt\For_[['init' => $3, 'cond' => $5, 'loop' => $7, 'stmts' => $9]]; } 378 | T_SWITCH '(' expr ')' switch_case_list { $$ = Stmt\Switch_[$3, $5]; } 379 | T_BREAK optional_expr semi { $$ = Stmt\Break_[$2]; } 380 | T_CONTINUE optional_expr semi { $$ = Stmt\Continue_[$2]; } 381 | T_RETURN optional_expr semi { $$ = Stmt\Return_[$2]; } 382 | T_GLOBAL global_var_list semi { $$ = Stmt\Global_[$2]; } 383 | T_STATIC static_var_list semi { $$ = Stmt\Static_[$2]; } 384 | T_ECHO expr_list_forbid_comma semi { $$ = Stmt\Echo_[$2]; } 385 | T_INLINE_HTML { 386 $$ = Stmt\InlineHTML[$1]; 387 $$->setAttribute('hasLeadingNewline', $this->inlineHtmlHasLeadingNewline(#1)); 388 } 389 | expr semi { $$ = Stmt\Expression[$1]; } 390 | T_UNSET '(' variables_list ')' semi { $$ = Stmt\Unset_[$3]; } 391 | T_FOREACH '(' expr T_AS foreach_variable ')' foreach_statement 392 { $$ = Stmt\Foreach_[$3, $5[0], ['keyVar' => null, 'byRef' => $5[1], 'stmts' => $7]]; } 393 | T_FOREACH '(' expr T_AS variable T_DOUBLE_ARROW foreach_variable ')' foreach_statement 394 { $$ = Stmt\Foreach_[$3, $7[0], ['keyVar' => $5, 'byRef' => $7[1], 'stmts' => $9]]; } 395 | T_FOREACH '(' expr error ')' foreach_statement 396 { $$ = Stmt\Foreach_[$3, new Expr\Error(stackAttributes(#4)), ['stmts' => $6]]; } 397 | T_DECLARE '(' declare_list ')' declare_statement { $$ = Stmt\Declare_[$3, $5]; } 398 | T_TRY '{' inner_statement_list '}' catches optional_finally 399 { $$ = Stmt\TryCatch[$3, $5, $6]; $this->checkTryCatch($$); } 400 | T_GOTO identifier_not_reserved semi { $$ = Stmt\Goto_[$2]; } 401 | identifier_not_reserved ':' { $$ = Stmt\Label[$1]; } 402 | error { $$ = null; /* means: no statement */ } 403 ; 404 405 statement: 406 non_empty_statement 407 | ';' { makeNop($$); } 408 ; 409 410 blocklike_statement: 411 statement { toBlock($1); } 412 ; 413 414 catches: 415 /* empty */ { init(); } 416 | catches catch { push($1, $2); } 417 ; 418 419 name_union: 420 name { init($1); } 421 | name_union '|' name { push($1, $3); } 422 ; 423 424 catch: 425 T_CATCH '(' name_union optional_plain_variable ')' '{' inner_statement_list '}' 426 { $$ = Stmt\Catch_[$3, $4, $7]; } 427 ; 428 429 optional_finally: 430 /* empty */ { $$ = null; } 431 | T_FINALLY '{' inner_statement_list '}' { $$ = Stmt\Finally_[$3]; } 432 ; 433 434 variables_list: 435 non_empty_variables_list optional_comma 436 ; 437 438 non_empty_variables_list: 439 variable { init($1); } 440 | non_empty_variables_list ',' variable { push($1, $3); } 441 ; 442 443 optional_ref: 444 /* empty */ { $$ = false; } 445 | ampersand { $$ = true; } 446 ; 447 448 optional_arg_ref: 449 /* empty */ { $$ = false; } 450 | T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG { $$ = true; } 451 ; 452 453 optional_ellipsis: 454 /* empty */ { $$ = false; } 455 | T_ELLIPSIS { $$ = true; } 456 ; 457 458 block_or_error: 459 '{' inner_statement_list '}' { $$ = $2; } 460 | error { $$ = []; } 461 ; 462 463 identifier_maybe_readonly: 464 identifier_not_reserved 465 | T_READONLY { $$ = Node\Identifier[$1]; } 466 ; 467 468 function_declaration_statement: 469 T_FUNCTION optional_ref identifier_maybe_readonly '(' parameter_list ')' optional_return_type block_or_error 470 { $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $8, 'attrGroups' => []]]; } 471 | attributes T_FUNCTION optional_ref identifier_maybe_readonly '(' parameter_list ')' optional_return_type block_or_error 472 { $$ = Stmt\Function_[$4, ['byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => $1]]; } 473 ; 474 475 class_declaration_statement: 476 class_entry_type identifier_not_reserved extends_from implements_list '{' class_statement_list '}' 477 { $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6, 'attrGroups' => []]]; 478 $this->checkClass($$, #2); } 479 | attributes class_entry_type identifier_not_reserved extends_from implements_list '{' class_statement_list '}' 480 { $$ = Stmt\Class_[$3, ['type' => $2, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]]; 481 $this->checkClass($$, #3); } 482 | optional_attributes T_INTERFACE identifier_not_reserved interface_extends_list '{' class_statement_list '}' 483 { $$ = Stmt\Interface_[$3, ['extends' => $4, 'stmts' => $6, 'attrGroups' => $1]]; 484 $this->checkInterface($$, #3); } 485 | optional_attributes T_TRAIT identifier_not_reserved '{' class_statement_list '}' 486 { $$ = Stmt\Trait_[$3, ['stmts' => $5, 'attrGroups' => $1]]; } 487 | optional_attributes T_ENUM identifier_not_reserved enum_scalar_type implements_list '{' class_statement_list '}' 488 { $$ = Stmt\Enum_[$3, ['scalarType' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]]; 489 $this->checkEnum($$, #3); } 490 ; 491 492 enum_scalar_type: 493 /* empty */ { $$ = null; } 494 | ':' type { $$ = $2; } 495 496 enum_case_expr: 497 /* empty */ { $$ = null; } 498 | '=' expr { $$ = $2; } 499 ; 500 501 class_entry_type: 502 T_CLASS { $$ = 0; } 503 | class_modifiers T_CLASS 504 ; 505 506 class_modifiers: 507 class_modifier 508 | class_modifiers class_modifier { $this->checkClassModifier($1, $2, #2); $$ = $1 | $2; } 509 ; 510 511 class_modifier: 512 T_ABSTRACT { $$ = Modifiers::ABSTRACT; } 513 | T_FINAL { $$ = Modifiers::FINAL; } 514 | T_READONLY { $$ = Modifiers::READONLY; } 515 ; 516 517 extends_from: 518 /* empty */ { $$ = null; } 519 | T_EXTENDS class_name { $$ = $2; } 520 ; 521 522 interface_extends_list: 523 /* empty */ { $$ = array(); } 524 | T_EXTENDS class_name_list { $$ = $2; } 525 ; 526 527 implements_list: 528 /* empty */ { $$ = array(); } 529 | T_IMPLEMENTS class_name_list { $$ = $2; } 530 ; 531 532 class_name_list: 533 non_empty_class_name_list no_comma 534 ; 535 536 non_empty_class_name_list: 537 class_name { init($1); } 538 | non_empty_class_name_list ',' class_name { push($1, $3); } 539 ; 540 541 for_statement: 542 blocklike_statement 543 | ':' inner_statement_list T_ENDFOR ';' { $$ = $2; } 544 ; 545 546 foreach_statement: 547 blocklike_statement 548 | ':' inner_statement_list T_ENDFOREACH ';' { $$ = $2; } 549 ; 550 551 declare_statement: 552 non_empty_statement { toBlock($1); } 553 | ';' { $$ = null; } 554 | ':' inner_statement_list T_ENDDECLARE ';' { $$ = $2; } 555 ; 556 557 declare_list: 558 non_empty_declare_list no_comma 559 ; 560 561 non_empty_declare_list: 562 declare_list_element { init($1); } 563 | non_empty_declare_list ',' declare_list_element { push($1, $3); } 564 ; 565 566 declare_list_element: 567 identifier_not_reserved '=' expr { $$ = Node\DeclareItem[$1, $3]; } 568 ; 569 570 switch_case_list: 571 '{' case_list '}' { $$ = $2; } 572 | '{' ';' case_list '}' { $$ = $3; } 573 | ':' case_list T_ENDSWITCH ';' { $$ = $2; } 574 | ':' ';' case_list T_ENDSWITCH ';' { $$ = $3; } 575 ; 576 577 case_list: 578 /* empty */ { init(); } 579 | case_list case { push($1, $2); } 580 ; 581 582 case: 583 T_CASE expr case_separator inner_statement_list_ex { $$ = Stmt\Case_[$2, $4]; } 584 | T_DEFAULT case_separator inner_statement_list_ex { $$ = Stmt\Case_[null, $3]; } 585 ; 586 587 case_separator: 588 ':' 589 | ';' 590 ; 591 592 match: 593 T_MATCH '(' expr ')' '{' match_arm_list '}' { $$ = Expr\Match_[$3, $6]; } 594 ; 595 596 match_arm_list: 597 /* empty */ { $$ = []; } 598 | non_empty_match_arm_list optional_comma 599 ; 600 601 non_empty_match_arm_list: 602 match_arm { init($1); } 603 | non_empty_match_arm_list ',' match_arm { push($1, $3); } 604 ; 605 606 match_arm: 607 expr_list_allow_comma T_DOUBLE_ARROW expr { $$ = Node\MatchArm[$1, $3]; } 608 | T_DEFAULT optional_comma T_DOUBLE_ARROW expr { $$ = Node\MatchArm[null, $4]; } 609 ; 610 611 while_statement: 612 blocklike_statement { $$ = $1; } 613 | ':' inner_statement_list T_ENDWHILE ';' { $$ = $2; } 614 ; 615 616 elseif_list: 617 /* empty */ { init(); } 618 | elseif_list elseif { push($1, $2); } 619 ; 620 621 elseif: 622 T_ELSEIF '(' expr ')' blocklike_statement { $$ = Stmt\ElseIf_[$3, $5]; } 623 ; 624 625 new_elseif_list: 626 /* empty */ { init(); } 627 | new_elseif_list new_elseif { push($1, $2); } 628 ; 629 630 new_elseif: 631 T_ELSEIF '(' expr ')' ':' inner_statement_list 632 { $$ = Stmt\ElseIf_[$3, $6]; $this->fixupAlternativeElse($$); } 633 ; 634 635 else_single: 636 /* empty */ { $$ = null; } 637 | T_ELSE blocklike_statement { $$ = Stmt\Else_[$2]; } 638 ; 639 640 new_else_single: 641 /* empty */ { $$ = null; } 642 | T_ELSE ':' inner_statement_list 643 { $$ = Stmt\Else_[$3]; $this->fixupAlternativeElse($$); } 644 ; 645 646 foreach_variable: 647 variable { $$ = array($1, false); } 648 | ampersand variable { $$ = array($2, true); } 649 | list_expr { $$ = array($1, false); } 650 | array_short_syntax 651 { $$ = array($this->fixupArrayDestructuring($1), false); } 652 ; 653 654 parameter_list: 655 non_empty_parameter_list optional_comma 656 | /* empty */ { $$ = array(); } 657 ; 658 659 non_empty_parameter_list: 660 parameter { init($1); } 661 | non_empty_parameter_list ',' parameter { push($1, $3); } 662 ; 663 664 optional_property_modifiers: 665 /* empty */ { $$ = 0; } 666 | optional_property_modifiers property_modifier 667 { $this->checkModifier($1, $2, #2); $$ = $1 | $2; } 668 ; 669 670 property_modifier: 671 T_PUBLIC { $$ = Modifiers::PUBLIC; } 672 | T_PROTECTED { $$ = Modifiers::PROTECTED; } 673 | T_PRIVATE { $$ = Modifiers::PRIVATE; } 674 | T_READONLY { $$ = Modifiers::READONLY; } 675 ; 676 677 parameter: 678 optional_attributes optional_property_modifiers optional_type_without_static 679 optional_arg_ref optional_ellipsis plain_variable 680 { $$ = new Node\Param($6, null, $3, $4, $5, attributes(), $2, $1); 681 $this->checkParam($$); } 682 | optional_attributes optional_property_modifiers optional_type_without_static 683 optional_arg_ref optional_ellipsis plain_variable '=' expr 684 { $$ = new Node\Param($6, $8, $3, $4, $5, attributes(), $2, $1); 685 $this->checkParam($$); } 686 | optional_attributes optional_property_modifiers optional_type_without_static 687 optional_arg_ref optional_ellipsis error 688 { $$ = new Node\Param(Expr\Error[], null, $3, $4, $5, attributes(), $2, $1); } 689 ; 690 691 type_expr: 692 type 693 | '?' type { $$ = Node\NullableType[$2]; } 694 | union_type { $$ = Node\UnionType[$1]; } 695 | intersection_type 696 ; 697 698 type: 699 type_without_static 700 | T_STATIC { $$ = Node\Name['static']; } 701 ; 702 703 type_without_static: 704 name { $$ = $this->handleBuiltinTypes($1); } 705 | T_ARRAY { $$ = Node\Identifier['array']; } 706 | T_CALLABLE { $$ = Node\Identifier['callable']; } 707 ; 708 709 union_type_element: 710 type 711 | '(' intersection_type ')' { $$ = $2; } 712 ; 713 714 union_type: 715 union_type_element '|' union_type_element { init($1, $3); } 716 | union_type '|' union_type_element { push($1, $3); } 717 ; 718 719 union_type_without_static_element: 720 type_without_static 721 | '(' intersection_type_without_static ')' { $$ = $2; } 722 ; 723 724 union_type_without_static: 725 union_type_without_static_element '|' union_type_without_static_element { init($1, $3); } 726 | union_type_without_static '|' union_type_without_static_element { push($1, $3); } 727 ; 728 729 intersection_type_list: 730 type T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type { init($1, $3); } 731 | intersection_type_list T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type 732 { push($1, $3); } 733 ; 734 735 intersection_type: 736 intersection_type_list { $$ = Node\IntersectionType[$1]; } 737 ; 738 739 intersection_type_without_static_list: 740 type_without_static T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type_without_static 741 { init($1, $3); } 742 | intersection_type_without_static_list T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type_without_static 743 { push($1, $3); } 744 ; 745 746 intersection_type_without_static: 747 intersection_type_without_static_list { $$ = Node\IntersectionType[$1]; } 748 ; 749 750 type_expr_without_static: 751 type_without_static 752 | '?' type_without_static { $$ = Node\NullableType[$2]; } 753 | union_type_without_static { $$ = Node\UnionType[$1]; } 754 | intersection_type_without_static 755 ; 756 757 optional_type_without_static: 758 /* empty */ { $$ = null; } 759 | type_expr_without_static 760 ; 761 762 optional_return_type: 763 /* empty */ { $$ = null; } 764 | ':' type_expr { $$ = $2; } 765 | ':' error { $$ = null; } 766 ; 767 768 argument_list: 769 '(' ')' { $$ = array(); } 770 | '(' non_empty_argument_list optional_comma ')' { $$ = $2; } 771 | '(' variadic_placeholder ')' { init($2); } 772 ; 773 774 variadic_placeholder: 775 T_ELLIPSIS { $$ = Node\VariadicPlaceholder[]; } 776 ; 777 778 non_empty_argument_list: 779 argument { init($1); } 780 | non_empty_argument_list ',' argument { push($1, $3); } 781 ; 782 783 argument: 784 expr { $$ = Node\Arg[$1, false, false]; } 785 | ampersand variable { $$ = Node\Arg[$2, true, false]; } 786 | T_ELLIPSIS expr { $$ = Node\Arg[$2, false, true]; } 787 | identifier_maybe_reserved ':' expr 788 { $$ = new Node\Arg($3, false, false, attributes(), $1); } 789 ; 790 791 global_var_list: 792 non_empty_global_var_list no_comma 793 ; 794 795 non_empty_global_var_list: 796 non_empty_global_var_list ',' global_var { push($1, $3); } 797 | global_var { init($1); } 798 ; 799 800 global_var: 801 simple_variable 802 ; 803 804 static_var_list: 805 non_empty_static_var_list no_comma 806 ; 807 808 non_empty_static_var_list: 809 non_empty_static_var_list ',' static_var { push($1, $3); } 810 | static_var { init($1); } 811 ; 812 813 static_var: 814 plain_variable { $$ = Node\StaticVar[$1, null]; } 815 | plain_variable '=' expr { $$ = Node\StaticVar[$1, $3]; } 816 ; 817 818 class_statement_list_ex: 819 class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } else { $$ = $1; } } 820 | /* empty */ { init(); } 821 ; 822 823 class_statement_list: 824 class_statement_list_ex 825 { makeZeroLengthNop($nop); 826 if ($nop !== null) { $1[] = $nop; } $$ = $1; } 827 ; 828 829 class_statement: 830 optional_attributes variable_modifiers optional_type_without_static property_declaration_list semi 831 { $$ = new Stmt\Property($2, $4, attributes(), $3, $1); 832 $this->checkProperty($$, #2); } 833 | optional_attributes method_modifiers T_CONST class_const_list semi 834 { $$ = new Stmt\ClassConst($4, $2, attributes(), $1); 835 $this->checkClassConst($$, #2); } 836 | optional_attributes method_modifiers T_CONST type_expr class_const_list semi 837 { $$ = new Stmt\ClassConst($5, $2, attributes(), $1, $4); 838 $this->checkClassConst($$, #2); } 839 | optional_attributes method_modifiers T_FUNCTION optional_ref identifier_maybe_reserved '(' parameter_list ')' 840 optional_return_type method_body 841 { $$ = Stmt\ClassMethod[$5, ['type' => $2, 'byRef' => $4, 'params' => $7, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]]; 842 $this->checkClassMethod($$, #2); } 843 | T_USE class_name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; } 844 | optional_attributes T_CASE identifier_maybe_reserved enum_case_expr semi 845 { $$ = Stmt\EnumCase[$3, $4, $1]; } 846 | error { $$ = null; /* will be skipped */ } 847 ; 848 849 trait_adaptations: 850 ';' { $$ = array(); } 851 | '{' trait_adaptation_list '}' { $$ = $2; } 852 ; 853 854 trait_adaptation_list: 855 /* empty */ { init(); } 856 | trait_adaptation_list trait_adaptation { push($1, $2); } 857 ; 858 859 trait_adaptation: 860 trait_method_reference_fully_qualified T_INSTEADOF class_name_list ';' 861 { $$ = Stmt\TraitUseAdaptation\Precedence[$1[0], $1[1], $3]; } 862 | trait_method_reference T_AS member_modifier identifier_maybe_reserved ';' 863 { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, $4]; } 864 | trait_method_reference T_AS member_modifier ';' 865 { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, null]; } 866 | trait_method_reference T_AS identifier_not_reserved ';' 867 { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; } 868 | trait_method_reference T_AS reserved_non_modifiers_identifier ';' 869 { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; } 870 ; 871 872 trait_method_reference_fully_qualified: 873 name T_PAAMAYIM_NEKUDOTAYIM identifier_maybe_reserved { $$ = array($1, $3); } 874 ; 875 trait_method_reference: 876 trait_method_reference_fully_qualified 877 | identifier_maybe_reserved { $$ = array(null, $1); } 878 ; 879 880 method_body: 881 ';' /* abstract method */ { $$ = null; } 882 | block_or_error 883 ; 884 885 variable_modifiers: 886 non_empty_member_modifiers 887 | T_VAR { $$ = 0; } 888 ; 889 890 method_modifiers: 891 /* empty */ { $$ = 0; } 892 | non_empty_member_modifiers 893 ; 894 895 non_empty_member_modifiers: 896 member_modifier 897 | non_empty_member_modifiers member_modifier { $this->checkModifier($1, $2, #2); $$ = $1 | $2; } 898 ; 899 900 member_modifier: 901 T_PUBLIC { $$ = Modifiers::PUBLIC; } 902 | T_PROTECTED { $$ = Modifiers::PROTECTED; } 903 | T_PRIVATE { $$ = Modifiers::PRIVATE; } 904 | T_STATIC { $$ = Modifiers::STATIC; } 905 | T_ABSTRACT { $$ = Modifiers::ABSTRACT; } 906 | T_FINAL { $$ = Modifiers::FINAL; } 907 | T_READONLY { $$ = Modifiers::READONLY; } 908 ; 909 910 property_declaration_list: 911 non_empty_property_declaration_list no_comma 912 ; 913 914 non_empty_property_declaration_list: 915 property_declaration { init($1); } 916 | non_empty_property_declaration_list ',' property_declaration 917 { push($1, $3); } 918 ; 919 920 property_decl_name: 921 T_VARIABLE { $$ = Node\VarLikeIdentifier[parseVar($1)]; } 922 ; 923 924 property_declaration: 925 property_decl_name { $$ = Node\PropertyItem[$1, null]; } 926 | property_decl_name '=' expr { $$ = Node\PropertyItem[$1, $3]; } 927 ; 928 929 expr_list_forbid_comma: 930 non_empty_expr_list no_comma 931 ; 932 933 expr_list_allow_comma: 934 non_empty_expr_list optional_comma 935 ; 936 937 non_empty_expr_list: 938 non_empty_expr_list ',' expr { push($1, $3); } 939 | expr { init($1); } 940 ; 941 942 for_expr: 943 /* empty */ { $$ = array(); } 944 | expr_list_forbid_comma 945 ; 946 947 expr: 948 variable 949 | list_expr '=' expr { $$ = Expr\Assign[$1, $3]; } 950 | array_short_syntax '=' expr 951 { $$ = Expr\Assign[$this->fixupArrayDestructuring($1), $3]; } 952 | variable '=' expr { $$ = Expr\Assign[$1, $3]; } 953 | variable '=' ampersand variable { $$ = Expr\AssignRef[$1, $4]; } 954 | variable '=' ampersand new_expr 955 { $$ = Expr\AssignRef[$1, $4]; 956 if (!$this->phpVersion->allowsAssignNewByReference()) { 957 $this->emitError(new Error('Cannot assign new by reference', attributes())); 958 } 959 } 960 | new_expr 961 | match 962 | T_CLONE expr { $$ = Expr\Clone_[$2]; } 963 | variable T_PLUS_EQUAL expr { $$ = Expr\AssignOp\Plus [$1, $3]; } 964 | variable T_MINUS_EQUAL expr { $$ = Expr\AssignOp\Minus [$1, $3]; } 965 | variable T_MUL_EQUAL expr { $$ = Expr\AssignOp\Mul [$1, $3]; } 966 | variable T_DIV_EQUAL expr { $$ = Expr\AssignOp\Div [$1, $3]; } 967 | variable T_CONCAT_EQUAL expr { $$ = Expr\AssignOp\Concat [$1, $3]; } 968 | variable T_MOD_EQUAL expr { $$ = Expr\AssignOp\Mod [$1, $3]; } 969 | variable T_AND_EQUAL expr { $$ = Expr\AssignOp\BitwiseAnd[$1, $3]; } 970 | variable T_OR_EQUAL expr { $$ = Expr\AssignOp\BitwiseOr [$1, $3]; } 971 | variable T_XOR_EQUAL expr { $$ = Expr\AssignOp\BitwiseXor[$1, $3]; } 972 | variable T_SL_EQUAL expr { $$ = Expr\AssignOp\ShiftLeft [$1, $3]; } 973 | variable T_SR_EQUAL expr { $$ = Expr\AssignOp\ShiftRight[$1, $3]; } 974 | variable T_POW_EQUAL expr { $$ = Expr\AssignOp\Pow [$1, $3]; } 975 | variable T_COALESCE_EQUAL expr { $$ = Expr\AssignOp\Coalesce [$1, $3]; } 976 | variable T_INC { $$ = Expr\PostInc[$1]; } 977 | T_INC variable { $$ = Expr\PreInc [$2]; } 978 | variable T_DEC { $$ = Expr\PostDec[$1]; } 979 | T_DEC variable { $$ = Expr\PreDec [$2]; } 980 | expr T_BOOLEAN_OR expr { $$ = Expr\BinaryOp\BooleanOr [$1, $3]; } 981 | expr T_BOOLEAN_AND expr { $$ = Expr\BinaryOp\BooleanAnd[$1, $3]; } 982 | expr T_LOGICAL_OR expr { $$ = Expr\BinaryOp\LogicalOr [$1, $3]; } 983 | expr T_LOGICAL_AND expr { $$ = Expr\BinaryOp\LogicalAnd[$1, $3]; } 984 | expr T_LOGICAL_XOR expr { $$ = Expr\BinaryOp\LogicalXor[$1, $3]; } 985 | expr '|' expr { $$ = Expr\BinaryOp\BitwiseOr [$1, $3]; } 986 | expr T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG expr { $$ = Expr\BinaryOp\BitwiseAnd[$1, $3]; } 987 | expr T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG expr { $$ = Expr\BinaryOp\BitwiseAnd[$1, $3]; } 988 | expr '^' expr { $$ = Expr\BinaryOp\BitwiseXor[$1, $3]; } 989 | expr '.' expr { $$ = Expr\BinaryOp\Concat [$1, $3]; } 990 | expr '+' expr { $$ = Expr\BinaryOp\Plus [$1, $3]; } 991 | expr '-' expr { $$ = Expr\BinaryOp\Minus [$1, $3]; } 992 | expr '*' expr { $$ = Expr\BinaryOp\Mul [$1, $3]; } 993 | expr '/' expr { $$ = Expr\BinaryOp\Div [$1, $3]; } 994 | expr '%' expr { $$ = Expr\BinaryOp\Mod [$1, $3]; } 995 | expr T_SL expr { $$ = Expr\BinaryOp\ShiftLeft [$1, $3]; } 996 | expr T_SR expr { $$ = Expr\BinaryOp\ShiftRight[$1, $3]; } 997 | expr T_POW expr { $$ = Expr\BinaryOp\Pow [$1, $3]; } 998 | '+' expr %prec T_INC { $$ = Expr\UnaryPlus [$2]; } 999 | '-' expr %prec T_INC { $$ = Expr\UnaryMinus[$2]; } 1000 | '!' expr { $$ = Expr\BooleanNot[$2]; } 1001 | '~' expr { $$ = Expr\BitwiseNot[$2]; } 1002 | expr T_IS_IDENTICAL expr { $$ = Expr\BinaryOp\Identical [$1, $3]; } 1003 | expr T_IS_NOT_IDENTICAL expr { $$ = Expr\BinaryOp\NotIdentical [$1, $3]; } 1004 | expr T_IS_EQUAL expr { $$ = Expr\BinaryOp\Equal [$1, $3]; } 1005 | expr T_IS_NOT_EQUAL expr { $$ = Expr\BinaryOp\NotEqual [$1, $3]; } 1006 | expr T_SPACESHIP expr { $$ = Expr\BinaryOp\Spaceship [$1, $3]; } 1007 | expr '<' expr { $$ = Expr\BinaryOp\Smaller [$1, $3]; } 1008 | expr T_IS_SMALLER_OR_EQUAL expr { $$ = Expr\BinaryOp\SmallerOrEqual[$1, $3]; } 1009 | expr '>' expr { $$ = Expr\BinaryOp\Greater [$1, $3]; } 1010 | expr T_IS_GREATER_OR_EQUAL expr { $$ = Expr\BinaryOp\GreaterOrEqual[$1, $3]; } 1011 | expr T_INSTANCEOF class_name_reference { $$ = Expr\Instanceof_[$1, $3]; } 1012 | '(' expr ')' { $$ = $2; } 1013 | expr '?' expr ':' expr { $$ = Expr\Ternary[$1, $3, $5]; } 1014 | expr '?' ':' expr { $$ = Expr\Ternary[$1, null, $4]; } 1015 | expr T_COALESCE expr { $$ = Expr\BinaryOp\Coalesce[$1, $3]; } 1016 | T_ISSET '(' expr_list_allow_comma ')' { $$ = Expr\Isset_[$3]; } 1017 | T_EMPTY '(' expr ')' { $$ = Expr\Empty_[$3]; } 1018 | T_INCLUDE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_INCLUDE]; } 1019 | T_INCLUDE_ONCE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_INCLUDE_ONCE]; } 1020 | T_EVAL '(' expr ')' { $$ = Expr\Eval_[$3]; } 1021 | T_REQUIRE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE]; } 1022 | T_REQUIRE_ONCE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE_ONCE]; } 1023 | T_INT_CAST expr { $$ = Expr\Cast\Int_ [$2]; } 1024 | T_DOUBLE_CAST expr 1025 { $attrs = attributes(); 1026 $attrs['kind'] = $this->getFloatCastKind($1); 1027 $$ = new Expr\Cast\Double($2, $attrs); } 1028 | T_STRING_CAST expr { $$ = Expr\Cast\String_ [$2]; } 1029 | T_ARRAY_CAST expr { $$ = Expr\Cast\Array_ [$2]; } 1030 | T_OBJECT_CAST expr { $$ = Expr\Cast\Object_ [$2]; } 1031 | T_BOOL_CAST expr { $$ = Expr\Cast\Bool_ [$2]; } 1032 | T_UNSET_CAST expr { $$ = Expr\Cast\Unset_ [$2]; } 1033 | T_EXIT exit_expr 1034 { $attrs = attributes(); 1035 $attrs['kind'] = strtolower($1) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE; 1036 $$ = new Expr\Exit_($2, $attrs); } 1037 | '@' expr { $$ = Expr\ErrorSuppress[$2]; } 1038 | scalar 1039 | '`' backticks_expr '`' { $$ = Expr\ShellExec[$2]; } 1040 | T_PRINT expr { $$ = Expr\Print_[$2]; } 1041 | T_YIELD { $$ = Expr\Yield_[null, null]; } 1042 | T_YIELD expr { $$ = Expr\Yield_[$2, null]; } 1043 | T_YIELD expr T_DOUBLE_ARROW expr { $$ = Expr\Yield_[$4, $2]; } 1044 | T_YIELD_FROM expr { $$ = Expr\YieldFrom[$2]; } 1045 | T_THROW expr { $$ = Expr\Throw_[$2]; } 1046 1047 | T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr %prec T_THROW 1048 { $$ = Expr\ArrowFunction[['static' => false, 'byRef' => $2, 'params' => $4, 'returnType' => $6, 'expr' => $8, 'attrGroups' => []]]; } 1049 | T_STATIC T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr %prec T_THROW 1050 { $$ = Expr\ArrowFunction[['static' => true, 'byRef' => $3, 'params' => $5, 'returnType' => $7, 'expr' => $9, 'attrGroups' => []]]; } 1051 | T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error 1052 { $$ = Expr\Closure[['static' => false, 'byRef' => $2, 'params' => $4, 'uses' => $6, 'returnType' => $7, 'stmts' => $8, 'attrGroups' => []]]; } 1053 | T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error 1054 { $$ = Expr\Closure[['static' => true, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => []]]; } 1055 1056 | attributes T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr %prec T_THROW 1057 { $$ = Expr\ArrowFunction[['static' => false, 'byRef' => $3, 'params' => $5, 'returnType' => $7, 'expr' => $9, 'attrGroups' => $1]]; } 1058 | attributes T_STATIC T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr %prec T_THROW 1059 { $$ = Expr\ArrowFunction[['static' => true, 'byRef' => $4, 'params' => $6, 'returnType' => $8, 'expr' => $10, 'attrGroups' => $1]]; } 1060 | attributes T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error 1061 { $$ = Expr\Closure[['static' => false, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => $1]]; } 1062 | attributes T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error 1063 { $$ = Expr\Closure[['static' => true, 'byRef' => $4, 'params' => $6, 'uses' => $8, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]]; } 1064 ; 1065 1066 anonymous_class: 1067 optional_attributes class_entry_type ctor_arguments extends_from implements_list '{' class_statement_list '}' 1068 { $$ = array(Stmt\Class_[null, ['type' => $2, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]], $3); 1069 $this->checkClass($$[0], -1); } 1070 ; 1071 1072 new_expr: 1073 T_NEW class_name_reference ctor_arguments { $$ = Expr\New_[$2, $3]; } 1074 | T_NEW anonymous_class 1075 { list($class, $ctorArgs) = $2; $$ = Expr\New_[$class, $ctorArgs]; } 1076 ; 1077 1078 lexical_vars: 1079 /* empty */ { $$ = array(); } 1080 | T_USE '(' lexical_var_list ')' { $$ = $3; } 1081 ; 1082 1083 lexical_var_list: 1084 non_empty_lexical_var_list optional_comma 1085 ; 1086 1087 non_empty_lexical_var_list: 1088 lexical_var { init($1); } 1089 | non_empty_lexical_var_list ',' lexical_var { push($1, $3); } 1090 ; 1091 1092 lexical_var: 1093 optional_ref plain_variable { $$ = Node\ClosureUse[$2, $1]; } 1094 ; 1095 1096 name_readonly: 1097 T_READONLY { $$ = Name[$1]; } 1098 ; 1099 1100 function_call: 1101 name argument_list { $$ = Expr\FuncCall[$1, $2]; } 1102 | name_readonly argument_list { $$ = Expr\FuncCall[$1, $2]; } 1103 | callable_expr argument_list { $$ = Expr\FuncCall[$1, $2]; } 1104 | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM member_name argument_list 1105 { $$ = Expr\StaticCall[$1, $3, $4]; } 1106 ; 1107 1108 class_name: 1109 T_STATIC { $$ = Name[$1]; } 1110 | name 1111 ; 1112 1113 name: 1114 T_STRING { $$ = Name[$1]; } 1115 | T_NAME_QUALIFIED { $$ = Name[$1]; } 1116 | T_NAME_FULLY_QUALIFIED { $$ = Name\FullyQualified[substr($1, 1)]; } 1117 | T_NAME_RELATIVE { $$ = Name\Relative[substr($1, 10)]; } 1118 ; 1119 1120 class_name_reference: 1121 class_name 1122 | new_variable 1123 | '(' expr ')' { $$ = $2; } 1124 | error { $$ = Expr\Error[]; $this->errorState = 2; } 1125 ; 1126 1127 class_name_or_var: 1128 class_name 1129 | fully_dereferencable 1130 ; 1131 1132 exit_expr: 1133 /* empty */ { $$ = null; } 1134 | '(' optional_expr ')' { $$ = $2; } 1135 ; 1136 1137 backticks_expr: 1138 /* empty */ { $$ = array(); } 1139 | encaps_string_part 1140 { $$ = array($1); parseEncapsed($$, '`', $this->phpVersion->supportsUnicodeEscapes()); } 1141 | encaps_list { parseEncapsed($1, '`', $this->phpVersion->supportsUnicodeEscapes()); $$ = $1; } 1142 ; 1143 1144 ctor_arguments: 1145 /* empty */ { $$ = array(); } 1146 | argument_list 1147 ; 1148 1149 constant: 1150 name { $$ = Expr\ConstFetch[$1]; } 1151 | T_LINE { $$ = Scalar\MagicConst\Line[]; } 1152 | T_FILE { $$ = Scalar\MagicConst\File[]; } 1153 | T_DIR { $$ = Scalar\MagicConst\Dir[]; } 1154 | T_CLASS_C { $$ = Scalar\MagicConst\Class_[]; } 1155 | T_TRAIT_C { $$ = Scalar\MagicConst\Trait_[]; } 1156 | T_METHOD_C { $$ = Scalar\MagicConst\Method[]; } 1157 | T_FUNC_C { $$ = Scalar\MagicConst\Function_[]; } 1158 | T_NS_C { $$ = Scalar\MagicConst\Namespace_[]; } 1159 ; 1160 1161 class_constant: 1162 class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_maybe_reserved 1163 { $$ = Expr\ClassConstFetch[$1, $3]; } 1164 | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}' 1165 { $$ = Expr\ClassConstFetch[$1, $4]; } 1166 /* We interpret an isolated FOO:: as an unfinished class constant fetch. It could also be 1167 an unfinished static property fetch or unfinished scoped call. */ 1168 | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM error 1169 { $$ = Expr\ClassConstFetch[$1, new Expr\Error(stackAttributes(#3))]; $this->errorState = 2; } 1170 ; 1171 1172 array_short_syntax: 1173 '[' array_pair_list ']' 1174 { $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_SHORT; 1175 $$ = new Expr\Array_($2, $attrs); } 1176 ; 1177 1178 dereferencable_scalar: 1179 T_ARRAY '(' array_pair_list ')' 1180 { $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_LONG; 1181 $$ = new Expr\Array_($3, $attrs); 1182 $this->createdArrays->attach($$); } 1183 | array_short_syntax { $$ = $1; $this->createdArrays->attach($$); } 1184 | T_CONSTANT_ENCAPSED_STRING 1185 { $$ = Scalar\String_::fromString($1, attributes(), $this->phpVersion->supportsUnicodeEscapes()); } 1186 | '"' encaps_list '"' 1187 { $attrs = attributes(); $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED; 1188 parseEncapsed($2, '"', $this->phpVersion->supportsUnicodeEscapes()); $$ = new Scalar\InterpolatedString($2, $attrs); } 1189 ; 1190 1191 scalar: 1192 T_LNUMBER 1193 { $$ = $this->parseLNumber($1, attributes(), $this->phpVersion->allowsInvalidOctals()); } 1194 | T_DNUMBER { $$ = Scalar\Float_::fromString($1, attributes()); } 1195 | dereferencable_scalar 1196 | constant 1197 | class_constant 1198 | T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC 1199 { $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), true); } 1200 | T_START_HEREDOC T_END_HEREDOC 1201 { $$ = $this->parseDocString($1, '', $2, attributes(), stackAttributes(#2), true); } 1202 | T_START_HEREDOC encaps_list T_END_HEREDOC 1203 { $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), true); } 1204 ; 1205 1206 optional_expr: 1207 /* empty */ { $$ = null; } 1208 | expr 1209 ; 1210 1211 fully_dereferencable: 1212 variable 1213 | '(' expr ')' { $$ = $2; } 1214 | dereferencable_scalar 1215 | class_constant 1216 ; 1217 1218 array_object_dereferencable: 1219 fully_dereferencable 1220 | constant 1221 ; 1222 1223 callable_expr: 1224 callable_variable 1225 | '(' expr ')' { $$ = $2; } 1226 | dereferencable_scalar 1227 ; 1228 1229 callable_variable: 1230 simple_variable 1231 | array_object_dereferencable '[' optional_expr ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } 1232 | array_object_dereferencable '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; } 1233 | function_call 1234 | array_object_dereferencable T_OBJECT_OPERATOR property_name argument_list 1235 { $$ = Expr\MethodCall[$1, $3, $4]; } 1236 | array_object_dereferencable T_NULLSAFE_OBJECT_OPERATOR property_name argument_list 1237 { $$ = Expr\NullsafeMethodCall[$1, $3, $4]; } 1238 ; 1239 1240 optional_plain_variable: 1241 /* empty */ { $$ = null; } 1242 | plain_variable 1243 ; 1244 1245 variable: 1246 callable_variable 1247 | static_member 1248 | array_object_dereferencable T_OBJECT_OPERATOR property_name 1249 { $$ = Expr\PropertyFetch[$1, $3]; } 1250 | array_object_dereferencable T_NULLSAFE_OBJECT_OPERATOR property_name 1251 { $$ = Expr\NullsafePropertyFetch[$1, $3]; } 1252 ; 1253 1254 simple_variable: 1255 plain_variable 1256 | '$' '{' expr '}' { $$ = Expr\Variable[$3]; } 1257 | '$' simple_variable { $$ = Expr\Variable[$2]; } 1258 | '$' error { $$ = Expr\Variable[Expr\Error[]]; $this->errorState = 2; } 1259 ; 1260 1261 static_member_prop_name: 1262 simple_variable 1263 { $var = $1->name; $$ = \is_string($var) ? Node\VarLikeIdentifier[$var] : $var; } 1264 ; 1265 1266 static_member: 1267 class_name_or_var T_PAAMAYIM_NEKUDOTAYIM static_member_prop_name 1268 { $$ = Expr\StaticPropertyFetch[$1, $3]; } 1269 ; 1270 1271 new_variable: 1272 simple_variable 1273 | new_variable '[' optional_expr ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } 1274 | new_variable '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; } 1275 | new_variable T_OBJECT_OPERATOR property_name { $$ = Expr\PropertyFetch[$1, $3]; } 1276 | new_variable T_NULLSAFE_OBJECT_OPERATOR property_name { $$ = Expr\NullsafePropertyFetch[$1, $3]; } 1277 | class_name T_PAAMAYIM_NEKUDOTAYIM static_member_prop_name 1278 { $$ = Expr\StaticPropertyFetch[$1, $3]; } 1279 | new_variable T_PAAMAYIM_NEKUDOTAYIM static_member_prop_name 1280 { $$ = Expr\StaticPropertyFetch[$1, $3]; } 1281 ; 1282 1283 member_name: 1284 identifier_maybe_reserved 1285 | '{' expr '}' { $$ = $2; } 1286 | simple_variable 1287 ; 1288 1289 property_name: 1290 identifier_not_reserved 1291 | '{' expr '}' { $$ = $2; } 1292 | simple_variable 1293 | error { $$ = Expr\Error[]; $this->errorState = 2; } 1294 ; 1295 1296 list_expr: 1297 T_LIST '(' inner_array_pair_list ')' 1298 { $$ = Expr\List_[$3]; $$->setAttribute('kind', Expr\List_::KIND_LIST); 1299 $this->postprocessList($$); } 1300 ; 1301 1302 array_pair_list: 1303 inner_array_pair_list 1304 { $$ = $1; $end = count($$)-1; if ($$[$end]->value instanceof Expr\Error) array_pop($$); } 1305 ; 1306 1307 comma_or_error: 1308 ',' 1309 | error 1310 { /* do nothing -- prevent default action of $$=$1. See #551. */ } 1311 ; 1312 1313 inner_array_pair_list: 1314 inner_array_pair_list comma_or_error array_pair { push($1, $3); } 1315 | array_pair { init($1); } 1316 ; 1317 1318 array_pair: 1319 expr { $$ = Node\ArrayItem[$1, null, false]; } 1320 | ampersand variable { $$ = Node\ArrayItem[$2, null, true]; } 1321 | list_expr { $$ = Node\ArrayItem[$1, null, false]; } 1322 | expr T_DOUBLE_ARROW expr { $$ = Node\ArrayItem[$3, $1, false]; } 1323 | expr T_DOUBLE_ARROW ampersand variable { $$ = Node\ArrayItem[$4, $1, true]; } 1324 | expr T_DOUBLE_ARROW list_expr { $$ = Node\ArrayItem[$3, $1, false]; } 1325 | T_ELLIPSIS expr { $$ = new Node\ArrayItem($2, null, false, attributes(), true); } 1326 | /* empty */ 1327 { /* Create an Error node now to remember the position. We'll later either report an error, 1328 or convert this into a null element, depending on whether this is a creation or destructuring context. */ 1329 $attrs = $this->createEmptyElemAttributes($this->tokenPos); 1330 $$ = new Node\ArrayItem(new Expr\Error($attrs), null, false, $attrs); } 1331 ; 1332 1333 encaps_list: 1334 encaps_list encaps_var { push($1, $2); } 1335 | encaps_list encaps_string_part { push($1, $2); } 1336 | encaps_var { init($1); } 1337 | encaps_string_part encaps_var { init($1, $2); } 1338 ; 1339 1340 encaps_string_part: 1341 T_ENCAPSED_AND_WHITESPACE 1342 { $attrs = attributes(); $attrs['rawValue'] = $1; $$ = new Node\InterpolatedStringPart($1, $attrs); } 1343 ; 1344 1345 encaps_str_varname: 1346 T_STRING_VARNAME { $$ = Expr\Variable[$1]; } 1347 ; 1348 1349 encaps_var: 1350 plain_variable 1351 | plain_variable '[' encaps_var_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } 1352 | plain_variable T_OBJECT_OPERATOR identifier_not_reserved 1353 { $$ = Expr\PropertyFetch[$1, $3]; } 1354 | plain_variable T_NULLSAFE_OBJECT_OPERATOR identifier_not_reserved 1355 { $$ = Expr\NullsafePropertyFetch[$1, $3]; } 1356 | T_DOLLAR_OPEN_CURLY_BRACES expr '}' { $$ = Expr\Variable[$2]; } 1357 | T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '}' { $$ = Expr\Variable[$2]; } 1358 | T_DOLLAR_OPEN_CURLY_BRACES encaps_str_varname '[' expr ']' '}' 1359 { $$ = Expr\ArrayDimFetch[$2, $4]; } 1360 | T_CURLY_OPEN variable '}' { $$ = $2; } 1361 ; 1362 1363 encaps_var_offset: 1364 T_STRING { $$ = Scalar\String_[$1]; } 1365 | T_NUM_STRING { $$ = $this->parseNumString($1, attributes()); } 1366 | '-' T_NUM_STRING { $$ = $this->parseNumString('-' . $2, attributes()); } 1367 | plain_variable 1368 ; 1369 1370 %% 1371