Decrement errorState when recovering from -> error

It's likely that an error after -> will trigger another one due to
missing semicolon without shifting a single token. We prevent an
immediate failure in this case by manually setting errorState to 2,
which will suppress the duplicate error message, but allow error
recovery.
This commit is contained in:
Nikita Popov 2016-07-25 17:18:52 +02:00
parent 09086fbe0a
commit 977cbab8e7
6 changed files with 36 additions and 9 deletions

View File

@ -915,7 +915,7 @@ object_property:
T_STRING { $$ = $1; }
| '{' expr '}' { $$ = $2; }
| variable_without_objects { $$ = $1; }
| error { $$ = Expr\Error[]; }
| error { $$ = Expr\Error[]; $this->errorState = 2; }
;
list_expr:

View File

@ -793,7 +793,7 @@ property_name:
T_STRING { $$ = $1; }
| '{' expr '}' { $$ = $2; }
| simple_variable { $$ = Expr\Variable[$1]; }
| error { $$ = Expr\Error[]; }
| error { $$ = Expr\Error[]; $this->errorState = 2; }
;
list_expr:

View File

@ -3009,7 +3009,7 @@ class Php5 extends \PhpParser\ParserAbstract
}
protected function reduceRule518() {
$this->semValue = new Expr\Error($this->startAttributeStack[$this->stackPos-(1-1)] + $this->endAttributes);
$this->semValue = new Expr\Error($this->startAttributeStack[$this->stackPos-(1-1)] + $this->endAttributes); $this->errorState = 2;
}
protected function reduceRule519() {

View File

@ -2619,7 +2619,7 @@ class Php7 extends \PhpParser\ParserAbstract
}
protected function reduceRule453() {
$this->semValue = new Expr\Error($this->startAttributeStack[$this->stackPos-(1-1)] + $this->endAttributes);
$this->semValue = new Expr\Error($this->startAttributeStack[$this->stackPos-(1-1)] + $this->endAttributes); $this->errorState = 2;
}
protected function reduceRule454() {

View File

@ -95,6 +95,8 @@ abstract class ParserAbstract implements Parser
protected $throwOnError;
/** @var Error[] Errors collected during last parse */
protected $errors;
/** @var int Error state, used to avoid error floods */
protected $errorState;
/**
* Creates a parser instance.
@ -157,7 +159,7 @@ abstract class ParserAbstract implements Parser
// Current position in the stack(s)
$this->stackPos = 0;
$errorState = 0;
$this->errorState = 0;
for (;;) {
//$this->traceNewState($state, $symbol);
@ -216,8 +218,8 @@ abstract class ParserAbstract implements Parser
$this->endAttributes = $endAttributes;
$symbol = self::SYMBOL_NONE;
if ($errorState) {
--$errorState;
if ($this->errorState) {
--$this->errorState;
}
if ($action < $this->YYNLSTATES) {
@ -274,7 +276,7 @@ abstract class ParserAbstract implements Parser
$this->semStack[$this->stackPos] = $this->semValue;
} else {
/* error */
switch ($errorState) {
switch ($this->errorState) {
case 0:
$msg = $this->getErrorMessage($symbol, $state);
$error = new Error($msg, $startAttributes + $endAttributes);
@ -285,7 +287,7 @@ abstract class ParserAbstract implements Parser
// Break missing intentionally
case 1:
case 2:
$errorState = 3;
$this->errorState = 3;
// Pop until error-expecting state uncovered
while (!(

View File

@ -254,4 +254,29 @@ array(
name: Expr_Error(
)
)
)
-----
<?php
function foo() {
$bar->
}
-----
Syntax error, unexpected '}' from 4:1 to 4:1
array(
0: Stmt_Function(
byRef: false
name: foo
params: array(
)
returnType: null
stmts: array(
0: Expr_PropertyFetch(
var: Expr_Variable(
name: bar
)
name: Expr_Error(
)
)
)
)
)