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)"]