From 25264267a6cab3dcba815955aae7e7bf302862e1 Mon Sep 17 00:00:00 2001 From: "J.J. Tolton" Date: Sun, 26 Oct 2025 11:40:48 -0400 Subject: [PATCH] Fix parser to reject incomplete reductions like ([ and ({ Fixes #3138 The parser was incorrectly accepting expressions like ([ and ({ as valid syntax, parsing them as atoms instead of rejecting them as incomplete reductions. This fix adds checks in reduce_brackets() to reject when an opening parenthesis is followed by: - Opening bracket [ - Opening curly brace { Note: (, and (( were already correctly rejected by existing checks. This brings the behavior in line with how curly braces work, where {[ and {( correctly produce syntax errors. Added tests in src/tests/syntax_errors.pl to verify the fix and prevent regressions. --- src/parser/parser.rs | 12 ++++++-- src/tests/syntax_errors.pl | 30 +++++++++++++++++++ tests/scryer/cli/src_tests/syntax_errors.toml | 1 + 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/tests/syntax_errors.pl create mode 100644 tests/scryer/cli/src_tests/syntax_errors.toml diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 61e85c7ec..ed578f815 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -829,8 +829,16 @@ impl<'a, R: CharRead> Parser<'a, R> { match td.tt { TokenType::Open | TokenType::OpenCT => { - if self.stack[idx].tt == TokenType::Comma { - return false; + // Reject incomplete reductions like ([ and ({ + // Note: (, is already rejected by checking Comma + // Note: (( is already rejected by the check at line 823 + match self.stack[idx].tt { + TokenType::Comma + | TokenType::OpenList + | TokenType::OpenCurly => { + return false; + } + _ => {} } if let Some(atom) = self.stack[idx].tt.sep_to_atom() { diff --git a/src/tests/syntax_errors.pl b/src/tests/syntax_errors.pl new file mode 100644 index 000000000..1a963269e --- /dev/null +++ b/src/tests/syntax_errors.pl @@ -0,0 +1,30 @@ +:- module(syntax_errors_tests, []). +:- use_module(test_framework). +:- use_module(library(charsio)). + +% Test for issue #3138 - ([) should be a syntax error when reading +test("read of ([). should produce syntax_error", ( + catch( + (read_from_chars("([).", _), false), + error(syntax_error(_), _), + true + ) +)). + +% Test that writeq(([)) produces syntax error when reading +test("read of writeq(([)). should produce syntax_error", ( + catch( + (read_from_chars("writeq(([)).", _), false), + error(syntax_error(_), _), + true + ) +)). + +% Test that ({) should be a syntax error (similar to ([) +test("read of ({). should produce syntax_error", ( + catch( + (read_from_chars("({).", _), false), + error(syntax_error(_), _), + true + ) +)). diff --git a/tests/scryer/cli/src_tests/syntax_errors.toml b/tests/scryer/cli/src_tests/syntax_errors.toml new file mode 100644 index 000000000..f0d0ccafc --- /dev/null +++ b/tests/scryer/cli/src_tests/syntax_errors.toml @@ -0,0 +1 @@ +args = ["-f", "--no-add-history", "src/tests/syntax_errors.pl", "-f", "-g", "use_module(library(syntax_errors_tests)), syntax_errors_tests:main_quiet(syntax_errors_tests)"]