From ff3fc5fed4db951625ab97ffbd27a79dc25d192f Mon Sep 17 00:00:00 2001 From: dpc00 Date: Tue, 29 Sep 2026 11:37:55 -0600 Subject: [PATCH 1/2] Capture the offending token in PHP 8 parse errors PHP 8 reports unexpected tokens as 'unexpected token ";"', 'unexpected identifier "foo"', 'unexpected variable "$x"', ... with double quotes and a description, but the regex only knew the PHP 7 form "unexpected 'foo'". 'near' was therefore never set and the error was drawn at the first character of the line. Accept both quote styles and the optional description. Add tests with messages from 'php -l' on PHP 8.4. Fixes #56 Co-Authored-By: Claude Sonnet 5.5 --- linter.py | 6 +++++- tests/test_regex.py | 50 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/linter.py b/linter.py index c6f8556..99151c7 100644 --- a/linter.py +++ b/linter.py @@ -40,7 +40,11 @@ class PHP(Linter): } regex = ( r'^(?PParse|Fatal) error:\s*' - r'(?P((?:parse|syntax) error,?)?\s*(?:unexpected \'(?P[^\']+)\')?.*) ' + # PHP 7 quotes the token with single quotes (`unexpected 'foo'`), PHP 8 + # with double quotes and a description (`unexpected token ";"`, + # `unexpected identifier "foo"`). + r'(?P((?:parse|syntax) error,?)?\s*' + r'(?:unexpected (?:[a-z-]+(?: [a-z-]+)* )?["\'](?P[^"\']+)["\'])?.*) ' r'(?:in - )?on line (?P\d+)' ) error_stream = util.STREAM_STDOUT diff --git a/tests/test_regex.py b/tests/test_regex.py index bda56d1..b397c6e 100644 --- a/tests/test_regex.py +++ b/tests/test_regex.py @@ -102,3 +102,53 @@ def test_issue_55_message_filter_only_strips_trailing_source(self): 'message': 'Cannot redeclare f() (previously declared in Standard input code:2)', }, ) + + def test_issue_56_php8_quoted_tokens(self): + # PHP 8 writes `unexpected token ";"`, `unexpected identifier "bar"`, ... + self.assertMatch( + 'Parse error: syntax error, unexpected token ";", expecting "]" ' + 'in Standard input code on line 2', + { + 'error': 'Parse', + 'line': 1, + 'message': 'syntax error, unexpected token ";", expecting "]"', + 'near': ';', + }, + ) + + self.assertMatch( + 'Parse error: syntax error, unexpected identifier "bar" in Standard input code on line 2', + { + 'error': 'Parse', + 'line': 1, + 'message': 'syntax error, unexpected identifier "bar"', + 'near': 'bar', + }, + ) + + self.assertMatch( + 'Parse error: syntax error, unexpected variable "$y" in Standard input code on line 2', + {'error': 'Parse', 'line': 1, 'near': '$y'}, + ) + + self.assertMatch( + 'Parse error: syntax error, unexpected integer "2", expecting "," or ";" ' + 'in Standard input code on line 2', + {'error': 'Parse', 'line': 1, 'near': '2'}, + ) + + self.assertMatch( + 'Parse error: syntax error, unexpected double-quoted string "def" ' + 'in Standard input code on line 2', + {'error': 'Parse', 'line': 1, 'near': 'def'}, + ) + + self.assertMatch( + 'Parse error: syntax error, unexpected end of file in Standard input code on line 3', + { + 'error': 'Parse', + 'line': 2, + 'message': 'syntax error, unexpected end of file', + 'near': None, + }, + ) From d616ef0b3bc900b4ddf7ea88580810ea7b380cd0 Mon Sep 17 00:00:00 2001 From: herr kaste Date: Tue, 29 Sep 2026 20:29:44 +0200 Subject: [PATCH 2/2] Preserve opposite quotes inside unexpected tokens Match the closing quote to the opening quote instead of excluding both quote characters from the captured token. Add a PHP 8 parse error where a double-quoted token contains an apostrophe. --- linter.py | 2 +- tests/test_regex.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/linter.py b/linter.py index 99151c7..f71310f 100644 --- a/linter.py +++ b/linter.py @@ -44,7 +44,7 @@ class PHP(Linter): # with double quotes and a description (`unexpected token ";"`, # `unexpected identifier "foo"`). r'(?P((?:parse|syntax) error,?)?\s*' - r'(?:unexpected (?:[a-z-]+(?: [a-z-]+)* )?["\'](?P[^"\']+)["\'])?.*) ' + r'(?:unexpected (?:[a-z-]+(?: [a-z-]+)* )?(?P["\'])(?P.+?)(?P=quote))?.*) ' r'(?:in - )?on line (?P\d+)' ) error_stream = util.STREAM_STDOUT diff --git a/tests/test_regex.py b/tests/test_regex.py index b397c6e..86b9ad3 100644 --- a/tests/test_regex.py +++ b/tests/test_regex.py @@ -143,6 +143,12 @@ def test_issue_56_php8_quoted_tokens(self): {'error': 'Parse', 'line': 1, 'near': 'def'}, ) + self.assertMatch( + 'Parse error: syntax error, unexpected double-quoted string "a\'b", ' + 'expecting "," or ";" in Standard input code on line 1', + {'error': 'Parse', 'line': 0, 'near': "a'b"}, + ) + self.assertMatch( 'Parse error: syntax error, unexpected end of file in Standard input code on line 3', {