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 semi 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 '}' 270 { $$ = Stmt\GroupUse[$3, $6, $2]; } 271 | T_USE legacy_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}' 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 identifier_maybe_readonly: 468 identifier_not_reserved 469 | T_READONLY { $$ = Node\Identifier[$1]; } 470 ; 471 472 function_declaration_statement: 473 T_FUNCTION optional_ref identifier_maybe_readonly '(' parameter_list ')' optional_return_type block_or_error 474 { $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $8, 'attrGroups' => []]]; } 475 | attributes T_FUNCTION optional_ref identifier_maybe_readonly '(' parameter_list ')' optional_return_type block_or_error 476 { $$ = Stmt\Function_[$4, ['byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => $1]]; } 477 ; 478 479 class_declaration_statement: 480 class_entry_type identifier_not_reserved extends_from implements_list '{' class_statement_list '}' 481 { $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6, 'attrGroups' => []]]; 482 $this->checkClass($$, #2); } 483 | attributes class_entry_type identifier_not_reserved extends_from implements_list '{' class_statement_list '}' 484 { $$ = Stmt\Class_[$3, ['type' => $2, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]]; 485 $this->checkClass($$, #3); } 486 | optional_attributes T_INTERFACE identifier_not_reserved interface_extends_list '{' class_statement_list '}' 487 { $$ = Stmt\Interface_[$3, ['extends' => $4, 'stmts' => $6, 'attrGroups' => $1]]; 488 $this->checkInterface($$, #3); } 489 | optional_attributes T_TRAIT identifier_not_reserved '{' class_statement_list '}' 490 { $$ = Stmt\Trait_[$3, ['stmts' => $5, 'attrGroups' => $1]]; } 491 | optional_attributes T_ENUM identifier_not_reserved enum_scalar_type implements_list '{' class_statement_list '}' 492 { $$ = Stmt\Enum_[$3, ['scalarType' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]]; 493 $this->checkEnum($$, #3); } 494 ; 495 496 enum_scalar_type: 497 /* empty */ { $$ = null; } 498 | ':' type { $$ = $2; } 499 500 enum_case_expr: 501 /* empty */ { $$ = null; } 502 | '=' expr { $$ = $2; } 503 ; 504 505 class_entry_type: 506 T_CLASS { $$ = 0; } 507 | class_modifiers T_CLASS 508 ; 509 510 class_modifiers: 511 class_modifier 512 | class_modifiers class_modifier { $this->checkClassModifier($1, $2, #2); $$ = $1 | $2; } 513 ; 514 515 class_modifier: 516 T_ABSTRACT { $$ = Modifiers::ABSTRACT; } 517 | T_FINAL { $$ = Modifiers::FINAL; } 518 | T_READONLY { $$ = Modifiers::READONLY; } 519 ; 520 521 extends_from: 522 /* empty */ { $$ = null; } 523 | T_EXTENDS class_name { $$ = $2; } 524 ; 525 526 interface_extends_list: 527 /* empty */ { $$ = array(); } 528 | T_EXTENDS class_name_list { $$ = $2; } 529 ; 530 531 implements_list: 532 /* empty */ { $$ = array(); } 533 | T_IMPLEMENTS class_name_list { $$ = $2; } 534 ; 535 536 class_name_list: 537 non_empty_class_name_list no_comma 538 ; 539 540 non_empty_class_name_list: 541 class_name { init($1); } 542 | non_empty_class_name_list ',' class_name { push($1, $3); } 543 ; 544 545 for_statement: 546 blocklike_statement 547 | ':' inner_statement_list T_ENDFOR ';' { $$ = $2; } 548 ; 549 550 foreach_statement: 551 blocklike_statement 552 | ':' inner_statement_list T_ENDFOREACH ';' { $$ = $2; } 553 ; 554 555 declare_statement: 556 non_empty_statement { toBlock($1); } 557 | ';' { $$ = null; } 558 | ':' inner_statement_list T_ENDDECLARE ';' { $$ = $2; } 559 ; 560 561 declare_list: 562 non_empty_declare_list no_comma 563 ; 564 565 non_empty_declare_list: 566 declare_list_element { init($1); } 567 | non_empty_declare_list ',' declare_list_element { push($1, $3); } 568 ; 569 570 declare_list_element: 571 identifier_not_reserved '=' expr { $$ = Node\DeclareItem[$1, $3]; } 572 ; 573 574 switch_case_list: 575 '{' case_list '}' { $$ = $2; } 576 | '{' ';' case_list '}' { $$ = $3; } 577 | ':' case_list T_ENDSWITCH ';' { $$ = $2; } 578 | ':' ';' case_list T_ENDSWITCH ';' { $$ = $3; } 579 ; 580 581 case_list: 582 /* empty */ { init(); } 583 | case_list case { push($1, $2); } 584 ; 585 586 case: 587 T_CASE expr case_separator inner_statement_list_ex { $$ = Stmt\Case_[$2, $4]; } 588 | T_DEFAULT case_separator inner_statement_list_ex { $$ = Stmt\Case_[null, $3]; } 589 ; 590 591 case_separator: 592 ':' 593 | ';' 594 ; 595 596 match: 597 T_MATCH '(' expr ')' '{' match_arm_list '}' { $$ = Expr\Match_[$3, $6]; } 598 ; 599 600 match_arm_list: 601 /* empty */ { $$ = []; } 602 | non_empty_match_arm_list optional_comma 603 ; 604 605 non_empty_match_arm_list: 606 match_arm { init($1); } 607 | non_empty_match_arm_list ',' match_arm { push($1, $3); } 608 ; 609 610 match_arm: 611 expr_list_allow_comma T_DOUBLE_ARROW expr { $$ = Node\MatchArm[$1, $3]; } 612 | T_DEFAULT optional_comma T_DOUBLE_ARROW expr { $$ = Node\MatchArm[null, $4]; } 613 ; 614 615 while_statement: 616 blocklike_statement { $$ = $1; } 617 | ':' inner_statement_list T_ENDWHILE ';' { $$ = $2; } 618 ; 619 620 elseif_list: 621 /* empty */ { init(); } 622 | elseif_list elseif { push($1, $2); } 623 ; 624 625 elseif: 626 T_ELSEIF '(' expr ')' blocklike_statement { $$ = Stmt\ElseIf_[$3, $5]; } 627 ; 628 629 new_elseif_list: 630 /* empty */ { init(); } 631 | new_elseif_list new_elseif { push($1, $2); } 632 ; 633 634 new_elseif: 635 T_ELSEIF '(' expr ')' ':' inner_statement_list 636 { $$ = Stmt\ElseIf_[$3, $6]; $this->fixupAlternativeElse($$); } 637 ; 638 639 else_single: 640 /* empty */ { $$ = null; } 641 | T_ELSE blocklike_statement { $$ = Stmt\Else_[$2]; } 642 ; 643 644 new_else_single: 645 /* empty */ { $$ = null; } 646 | T_ELSE ':' inner_statement_list 647 { $$ = Stmt\Else_[$3]; $this->fixupAlternativeElse($$); } 648 ; 649 650 foreach_variable: 651 variable { $$ = array($1, false); } 652 | ampersand variable { $$ = array($2, true); } 653 | list_expr { $$ = array($1, false); } 654 | array_short_syntax 655 { $$ = array($this->fixupArrayDestructuring($1), false); } 656 ; 657 658 parameter_list: 659 non_empty_parameter_list optional_comma 660 | /* empty */ { $$ = array(); } 661 ; 662 663 non_empty_parameter_list: 664 parameter { init($1); } 665 | non_empty_parameter_list ',' parameter { push($1, $3); } 666 ; 667 668 optional_property_modifiers: 669 /* empty */ { $$ = 0; } 670 | optional_property_modifiers property_modifier 671 { $this->checkModifier($1, $2, #2); $$ = $1 | $2; } 672 ; 673 674 property_modifier: 675 T_PUBLIC { $$ = Modifiers::PUBLIC; } 676 | T_PROTECTED { $$ = Modifiers::PROTECTED; } 677 | T_PRIVATE { $$ = Modifiers::PRIVATE; } 678 | T_PUBLIC_SET { $$ = Modifiers::PUBLIC_SET; } 679 | T_PROTECTED_SET { $$ = Modifiers::PROTECTED_SET; } 680 | T_PRIVATE_SET { $$ = Modifiers::PRIVATE_SET; } 681 | T_READONLY { $$ = Modifiers::READONLY; } 682 ; 683 684 parameter: 685 optional_attributes optional_property_modifiers optional_type_without_static 686 optional_arg_ref optional_ellipsis plain_variable optional_property_hook_list 687 { $$ = new Node\Param($6, null, $3, $4, $5, attributes(), $2, $1, $7); 688 $this->checkParam($$); } 689 | optional_attributes optional_property_modifiers optional_type_without_static 690 optional_arg_ref optional_ellipsis plain_variable '=' expr optional_property_hook_list 691 { $$ = new Node\Param($6, $8, $3, $4, $5, attributes(), $2, $1, $9); 692 $this->checkParam($$); } 693 | optional_attributes optional_property_modifiers optional_type_without_static 694 optional_arg_ref optional_ellipsis error 695 { $$ = new Node\Param(Expr\Error[], null, $3, $4, $5, attributes(), $2, $1); } 696 ; 697 698 type_expr: 699 type 700 | '?' type { $$ = Node\NullableType[$2]; } 701 | union_type { $$ = Node\UnionType[$1]; } 702 | intersection_type 703 ; 704 705 type: 706 type_without_static 707 | T_STATIC { $$ = Node\Name['static']; } 708 ; 709 710 type_without_static: 711 name { $$ = $this->handleBuiltinTypes($1); } 712 | T_ARRAY { $$ = Node\Identifier['array']; } 713 | T_CALLABLE { $$ = Node\Identifier['callable']; } 714 ; 715 716 union_type_element: 717 type 718 | '(' intersection_type ')' { $$ = $2; } 719 ; 720 721 union_type: 722 union_type_element '|' union_type_element { init($1, $3); } 723 | union_type '|' union_type_element { push($1, $3); } 724 ; 725 726 union_type_without_static_element: 727 type_without_static 728 | '(' intersection_type_without_static ')' { $$ = $2; } 729 ; 730 731 union_type_without_static: 732 union_type_without_static_element '|' union_type_without_static_element { init($1, $3); } 733 | union_type_without_static '|' union_type_without_static_element { push($1, $3); } 734 ; 735 736 intersection_type_list: 737 type T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type { init($1, $3); } 738 | intersection_type_list T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type 739 { push($1, $3); } 740 ; 741 742 intersection_type: 743 intersection_type_list { $$ = Node\IntersectionType[$1]; } 744 ; 745 746 intersection_type_without_static_list: 747 type_without_static T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type_without_static 748 { init($1, $3); } 749 | intersection_type_without_static_list T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type_without_static 750 { push($1, $3); } 751 ; 752 753 intersection_type_without_static: 754 intersection_type_without_static_list { $$ = Node\IntersectionType[$1]; } 755 ; 756 757 type_expr_without_static: 758 type_without_static 759 | '?' type_without_static { $$ = Node\NullableType[$2]; } 760 | union_type_without_static { $$ = Node\UnionType[$1]; } 761 | intersection_type_without_static 762 ; 763 764 optional_type_without_static: 765 /* empty */ { $$ = null; } 766 | type_expr_without_static 767 ; 768 769 optional_return_type: 770 /* empty */ { $$ = null; } 771 | ':' type_expr { $$ = $2; } 772 | ':' error { $$ = null; } 773 ; 774 775 argument_list: 776 '(' ')' { $$ = array(); } 777 | '(' non_empty_argument_list optional_comma ')' { $$ = $2; } 778 | '(' variadic_placeholder ')' { init($2); } 779 ; 780 781 variadic_placeholder: 782 T_ELLIPSIS { $$ = Node\VariadicPlaceholder[]; } 783 ; 784 785 non_empty_argument_list: 786 argument { init($1); } 787 | non_empty_argument_list ',' argument { push($1, $3); } 788 ; 789 790 argument: 791 expr { $$ = Node\Arg[$1, false, false]; } 792 | ampersand variable { $$ = Node\Arg[$2, true, false]; } 793 | T_ELLIPSIS expr { $$ = Node\Arg[$2, false, true]; } 794 | identifier_maybe_reserved ':' expr 795 { $$ = new Node\Arg($3, false, false, attributes(), $1); } 796 ; 797 798 global_var_list: 799 non_empty_global_var_list no_comma 800 ; 801 802 non_empty_global_var_list: 803 non_empty_global_var_list ',' global_var { push($1, $3); } 804 | global_var { init($1); } 805 ; 806 807 global_var: 808 simple_variable 809 ; 810 811 static_var_list: 812 non_empty_static_var_list no_comma 813 ; 814 815 non_empty_static_var_list: 816 non_empty_static_var_list ',' static_var { push($1, $3); } 817 | static_var { init($1); } 818 ; 819 820 static_var: 821 plain_variable { $$ = Node\StaticVar[$1, null]; } 822 | plain_variable '=' expr { $$ = Node\StaticVar[$1, $3]; } 823 ; 824 825 class_statement_list_ex: 826 class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } else { $$ = $1; } } 827 | /* empty */ { init(); } 828 ; 829 830 class_statement_list: 831 class_statement_list_ex 832 { makeZeroLengthNop($nop); 833 if ($nop !== null) { $1[] = $nop; } $$ = $1; } 834 ; 835 836 class_statement: 837 optional_attributes variable_modifiers optional_type_without_static property_declaration_list semi 838 { $$ = new Stmt\Property($2, $4, attributes(), $3, $1); } 839 #if PHP8 840 | optional_attributes variable_modifiers optional_type_without_static property_declaration_list '{' property_hook_list '}' 841 { $$ = new Stmt\Property($2, $4, attributes(), $3, $1, $6); 842 $this->checkPropertyHookList($6, #5); } 843 #endif 844 | optional_attributes method_modifiers T_CONST class_const_list semi 845 { $$ = new Stmt\ClassConst($4, $2, attributes(), $1); 846 $this->checkClassConst($$, #2); } 847 | optional_attributes method_modifiers T_CONST type_expr class_const_list semi 848 { $$ = new Stmt\ClassConst($5, $2, attributes(), $1, $4); 849 $this->checkClassConst($$, #2); } 850 | optional_attributes method_modifiers T_FUNCTION optional_ref identifier_maybe_reserved '(' parameter_list ')' 851 optional_return_type method_body 852 { $$ = Stmt\ClassMethod[$5, ['type' => $2, 'byRef' => $4, 'params' => $7, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]]; 853 $this->checkClassMethod($$, #2); } 854 | T_USE class_name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; } 855 | optional_attributes T_CASE identifier_maybe_reserved enum_case_expr semi 856 { $$ = Stmt\EnumCase[$3, $4, $1]; } 857 | error { $$ = null; /* will be skipped */ } 858 ; 859 860 trait_adaptations: 861 ';' { $$ = array(); } 862 | '{' trait_adaptation_list '}' { $$ = $2; } 863 ; 864 865 trait_adaptation_list: 866 /* empty */ { init(); } 867 | trait_adaptation_list trait_adaptation { push($1, $2); } 868 ; 869 870 trait_adaptation: 871 trait_method_reference_fully_qualified T_INSTEADOF class_name_list ';' 872 { $$ = Stmt\TraitUseAdaptation\Precedence[$1[0], $1[1], $3]; } 873 | trait_method_reference T_AS member_modifier identifier_maybe_reserved ';' 874 { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, $4]; } 875 | trait_method_reference T_AS member_modifier ';' 876 { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, null]; } 877 | trait_method_reference T_AS identifier_not_reserved ';' 878 { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; } 879 | trait_method_reference T_AS reserved_non_modifiers_identifier ';' 880 { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; } 881 ; 882 883 trait_method_reference_fully_qualified: 884 name T_PAAMAYIM_NEKUDOTAYIM identifier_maybe_reserved { $$ = array($1, $3); } 885 ; 886 trait_method_reference: 887 trait_method_reference_fully_qualified 888 | identifier_maybe_reserved { $$ = array(null, $1); } 889 ; 890 891 method_body: 892 ';' /* abstract method */ { $$ = null; } 893 | block_or_error 894 ; 895 896 variable_modifiers: 897 non_empty_member_modifiers 898 | T_VAR { $$ = 0; } 899 ; 900 901 method_modifiers: 902 /* empty */ { $$ = 0; } 903 | non_empty_member_modifiers 904 ; 905 906 non_empty_member_modifiers: 907 member_modifier 908 | non_empty_member_modifiers member_modifier { $this->checkModifier($1, $2, #2); $$ = $1 | $2; } 909 ; 910 911 member_modifier: 912 T_PUBLIC { $$ = Modifiers::PUBLIC; } 913 | T_PROTECTED { $$ = Modifiers::PROTECTED; } 914 | T_PRIVATE { $$ = Modifiers::PRIVATE; } 915 | T_PUBLIC_SET { $$ = Modifiers::PUBLIC_SET; } 916 | T_PROTECTED_SET { $$ = Modifiers::PROTECTED_SET; } 917 | T_PRIVATE_SET { $$ = Modifiers::PRIVATE_SET; } 918 | T_STATIC { $$ = Modifiers::STATIC; } 919 | T_ABSTRACT { $$ = Modifiers::ABSTRACT; } 920 | T_FINAL { $$ = Modifiers::FINAL; } 921 | T_READONLY { $$ = Modifiers::READONLY; } 922 ; 923 924 property_declaration_list: 925 non_empty_property_declaration_list no_comma 926 ; 927 928 non_empty_property_declaration_list: 929 property_declaration { init($1); } 930 | non_empty_property_declaration_list ',' property_declaration 931 { push($1, $3); } 932 ; 933 934 property_decl_name: 935 T_VARIABLE { $$ = Node\VarLikeIdentifier[parseVar($1)]; } 936 ; 937 938 property_declaration: 939 property_decl_name { $$ = Node\PropertyItem[$1, null]; } 940 | property_decl_name '=' expr { $$ = Node\PropertyItem[$1, $3]; } 941 ; 942 943 property_hook_list: 944 /* empty */ { $$ = []; } 945 | property_hook_list property_hook { push($1, $2); } 946 ; 947 948 optional_property_hook_list: 949 /* empty */ { $$ = []; } 950 #if PHP8 951 | '{' property_hook_list '}' { $$ = $2; $this->checkPropertyHookList($2, #1); } 952 #endif 953 ; 954 955 property_hook: 956 optional_attributes property_hook_modifiers optional_ref identifier_not_reserved property_hook_body 957 { $$ = Node\PropertyHook[$4, $5, ['flags' => $2, 'byRef' => $3, 'params' => [], 'attrGroups' => $1]]; 958 $this->checkPropertyHook($$, null); } 959 | optional_attributes property_hook_modifiers optional_ref identifier_not_reserved '(' parameter_list ')' property_hook_body 960 { $$ = Node\PropertyHook[$4, $8, ['flags' => $2, 'byRef' => $3, 'params' => $6, 'attrGroups' => $1]]; 961 $this->checkPropertyHook($$, #5); } 962 ; 963 964 property_hook_body: 965 ';' { $$ = null; } 966 | '{' inner_statement_list '}' { $$ = $2; } 967 | T_DOUBLE_ARROW expr ';' { $$ = $2; } 968 ; 969 970 property_hook_modifiers: 971 /* empty */ { $$ = 0; } 972 | property_hook_modifiers member_modifier 973 { $this->checkPropertyHookModifiers($1, $2, #2); $$ = $1 | $2; } 974 ; 975 976 expr_list_forbid_comma: 977 non_empty_expr_list no_comma 978 ; 979 980 expr_list_allow_comma: 981 non_empty_expr_list optional_comma 982 ; 983 984 non_empty_expr_list: 985 non_empty_expr_list ',' expr { push($1, $3); } 986 | expr { init($1); } 987 ; 988 989 for_expr: 990 /* empty */ { $$ = array(); } 991 | expr_list_forbid_comma 992 ; 993 994 expr: 995 variable 996 | list_expr '=' expr { $$ = Expr\Assign[$1, $3]; } 997 | array_short_syntax '=' expr 998 { $$ = Expr\Assign[$this->fixupArrayDestructuring($1), $3]; } 999 | variable '=' expr { $$ = Expr\Assign[$1, $3]; } 1000 | variable '=' ampersand variable { $$ = Expr\AssignRef[$1, $4]; } 1001 | variable '=' ampersand new_expr 1002 { $$ = Expr\AssignRef[$1, $4]; 1003 if (!$this->phpVersion->allowsAssignNewByReference()) { 1004 $this->emitError(new Error('Cannot assign new by reference', attributes())); 1005 } 1006 } 1007 | new_expr 1008 | match 1009 | T_CLONE expr { $$ = Expr\Clone_[$2]; } 1010 | variable T_PLUS_EQUAL expr { $$ = Expr\AssignOp\Plus [$1, $3]; } 1011 | variable T_MINUS_EQUAL expr { $$ = Expr\AssignOp\Minus [$1, $3]; } 1012 | variable T_MUL_EQUAL expr { $$ = Expr\AssignOp\Mul [$1, $3]; } 1013 | variable T_DIV_EQUAL expr { $$ = Expr\AssignOp\Div [$1, $3]; } 1014 | variable T_CONCAT_EQUAL expr { $$ = Expr\AssignOp\Concat [$1, $3]; } 1015 | variable T_MOD_EQUAL expr { $$ = Expr\AssignOp\Mod [$1, $3]; } 1016 | variable T_AND_EQUAL expr { $$ = Expr\AssignOp\BitwiseAnd[$1, $3]; } 1017 | variable T_OR_EQUAL expr { $$ = Expr\AssignOp\BitwiseOr [$1, $3]; } 1018 | variable T_XOR_EQUAL expr { $$ = Expr\AssignOp\BitwiseXor[$1, $3]; } 1019 | variable T_SL_EQUAL expr { $$ = Expr\AssignOp\ShiftLeft [$1, $3]; } 1020 | variable T_SR_EQUAL expr { $$ = Expr\AssignOp\ShiftRight[$1, $3]; } 1021 | variable T_POW_EQUAL expr { $$ = Expr\AssignOp\Pow [$1, $3]; } 1022 | variable T_COALESCE_EQUAL expr { $$ = Expr\AssignOp\Coalesce [$1, $3]; } 1023 | variable T_INC { $$ = Expr\PostInc[$1]; } 1024 | T_INC variable { $$ = Expr\PreInc [$2]; } 1025 | variable T_DEC { $$ = Expr\PostDec[$1]; } 1026 | T_DEC variable { $$ = Expr\PreDec [$2]; } 1027 | expr T_BOOLEAN_OR expr { $$ = Expr\BinaryOp\BooleanOr [$1, $3]; } 1028 | expr T_BOOLEAN_AND expr { $$ = Expr\BinaryOp\BooleanAnd[$1, $3]; } 1029 | expr T_LOGICAL_OR expr { $$ = Expr\BinaryOp\LogicalOr [$1, $3]; } 1030 | expr T_LOGICAL_AND expr { $$ = Expr\BinaryOp\LogicalAnd[$1, $3]; } 1031 | expr T_LOGICAL_XOR expr { $$ = Expr\BinaryOp\LogicalXor[$1, $3]; } 1032 | expr '|' expr { $$ = Expr\BinaryOp\BitwiseOr [$1, $3]; } 1033 | expr T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG expr { $$ = Expr\BinaryOp\BitwiseAnd[$1, $3]; } 1034 | expr T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG expr { $$ = Expr\BinaryOp\BitwiseAnd[$1, $3]; } 1035 | expr '^' expr { $$ = Expr\BinaryOp\BitwiseXor[$1, $3]; } 1036 | expr '.' expr { $$ = Expr\BinaryOp\Concat [$1, $3]; } 1037 | expr '+' expr { $$ = Expr\BinaryOp\Plus [$1, $3]; } 1038 | expr '-' expr { $$ = Expr\BinaryOp\Minus [$1, $3]; } 1039 | expr '*' expr { $$ = Expr\BinaryOp\Mul [$1, $3]; } 1040 | expr '/' expr { $$ = Expr\BinaryOp\Div [$1, $3]; } 1041 | expr '%' expr { $$ = Expr\BinaryOp\Mod [$1, $3]; } 1042 | expr T_SL expr { $$ = Expr\BinaryOp\ShiftLeft [$1, $3]; } 1043 | expr T_SR expr { $$ = Expr\BinaryOp\ShiftRight[$1, $3]; } 1044 | expr T_POW expr { $$ = Expr\BinaryOp\Pow [$1, $3]; } 1045 | '+' expr %prec T_INC { $$ = Expr\UnaryPlus [$2]; } 1046 | '-' expr %prec T_INC { $$ = Expr\UnaryMinus[$2]; } 1047 | '!' expr { $$ = Expr\BooleanNot[$2]; } 1048 | '~' expr { $$ = Expr\BitwiseNot[$2]; } 1049 | expr T_IS_IDENTICAL expr { $$ = Expr\BinaryOp\Identical [$1, $3]; } 1050 | expr T_IS_NOT_IDENTICAL expr { $$ = Expr\BinaryOp\NotIdentical [$1, $3]; } 1051 | expr T_IS_EQUAL expr { $$ = Expr\BinaryOp\Equal [$1, $3]; } 1052 | expr T_IS_NOT_EQUAL expr { $$ = Expr\BinaryOp\NotEqual [$1, $3]; } 1053 | expr T_SPACESHIP expr { $$ = Expr\BinaryOp\Spaceship [$1, $3]; } 1054 | expr '<' expr { $$ = Expr\BinaryOp\Smaller [$1, $3]; } 1055 | expr T_IS_SMALLER_OR_EQUAL expr { $$ = Expr\BinaryOp\SmallerOrEqual[$1, $3]; } 1056 | expr '>' expr { $$ = Expr\BinaryOp\Greater [$1, $3]; } 1057 | expr T_IS_GREATER_OR_EQUAL expr { $$ = Expr\BinaryOp\GreaterOrEqual[$1, $3]; } 1058 | expr T_INSTANCEOF class_name_reference { $$ = Expr\Instanceof_[$1, $3]; } 1059 | '(' expr ')' { $$ = $2; } 1060 | expr '?' expr ':' expr { $$ = Expr\Ternary[$1, $3, $5]; } 1061 | expr '?' ':' expr { $$ = Expr\Ternary[$1, null, $4]; } 1062 | expr T_COALESCE expr { $$ = Expr\BinaryOp\Coalesce[$1, $3]; } 1063 | T_ISSET '(' expr_list_allow_comma ')' { $$ = Expr\Isset_[$3]; } 1064 | T_EMPTY '(' expr ')' { $$ = Expr\Empty_[$3]; } 1065 | T_INCLUDE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_INCLUDE]; } 1066 | T_INCLUDE_ONCE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_INCLUDE_ONCE]; } 1067 | T_EVAL '(' expr ')' { $$ = Expr\Eval_[$3]; } 1068 | T_REQUIRE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE]; } 1069 | T_REQUIRE_ONCE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE_ONCE]; } 1070 | T_INT_CAST expr { $$ = Expr\Cast\Int_ [$2]; } 1071 | T_DOUBLE_CAST expr 1072 { $attrs = attributes(); 1073 $attrs['kind'] = $this->getFloatCastKind($1); 1074 $$ = new Expr\Cast\Double($2, $attrs); } 1075 | T_STRING_CAST expr { $$ = Expr\Cast\String_ [$2]; } 1076 | T_ARRAY_CAST expr { $$ = Expr\Cast\Array_ [$2]; } 1077 | T_OBJECT_CAST expr { $$ = Expr\Cast\Object_ [$2]; } 1078 | T_BOOL_CAST expr { $$ = Expr\Cast\Bool_ [$2]; } 1079 | T_UNSET_CAST expr { $$ = Expr\Cast\Unset_ [$2]; } 1080 | T_EXIT ctor_arguments 1081 { $$ = $this->createExitExpr($1, #1, $2, attributes()); } 1082 | '@' expr { $$ = Expr\ErrorSuppress[$2]; } 1083 | scalar 1084 | '`' backticks_expr '`' { $$ = Expr\ShellExec[$2]; } 1085 | T_PRINT expr { $$ = Expr\Print_[$2]; } 1086 | T_YIELD { $$ = Expr\Yield_[null, null]; } 1087 | T_YIELD expr { $$ = Expr\Yield_[$2, null]; } 1088 | T_YIELD expr T_DOUBLE_ARROW expr { $$ = Expr\Yield_[$4, $2]; } 1089 | T_YIELD_FROM expr { $$ = Expr\YieldFrom[$2]; } 1090 | T_THROW expr { $$ = Expr\Throw_[$2]; } 1091 1092 | T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr %prec T_THROW 1093 { $$ = Expr\ArrowFunction[['static' => false, 'byRef' => $2, 'params' => $4, 'returnType' => $6, 'expr' => $8, 'attrGroups' => []]]; } 1094 | T_STATIC T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr %prec T_THROW 1095 { $$ = Expr\ArrowFunction[['static' => true, 'byRef' => $3, 'params' => $5, 'returnType' => $7, 'expr' => $9, 'attrGroups' => []]]; } 1096 | T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error 1097 { $$ = Expr\Closure[['static' => false, 'byRef' => $2, 'params' => $4, 'uses' => $6, 'returnType' => $7, 'stmts' => $8, 'attrGroups' => []]]; } 1098 | T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error 1099 { $$ = Expr\Closure[['static' => true, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => []]]; } 1100 1101 | attributes T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr %prec T_THROW 1102 { $$ = Expr\ArrowFunction[['static' => false, 'byRef' => $3, 'params' => $5, 'returnType' => $7, 'expr' => $9, 'attrGroups' => $1]]; } 1103 | attributes T_STATIC T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr %prec T_THROW 1104 { $$ = Expr\ArrowFunction[['static' => true, 'byRef' => $4, 'params' => $6, 'returnType' => $8, 'expr' => $10, 'attrGroups' => $1]]; } 1105 | attributes T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error 1106 { $$ = Expr\Closure[['static' => false, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => $1]]; } 1107 | attributes T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error 1108 { $$ = Expr\Closure[['static' => true, 'byRef' => $4, 'params' => $6, 'uses' => $8, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]]; } 1109 ; 1110 1111 anonymous_class: 1112 optional_attributes class_entry_type ctor_arguments extends_from implements_list '{' class_statement_list '}' 1113 { $$ = array(Stmt\Class_[null, ['type' => $2, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]], $3); 1114 $this->checkClass($$[0], -1); } 1115 ; 1116 1117 new_dereferenceable: 1118 T_NEW class_name_reference argument_list { $$ = Expr\New_[$2, $3]; } 1119 | T_NEW anonymous_class 1120 { list($class, $ctorArgs) = $2; $$ = Expr\New_[$class, $ctorArgs]; } 1121 ; 1122 1123 new_non_dereferenceable: 1124 T_NEW class_name_reference { $$ = Expr\New_[$2, []]; } 1125 ; 1126 1127 new_expr: 1128 new_dereferenceable 1129 | new_non_dereferenceable 1130 ; 1131 1132 lexical_vars: 1133 /* empty */ { $$ = array(); } 1134 | T_USE '(' lexical_var_list ')' { $$ = $3; } 1135 ; 1136 1137 lexical_var_list: 1138 non_empty_lexical_var_list optional_comma 1139 ; 1140 1141 non_empty_lexical_var_list: 1142 lexical_var { init($1); } 1143 | non_empty_lexical_var_list ',' lexical_var { push($1, $3); } 1144 ; 1145 1146 lexical_var: 1147 optional_ref plain_variable { $$ = Node\ClosureUse[$2, $1]; } 1148 ; 1149 1150 name_readonly: 1151 T_READONLY { $$ = Name[$1]; } 1152 ; 1153 1154 function_call: 1155 name argument_list { $$ = Expr\FuncCall[$1, $2]; } 1156 | name_readonly argument_list { $$ = Expr\FuncCall[$1, $2]; } 1157 | callable_expr argument_list { $$ = Expr\FuncCall[$1, $2]; } 1158 | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM member_name argument_list 1159 { $$ = Expr\StaticCall[$1, $3, $4]; } 1160 ; 1161 1162 class_name: 1163 T_STATIC { $$ = Name[$1]; } 1164 | name 1165 ; 1166 1167 name: 1168 T_STRING { $$ = Name[$1]; } 1169 | T_NAME_QUALIFIED { $$ = Name[$1]; } 1170 | T_NAME_FULLY_QUALIFIED { $$ = Name\FullyQualified[substr($1, 1)]; } 1171 | T_NAME_RELATIVE { $$ = Name\Relative[substr($1, 10)]; } 1172 ; 1173 1174 class_name_reference: 1175 class_name 1176 | new_variable 1177 | '(' expr ')' { $$ = $2; } 1178 | error { $$ = Expr\Error[]; $this->errorState = 2; } 1179 ; 1180 1181 class_name_or_var: 1182 class_name 1183 | fully_dereferenceable 1184 ; 1185 1186 backticks_expr: 1187 /* empty */ { $$ = array(); } 1188 | encaps_string_part 1189 { $$ = array($1); parseEncapsed($$, '`', $this->phpVersion->supportsUnicodeEscapes()); } 1190 | encaps_list { parseEncapsed($1, '`', $this->phpVersion->supportsUnicodeEscapes()); $$ = $1; } 1191 ; 1192 1193 ctor_arguments: 1194 /* empty */ { $$ = array(); } 1195 | argument_list 1196 ; 1197 1198 constant: 1199 name { $$ = Expr\ConstFetch[$1]; } 1200 | T_LINE { $$ = Scalar\MagicConst\Line[]; } 1201 | T_FILE { $$ = Scalar\MagicConst\File[]; } 1202 | T_DIR { $$ = Scalar\MagicConst\Dir[]; } 1203 | T_CLASS_C { $$ = Scalar\MagicConst\Class_[]; } 1204 | T_TRAIT_C { $$ = Scalar\MagicConst\Trait_[]; } 1205 | T_METHOD_C { $$ = Scalar\MagicConst\Method[]; } 1206 | T_FUNC_C { $$ = Scalar\MagicConst\Function_[]; } 1207 | T_NS_C { $$ = Scalar\MagicConst\Namespace_[]; } 1208 | T_PROPERTY_C { $$ = Scalar\MagicConst\Property[]; } 1209 ; 1210 1211 class_constant: 1212 class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_maybe_reserved 1213 { $$ = Expr\ClassConstFetch[$1, $3]; } 1214 | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}' 1215 { $$ = Expr\ClassConstFetch[$1, $4]; } 1216 /* We interpret an isolated FOO:: as an unfinished class constant fetch. It could also be 1217 an unfinished static property fetch or unfinished scoped call. */ 1218 | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM error 1219 { $$ = Expr\ClassConstFetch[$1, new Expr\Error(stackAttributes(#3))]; $this->errorState = 2; } 1220 ; 1221 1222 array_short_syntax: 1223 '[' array_pair_list ']' 1224 { $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_SHORT; 1225 $$ = new Expr\Array_($2, $attrs); } 1226 ; 1227 1228 dereferenceable_scalar: 1229 T_ARRAY '(' array_pair_list ')' 1230 { $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_LONG; 1231 $$ = new Expr\Array_($3, $attrs); 1232 $this->createdArrays->attach($$); } 1233 | array_short_syntax { $$ = $1; $this->createdArrays->attach($$); } 1234 | T_CONSTANT_ENCAPSED_STRING 1235 { $$ = Scalar\String_::fromString($1, attributes(), $this->phpVersion->supportsUnicodeEscapes()); } 1236 | '"' encaps_list '"' 1237 { $attrs = attributes(); $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED; 1238 parseEncapsed($2, '"', $this->phpVersion->supportsUnicodeEscapes()); $$ = new Scalar\InterpolatedString($2, $attrs); } 1239 ; 1240 1241 scalar: 1242 T_LNUMBER 1243 { $$ = $this->parseLNumber($1, attributes(), $this->phpVersion->allowsInvalidOctals()); } 1244 | T_DNUMBER { $$ = Scalar\Float_::fromString($1, attributes()); } 1245 | dereferenceable_scalar 1246 | constant 1247 | class_constant 1248 | T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC 1249 { $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), true); } 1250 | T_START_HEREDOC T_END_HEREDOC 1251 { $$ = $this->parseDocString($1, '', $2, attributes(), stackAttributes(#2), true); } 1252 | T_START_HEREDOC encaps_list T_END_HEREDOC 1253 { $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), true); } 1254 ; 1255 1256 optional_expr: 1257 /* empty */ { $$ = null; } 1258 | expr 1259 ; 1260 1261 fully_dereferenceable: 1262 variable 1263 | '(' expr ')' { $$ = $2; } 1264 | dereferenceable_scalar 1265 | class_constant 1266 | new_dereferenceable 1267 ; 1268 1269 array_object_dereferenceable: 1270 fully_dereferenceable 1271 | constant 1272 ; 1273 1274 callable_expr: 1275 callable_variable 1276 | '(' expr ')' { $$ = $2; } 1277 | dereferenceable_scalar 1278 | new_dereferenceable 1279 ; 1280 1281 callable_variable: 1282 simple_variable 1283 | array_object_dereferenceable '[' optional_expr ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } 1284 #if PHP7 1285 | array_object_dereferenceable '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; } 1286 #endif 1287 | function_call 1288 | array_object_dereferenceable T_OBJECT_OPERATOR property_name argument_list 1289 { $$ = Expr\MethodCall[$1, $3, $4]; } 1290 | array_object_dereferenceable T_NULLSAFE_OBJECT_OPERATOR property_name argument_list 1291 { $$ = Expr\NullsafeMethodCall[$1, $3, $4]; } 1292 ; 1293 1294 optional_plain_variable: 1295 /* empty */ { $$ = null; } 1296 | plain_variable 1297 ; 1298 1299 variable: 1300 callable_variable 1301 | static_member 1302 | array_object_dereferenceable T_OBJECT_OPERATOR property_name 1303 { $$ = Expr\PropertyFetch[$1, $3]; } 1304 | array_object_dereferenceable T_NULLSAFE_OBJECT_OPERATOR property_name 1305 { $$ = Expr\NullsafePropertyFetch[$1, $3]; } 1306 ; 1307 1308 simple_variable: 1309 plain_variable 1310 | '$' '{' expr '}' { $$ = Expr\Variable[$3]; } 1311 | '$' simple_variable { $$ = Expr\Variable[$2]; } 1312 | '$' error { $$ = Expr\Variable[Expr\Error[]]; $this->errorState = 2; } 1313 ; 1314 1315 static_member_prop_name: 1316 simple_variable 1317 { $var = $1->name; $$ = \is_string($var) ? Node\VarLikeIdentifier[$var] : $var; } 1318 ; 1319 1320 static_member: 1321 class_name_or_var T_PAAMAYIM_NEKUDOTAYIM static_member_prop_name 1322 { $$ = Expr\StaticPropertyFetch[$1, $3]; } 1323 ; 1324 1325 new_variable: 1326 simple_variable 1327 | new_variable '[' optional_expr ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } 1328 #if PHP7 1329 | new_variable '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; } 1330 #endif 1331 | new_variable T_OBJECT_OPERATOR property_name { $$ = Expr\PropertyFetch[$1, $3]; } 1332 | new_variable T_NULLSAFE_OBJECT_OPERATOR property_name { $$ = Expr\NullsafePropertyFetch[$1, $3]; } 1333 | class_name T_PAAMAYIM_NEKUDOTAYIM static_member_prop_name 1334 { $$ = Expr\StaticPropertyFetch[$1, $3]; } 1335 | new_variable T_PAAMAYIM_NEKUDOTAYIM static_member_prop_name 1336 { $$ = Expr\StaticPropertyFetch[$1, $3]; } 1337 ; 1338 1339 member_name: 1340 identifier_maybe_reserved 1341 | '{' expr '}' { $$ = $2; } 1342 | simple_variable 1343 ; 1344 1345 property_name: 1346 identifier_not_reserved 1347 | '{' expr '}' { $$ = $2; } 1348 | simple_variable 1349 | error { $$ = Expr\Error[]; $this->errorState = 2; } 1350 ; 1351 1352 list_expr: 1353 T_LIST '(' inner_array_pair_list ')' 1354 { $$ = Expr\List_[$3]; $$->setAttribute('kind', Expr\List_::KIND_LIST); 1355 $this->postprocessList($$); } 1356 ; 1357 1358 array_pair_list: 1359 inner_array_pair_list 1360 { $$ = $1; $end = count($$)-1; if ($$[$end]->value instanceof Expr\Error) array_pop($$); } 1361 ; 1362 1363 comma_or_error: 1364 ',' 1365 | error 1366 { /* do nothing -- prevent default action of $$=$1. See #551. */ } 1367 ; 1368 1369 inner_array_pair_list: 1370 inner_array_pair_list comma_or_error array_pair { push($1, $3); } 1371 | array_pair { init($1); } 1372 ; 1373 1374 array_pair: 1375 expr { $$ = Node\ArrayItem[$1, null, false]; } 1376 | ampersand variable { $$ = Node\ArrayItem[$2, null, true]; } 1377 | list_expr { $$ = Node\ArrayItem[$1, null, false]; } 1378 | expr T_DOUBLE_ARROW expr { $$ = Node\ArrayItem[$3, $1, false]; } 1379 | expr T_DOUBLE_ARROW ampersand variable { $$ = Node\ArrayItem[$4, $1, true]; } 1380 | expr T_DOUBLE_ARROW list_expr { $$ = Node\ArrayItem[$3, $1, false]; } 1381 | T_ELLIPSIS expr { $$ = new Node\ArrayItem($2, null, false, attributes(), true); } 1382 | /* empty */ 1383 { /* Create an Error node now to remember the position. We'll later either report an error, 1384 or convert this into a null element, depending on whether this is a creation or destructuring context. */ 1385 $attrs = $this->createEmptyElemAttributes($this->tokenPos); 1386 $$ = new Node\ArrayItem(new Expr\Error($attrs), null, false, $attrs); } 1387 ; 1388 1389 encaps_list: 1390 encaps_list encaps_var { push($1, $2); } 1391 | encaps_list encaps_string_part { push($1, $2); } 1392 | encaps_var { init($1); } 1393 | encaps_string_part encaps_var { init($1, $2); } 1394 ; 1395 1396 encaps_string_part: 1397 T_ENCAPSED_AND_WHITESPACE 1398 { $attrs = attributes(); $attrs['rawValue'] = $1; $$ = new Node\InterpolatedStringPart($1, $attrs); } 1399 ; 1400 1401 encaps_str_varname: 1402 T_STRING_VARNAME { $$ = Expr\Variable[$1]; } 1403 ; 1404 1405 encaps_var: 1406 plain_variable 1407 | plain_variable '[' encaps_var_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } 1408 | plain_variable T_OBJECT_OPERATOR identifier_not_reserved 1409 { $$ = Expr\PropertyFetch[$1, $3]; } 1410 | plain_variable T_NULLSAFE_OBJECT_OPERATOR identifier_not_reserved 1411 { $$ = Expr\NullsafePropertyFetch[$1, $3]; } 1412 | T_DOLLAR_OPEN_CURLY_BRACES expr '}' { $$ = Expr\Variable[$2]; } 1413 | T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '}' { $$ = Expr\Variable[$2]; } 1414 | T_DOLLAR_OPEN_CURLY_BRACES encaps_str_varname '[' expr ']' '}' 1415 { $$ = Expr\ArrayDimFetch[$2, $4]; } 1416 | T_CURLY_OPEN variable '}' { $$ = $2; } 1417 ; 1418 1419 encaps_var_offset: 1420 T_STRING { $$ = Scalar\String_[$1]; } 1421 | T_NUM_STRING { $$ = $this->parseNumString($1, attributes()); } 1422 | '-' T_NUM_STRING { $$ = $this->parseNumString('-' . $2, attributes()); } 1423 | plain_variable 1424 ; 1425 1426 %% 1427