From dcee5828269352df82ef68b4cd2facb5655b0c49 Mon Sep 17 00:00:00 2001 From: "C.A.P. Linssen" Date: Wed, 11 Dec 2024 13:41:13 +0100 Subject: [PATCH] friendlier lexer and parser error messages --- pynestml/grammars/generate_lexer_parser | 2 +- pynestml/utils/error_listener.py | 4 ++++ pynestml/utils/messages.py | 8 ++++---- pynestml/utils/model_parser.py | 21 ++++++++++++++------- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/pynestml/grammars/generate_lexer_parser b/pynestml/grammars/generate_lexer_parser index 6f695a202..c2248afab 100755 --- a/pynestml/grammars/generate_lexer_parser +++ b/pynestml/grammars/generate_lexer_parser @@ -22,4 +22,4 @@ # Do not change the position of this file! In order to generate the corresponding code into `pynestml/generated`, this script has to be executed from `pynestml/grammars`. -antlr4 -Dlanguage=Python3 *.g4 -visitor -no-listener -o ../generated +antlr4 -encoding UTF8 -Dlanguage=Python3 *.g4 -visitor -no-listener -o ../generated diff --git a/pynestml/utils/error_listener.py b/pynestml/utils/error_listener.py index b4bd4c126..3666949d2 100644 --- a/pynestml/utils/error_listener.py +++ b/pynestml/utils/error_listener.py @@ -36,3 +36,7 @@ def error_occurred(self): def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): self._error_occurred = True + self.offendingSymbol = offendingSymbol + self.line = line + self.column = column + self.msg = msg diff --git a/pynestml/utils/messages.py b/pynestml/utils/messages.py index 9c6157fb4..26fe8d519 100644 --- a/pynestml/utils/messages.py +++ b/pynestml/utils/messages.py @@ -182,8 +182,8 @@ def get_no_code_generated(cls): return MessageCode.NO_CODE_GENERATED, message @classmethod - def get_lexer_error(cls): - message = 'Error occurred during lexing: abort' + def get_lexer_error(cls, msg): + message = 'Error occurred during lexing: ' + msg return MessageCode.LEXER_ERROR, message @classmethod @@ -192,8 +192,8 @@ def get_could_not_determine_cond_based(cls, type_str, name): return MessageCode.LEXER_ERROR, message @classmethod - def get_parser_error(cls): - message = 'Error occurred during parsing: abort' + def get_parser_error(cls, msg): + message = 'Error occurred during parsing: ' + msg return MessageCode.PARSER_ERROR, message @classmethod diff --git a/pynestml/utils/model_parser.py b/pynestml/utils/model_parser.py index 295740809..f05cdf0e1 100644 --- a/pynestml/utils/model_parser.py +++ b/pynestml/utils/model_parser.py @@ -89,7 +89,7 @@ def parse_file(cls, file_path=None): :rtype: ASTNestMLCompilationUnit """ try: - input_file = FileStream(file_path) + input_file = FileStream(file_path, encoding='utf-8') except IOError: code, message = Messages.get_input_path_not_found(path=file_path) Logger.log_message(node=None, code=None, message=message, @@ -101,7 +101,6 @@ def parse_file(cls, file_path=None): # create a lexer and hand over the input lexer = PyNestMLLexer() lexer.removeErrorListeners() - lexer.addErrorListener(ConsoleErrorListener()) lexerErrorListener = NestMLErrorListener() lexer.addErrorListener(lexerErrorListener) lexer._errHandler = BailErrorStrategy() # halt immediately on lexer errors @@ -111,14 +110,18 @@ def parse_file(cls, file_path=None): stream = CommonTokenStream(lexer) stream.fill() if lexerErrorListener._error_occurred: - code, message = Messages.get_lexer_error() + error_location = ASTSourceLocation(lexerErrorListener.line, + lexerErrorListener.column, + lexerErrorListener.line, + lexerErrorListener.column) + code, message = Messages.get_lexer_error(lexerErrorListener.msg) Logger.log_message(node=None, code=None, message=message, - error_position=None, log_level=LoggingLevel.ERROR) + error_position=error_location, log_level=LoggingLevel.ERROR) return + # parse the file parser = PyNestMLParser(None) parser.removeErrorListeners() - parser.addErrorListener(ConsoleErrorListener()) parserErrorListener = NestMLErrorListener() parser.addErrorListener(parserErrorListener) # parser._errHandler = BailErrorStrategy() # N.B. uncomment this line and the next to halt immediately on parse errors @@ -126,9 +129,13 @@ def parse_file(cls, file_path=None): parser.setTokenStream(stream) compilation_unit = parser.nestMLCompilationUnit() if parserErrorListener._error_occurred: - code, message = Messages.get_parser_error() + error_location = ASTSourceLocation(parserErrorListener.line, + parserErrorListener.column, + parserErrorListener.line, + parserErrorListener.column) + code, message = Messages.get_parser_error(parserErrorListener.msg) Logger.log_message(node=None, code=None, message=message, - error_position=None, log_level=LoggingLevel.ERROR) + error_position=error_location, log_level=LoggingLevel.ERROR) return # create a new visitor and return the new AST