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