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