chrset
chrset

Reputation: 711

ANTLR4 Python in Unittest: how to abort on any error

I want to test my lexer/parser in a Python Unittest. For that purpose I'd like antlr to fail with an Exception everytime anything is out of order. What is the most elegant way to achieve this?

I have read the ANTLR Mega Tutorial, there they write an ErrorListener which overrides syntaxError() to save the last offending symbol and then in the end, they check if any offending symbol was encountered.

I saw that there are different ErrorStrategy classes and BailErrorStrategy sounds like this is what I need. But then I read How can I fail on first syntax error in a python ANTLR generated parser while keeping the error message? which says this strategy doesn't alway throw an Exception.

My best idea so far is to throw an Exception in ErrorListener.syntxError():

import unittest
from antlr4 import *
from antlr.myLexer import myLexer
from antlr.myParser import myParser
from antlr4.error.ErrorListener import ErrorListener


class MyErrorListener(ErrorListener):
    def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
        raise Exception("ERROR: when parsing line %d column %d: %s\n" % \
                        (line, column, msg))


class TestMyParser(unittest.TestCase):
    def test_with_testfile(self):
        error_listener = MyErrorListener()
        input_stream = FileStream("testfile")
        lexer = myLexer(input_stream)
        lexer.removeErrorListeners()
        lexer.addErrorListener(error_listener)
        stream = CommonTokenStream(lexer)
        parser = myParser(stream)
        parser.removeErrorListeners()
        parser.addErrorListener(error_listener)
        tree = parser.startrule()


if __name__ == '__main__':
    unittest.main()

Upvotes: 0

Views: 1296

Answers (1)

Mike Lischke
Mike Lischke

Reputation: 53357

The best option you have is the BailErrorStategy. It uses an exception which is not catched anywhere in the ANTLR4 runtime and hence that bubbles up to your own code directly.

If you use a normal error handler/default strategy it will always try to recover from syntax errors to allow continuing the parse run.

But even with the BailErrorStrategy in place you can have an error listener to get the first (and only) error that came up. For the error messages I recommend attaching your own error listener class to produce your own version of the error message like I did in this C++ code

Upvotes: 1

Related Questions