{ $$ = Stmt\Foreach_[$3, $5[0], ['keyVar' => null, 'byRef' => $5[1], 'stmts' => $7]]; }
| T_FOREACH '(' expr T_AS variable T_DOUBLE_ARROW foreach_variable ')' foreach_statement
{ $$ = Stmt\Foreach_[$3, $7[0], ['keyVar' => $5, 'byRef' => $7[1], 'stmts' => $9]]; }
+ | T_FOREACH '(' expr error ')' foreach_statement
+ { $$ = Stmt\Foreach_[$3, new Expr\Error(stackAttributes(#4)), ['stmts' => $6]]; }
| T_DECLARE '(' declare_list ')' declare_statement { $$ = Stmt\Declare_[$3, $5]; }
| T_TRY '{' inner_statement_list '}' catches optional_finally
{ $$ = Stmt\TryCatch[$3, $5, $6]; $this->checkTryCatch($$); }
| T_ELLIPSIS { $$ = true; }
;
+block_or_error:
+ '{' inner_statement_list '}' { $$ = $2; }
+ | error { $$ = []; }
+;
+
function_declaration_statement:
- T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type '{' inner_statement_list '}'
- { $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $9]]; }
+ T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type block_or_error
+ { $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $8]]; }
;
class_declaration_statement:
{ $$ = Node\Param[$4, null, $1, $2, $3]; $this->checkParam($$); }
| optional_param_type optional_ref optional_ellipsis plain_variable '=' expr
{ $$ = Node\Param[$4, $6, $1, $2, $3]; $this->checkParam($$); }
+ | optional_param_type optional_ref optional_ellipsis error
+ { $$ = Node\Param[Expr\Error[], null, $1, $2, $3]; }
;
type_expr:
| plain_variable '=' expr { $$ = Stmt\StaticVar[$1, $3]; }
;
-class_statement_list:
- class_statement_list class_statement { push($1, $2); }
+class_statement_list_ex:
+ class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } }
| /* empty */ { init(); }
;
+class_statement_list:
+ class_statement_list_ex
+ { makeNop($nop, $this->lookaheadStartAttributes, $this->endAttributes);
+ if ($nop !== null) { $1[] = $nop; } $$ = $1; }
+;
+
class_statement:
variable_modifiers property_declaration_list ';'
{ $$ = Stmt\Property[$1, $2]; $this->checkProperty($$, #1); }
{ $$ = Stmt\ClassMethod[$4, ['type' => $1, 'byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9]];
$this->checkClassMethod($$, #1); }
| T_USE class_name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; }
+ | error { $$ = null; /* will be skipped */ }
;
trait_adaptations:
method_body:
';' /* abstract method */ { $$ = null; }
- | '{' inner_statement_list '}' { $$ = $2; }
+ | block_or_error { $$ = $1; }
;
variable_modifiers:
| T_YIELD expr T_DOUBLE_ARROW expr { $$ = Expr\Yield_[$4, $2]; }
| T_YIELD_FROM expr { $$ = Expr\YieldFrom[$2]; }
| T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type
- '{' inner_statement_list '}'
- { $$ = Expr\Closure[['static' => false, 'byRef' => $2, 'params' => $4, 'uses' => $6, 'returnType' => $7, 'stmts' => $9]]; }
+ block_or_error
+ { $$ = Expr\Closure[['static' => false, 'byRef' => $2, 'params' => $4, 'uses' => $6, 'returnType' => $7, 'stmts' => $8]]; }
| T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type
- '{' inner_statement_list '}'
- { $$ = Expr\Closure[['static' => true, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $10]]; }
+ block_or_error
+ { $$ = Expr\Closure[['static' => true, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $9]]; }
;
anonymous_class:
| dereferencable_scalar { $$ = $1; }
| constant { $$ = $1; }
| T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC
- { $attrs = attributes(); setDocStringAttrs($attrs, $1);
- $$ = new Scalar\String_(Scalar\String_::parseDocString($1, $2), $attrs); }
+ { $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), true); }
| T_START_HEREDOC T_END_HEREDOC
- { $attrs = attributes(); setDocStringAttrs($attrs, $1);
- $$ = new Scalar\String_('', $attrs); }
+ { $$ = $this->parseDocString($1, '', $2, attributes(), stackAttributes(#2), true); }
| '"' encaps_list '"'
{ $attrs = attributes(); $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED;
parseEncapsed($2, '"', true); $$ = new Scalar\Encapsed($2, $attrs); }
| T_START_HEREDOC encaps_list T_END_HEREDOC
- { $attrs = attributes(); setDocStringAttrs($attrs, $1);
- parseEncapsedDoc($2, true); $$ = new Scalar\Encapsed($2, $attrs); }
+ { $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), true); }
;
optional_expr:
{ $$ = $1; $end = count($$)-1; if ($$[$end] === null) array_pop($$); }
;
+comma_or_error:
+ ','
+ | error
+;
+
inner_array_pair_list:
- inner_array_pair_list ',' array_pair { push($1, $3); }
+ inner_array_pair_list comma_or_error array_pair { push($1, $3); }
| array_pair { init($1); }
;