Reputation: 711
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
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