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