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