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