From 2500f20dd6877417d69d37fdf1700f400bb51b34 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 08:11:53 +0000 Subject: [PATCH 1/3] Initial plan From 77bfa8fc764ca16f5c938767f1b9f70c35608e24 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 08:17:01 +0000 Subject: [PATCH 2/3] Initial plan for fixing ANTLR4 error handling Co-authored-by: hzhangxyz <11623447+hzhangxyz@users.noreply.github.com> --- bnf/test_error_listener.mjs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 bnf/test_error_listener.mjs diff --git a/bnf/test_error_listener.mjs b/bnf/test_error_listener.mjs new file mode 100644 index 00000000..3a50a725 --- /dev/null +++ b/bnf/test_error_listener.mjs @@ -0,0 +1,35 @@ +import { InputStream, CommonTokenStream, ErrorListener, BailErrorStrategy } from "antlr4"; +import DspLexer from "./atsds_bnf/DspLexer.js"; +import DspParser from "./atsds_bnf/DspParser.js"; + +// Custom error listener that throws exceptions +class ThrowingErrorListener extends ErrorListener { + syntaxError(recognizer, offendingSymbol, line, column, msg, e) { + throw new Error(`line ${line}:${column} ${msg}`); + } +} + +console.log("Test with BailErrorStrategy and custom error listener:"); +try { + const input = "(a + b -> c"; + const chars = new InputStream(input); + const lexer = new DspLexer(chars); + const tokens = new CommonTokenStream(lexer); + const parser = new DspParser(tokens); + + // Remove default error listeners + parser.removeErrorListeners(); + lexer.removeErrorListeners(); + + // Add our throwing error listener + parser.addErrorListener(new ThrowingErrorListener()); + lexer.addErrorListener(new ThrowingErrorListener()); + + // Use BailErrorStrategy to stop parsing on first error + parser._errHandler = new BailErrorStrategy(); + + const tree = parser.rule_pool(); + console.log("Parsed successfully (should not reach here)"); +} catch (e) { + console.log("Error caught:", e.message); +} From 367151b15cfb847df094a14698d192a4e8a4108b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 08:18:59 +0000 Subject: [PATCH 3/3] Implement error handling for ANTLR4 JS binding Co-authored-by: hzhangxyz <11623447+hzhangxyz@users.noreply.github.com> --- bnf/atsds_bnf/index.mjs | 16 ++++++++++++++- bnf/test_error_listener.mjs | 35 -------------------------------- bnf/tests/test_parse_unparse.mjs | 30 +++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 36 deletions(-) delete mode 100644 bnf/test_error_listener.mjs diff --git a/bnf/atsds_bnf/index.mjs b/bnf/atsds_bnf/index.mjs index 022df339..142e62de 100644 --- a/bnf/atsds_bnf/index.mjs +++ b/bnf/atsds_bnf/index.mjs @@ -1,4 +1,4 @@ -import { InputStream, CommonTokenStream } from "antlr4"; +import { InputStream, CommonTokenStream, ErrorListener } from "antlr4"; import DspLexer from "./DspLexer.js"; import DspParser from "./DspParser.js"; import DspVisitor from "./DspVisitor.js"; @@ -6,6 +6,12 @@ import DsLexer from "./DsLexer.js"; import DsParser from "./DsParser.js"; import DsVisitor from "./DsVisitor.js"; +class ThrowingErrorListener extends ErrorListener { + syntaxError(recognizer, offendingSymbol, line, column, msg, e) { + throw new Error(`line ${line}:${column} ${msg}`); + } +} + class ParseVisitor extends DspVisitor { visitRule_pool(ctx) { return ctx @@ -104,8 +110,12 @@ class UnparseVisitor extends DsVisitor { export function parse(input) { const chars = new InputStream(input); const lexer = new DspLexer(chars); + lexer.removeErrorListeners(); + lexer.addErrorListener(new ThrowingErrorListener()); const tokens = new CommonTokenStream(lexer); const parser = new DspParser(tokens); + parser.removeErrorListeners(); + parser.addErrorListener(new ThrowingErrorListener()); const tree = parser.rule_pool(); const visitor = new ParseVisitor(); return visitor.visit(tree); @@ -114,8 +124,12 @@ export function parse(input) { export function unparse(input) { const chars = new InputStream(input); const lexer = new DsLexer(chars); + lexer.removeErrorListeners(); + lexer.addErrorListener(new ThrowingErrorListener()); const tokens = new CommonTokenStream(lexer); const parser = new DsParser(tokens); + parser.removeErrorListeners(); + parser.addErrorListener(new ThrowingErrorListener()); const tree = parser.rule_pool(); const visitor = new UnparseVisitor(); return visitor.visit(tree); diff --git a/bnf/test_error_listener.mjs b/bnf/test_error_listener.mjs deleted file mode 100644 index 3a50a725..00000000 --- a/bnf/test_error_listener.mjs +++ /dev/null @@ -1,35 +0,0 @@ -import { InputStream, CommonTokenStream, ErrorListener, BailErrorStrategy } from "antlr4"; -import DspLexer from "./atsds_bnf/DspLexer.js"; -import DspParser from "./atsds_bnf/DspParser.js"; - -// Custom error listener that throws exceptions -class ThrowingErrorListener extends ErrorListener { - syntaxError(recognizer, offendingSymbol, line, column, msg, e) { - throw new Error(`line ${line}:${column} ${msg}`); - } -} - -console.log("Test with BailErrorStrategy and custom error listener:"); -try { - const input = "(a + b -> c"; - const chars = new InputStream(input); - const lexer = new DspLexer(chars); - const tokens = new CommonTokenStream(lexer); - const parser = new DspParser(tokens); - - // Remove default error listeners - parser.removeErrorListeners(); - lexer.removeErrorListeners(); - - // Add our throwing error listener - parser.addErrorListener(new ThrowingErrorListener()); - lexer.addErrorListener(new ThrowingErrorListener()); - - // Use BailErrorStrategy to stop parsing on first error - parser._errHandler = new BailErrorStrategy(); - - const tree = parser.rule_pool(); - console.log("Parsed successfully (should not reach here)"); -} catch (e) { - console.log("Error caught:", e.message); -} diff --git a/bnf/tests/test_parse_unparse.mjs b/bnf/tests/test_parse_unparse.mjs index d08de008..a44a27ed 100644 --- a/bnf/tests/test_parse_unparse.mjs +++ b/bnf/tests/test_parse_unparse.mjs @@ -143,3 +143,33 @@ test("roundtrip_unparse_parse", () => { const ds_result = parse(dsp_intermediate); expect(ds_result).toBe(ds_original); }); + +test("parse_error_missing_closing_parenthesis", () => { + // Test that parse throws error on missing closing parenthesis + const dsp_input = "(a + b -> c"; + expect(() => parse(dsp_input)).toThrow(/line 1:7 no viable alternative/); +}); + +test("parse_error_bad_syntax", () => { + // Test that parse throws error on bad syntax + const dsp_input = "a b c -> -> d"; + expect(() => parse(dsp_input)).toThrow(/line 1:2 mismatched input/); +}); + +test("parse_error_malformed_parentheses", () => { + // Test that parse throws error on malformed parentheses + const dsp_input = "()()()"; + expect(() => parse(dsp_input)).toThrow(/line 1:1 no viable alternative/); +}); + +test("unparse_error_incomplete_binary", () => { + // Test that unparse throws error on incomplete binary expression + const ds_input = "(binary"; + expect(() => unparse(ds_input)).toThrow(/line 1:7 mismatched input/); +}); + +test("unparse_error_malformed_function", () => { + // Test that unparse throws error on malformed function + const ds_input = "(function"; + expect(() => unparse(ds_input)).toThrow(/line 1:9 mismatched input/); +});