diff --git a/CHANGELOG.md b/CHANGELOG.md index 29869c0..263b43a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,11 @@ Version 0.9.4-dev ----------------- -Nothing yet. +* Syntax errors now include information on expected tokens and mimic the format of PHP's own (pre 5.4) error messages. + Example: + + Old: Unexpected token T_STATIC on line 1 + New: Syntax error, unexpected T_STATIC, expecting T_STRING or T_NS_SEPARATOR or '{' Version 0.9.3 (22.11.2012) -------------------------- diff --git a/grammar/kmyacc.php.parser b/grammar/kmyacc.php.parser index 3668de1..d95850a 100644 --- a/grammar/kmyacc.php.parser +++ b/grammar/kmyacc.php.parser @@ -304,8 +304,35 @@ class #(-p) $attributeStack[$this->stackPos] = $startAttributes; } else { /* error */ + $expected = array(); + + $base = self::$yybase[$state]; + for ($i = 0; $i < self::TOKEN_MAP_SIZE; ++$i) { + $n = $base + $i; + if ($n >= 0 && $n < self::YYLAST && self::$yycheck[$n] == $i + || $state < self::YY2TBLSTATE + && ($n = self::$yybase[$state + self::YYNLSTATES] + $i) + && $n < self::YYLAST && self::$yycheck[$n] == $i + ) { + if (self::$yyaction[$n] != self::YYUNEXPECTED) { + if (count($expected) == 4) { + /* Too many expected tokens */ + $expected = array(); + break; + } + + $expected[] = self::$terminals[$i]; + } + } + } + + $expectedString = ''; + if ($expected) { + $expectedString = ', expecting ' . implode(' or ', $expected); + } + throw new PHPParser_Error( - 'Unexpected token ' . self::$terminals[$tokenId], + 'Syntax error, unexpected ' . self::$terminals[$tokenId] . $expectedString, $startAttributes['startLine'] ); } diff --git a/lib/PHPParser/Parser.php b/lib/PHPParser/Parser.php index dfabd13..c15afe8 100644 --- a/lib/PHPParser/Parser.php +++ b/lib/PHPParser/Parser.php @@ -1068,8 +1068,35 @@ class PHPParser_Parser $attributeStack[$this->stackPos] = $startAttributes; } else { /* error */ + $expected = array(); + + $base = self::$yybase[$state]; + for ($i = 0; $i < self::TOKEN_MAP_SIZE; ++$i) { + $n = $base + $i; + if ($n >= 0 && $n < self::YYLAST && self::$yycheck[$n] == $i + || $state < self::YY2TBLSTATE + && ($n = self::$yybase[$state + self::YYNLSTATES] + $i) + && $n < self::YYLAST && self::$yycheck[$n] == $i + ) { + if (self::$yyaction[$n] != self::YYUNEXPECTED) { + if (count($expected) == 4) { + /* Too many expected tokens */ + $expected = array(); + break; + } + + $expected[] = self::$terminals[$i]; + } + } + } + + $expectedString = ''; + if ($expected) { + $expectedString = ', expecting ' . implode(' or ', $expected); + } + throw new PHPParser_Error( - 'Unexpected token ' . self::$terminals[$tokenId], + 'Syntax error, unexpected ' . self::$terminals[$tokenId] . $expectedString, $startAttributes['startLine'] ); } diff --git a/test/code/parser/stmt/class/modifier.test-fail b/test/code/parser/stmt/class/modifier.test-fail index 10b6b70..b1bfc72 100644 --- a/test/code/parser/stmt/class/modifier.test-fail +++ b/test/code/parser/stmt/class/modifier.test-fail @@ -26,4 +26,4 @@ Cannot use the final and abstract modifier at the same time on line 1 -----