From 977cbab8e73d69d32cf7a62c91ab932e9d778287 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 25 Jul 2016 17:18:52 +0200 Subject: [PATCH] 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. --- grammar/php5.y | 2 +- grammar/php7.y | 2 +- lib/PhpParser/Parser/Php5.php | 2 +- lib/PhpParser/Parser/Php7.php | 2 +- lib/PhpParser/ParserAbstract.php | 12 ++++++---- test/code/parser/errorHandling/recovery.test | 25 ++++++++++++++++++++ 6 files changed, 36 insertions(+), 9 deletions(-) diff --git a/grammar/php5.y b/grammar/php5.y index 63cfe5d..5f03bf6 100644 --- a/grammar/php5.y +++ b/grammar/php5.y @@ -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: diff --git a/grammar/php7.y b/grammar/php7.y index 3d5b82f..644891f 100644 --- a/grammar/php7.y +++ b/grammar/php7.y @@ -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: diff --git a/lib/PhpParser/Parser/Php5.php b/lib/PhpParser/Parser/Php5.php index ea81688..d1d17e1 100644 --- a/lib/PhpParser/Parser/Php5.php +++ b/lib/PhpParser/Parser/Php5.php @@ -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() { diff --git a/lib/PhpParser/Parser/Php7.php b/lib/PhpParser/Parser/Php7.php index 736d04f..2ddc977 100644 --- a/lib/PhpParser/Parser/Php7.php +++ b/lib/PhpParser/Parser/Php7.php @@ -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() { diff --git a/lib/PhpParser/ParserAbstract.php b/lib/PhpParser/ParserAbstract.php index 88ae05d..bc9559b 100644 --- a/lib/PhpParser/ParserAbstract.php +++ b/lib/PhpParser/ParserAbstract.php @@ -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 (!( diff --git a/test/code/parser/errorHandling/recovery.test b/test/code/parser/errorHandling/recovery.test index 2a602da..e836be4 100644 --- a/test/code/parser/errorHandling/recovery.test +++ b/test/code/parser/errorHandling/recovery.test @@ -254,4 +254,29 @@ array( name: Expr_Error( ) ) +) +----- + +} +----- +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( + ) + ) + ) + ) ) \ No newline at end of file