In January 2021 we will introduce a 10 GB quota for project repositories. Higher limits for individual projects will be available on request. Please see https://doku.lrz.de/display/PUBLIC/GitLab for more information.

Commit 43cb9807 authored by Eckhart Arnold's avatar Eckhart Arnold

- error handling simplified

parent cc2ade10
......@@ -511,7 +511,7 @@ class EBNFCompiler(Compiler):
if entry not in symbols and not entry.startswith(":"):
messages.append(Error(('Symbol "%s" is not defined in grammar %s but appears in '
'the transformation table!') % (entry, self.grammar_name),
Error.UNDEFINED_SYMBOL_IN_TRANSFORMATION_TABLE, 0))
0, Error.UNDEFINED_SYMBOL_IN_TRANSFORMATION_TABLE))
return messages
......
......@@ -41,9 +41,10 @@ import bisect
from DHParser.preprocess import SourceMapFunc
from DHParser.stringview import StringView
from DHParser.toolkit import typing
from typing import Iterable, Iterator, Union, Tuple, List, Optional
from typing import Iterable, Iterator, Union, Tuple, List, NewType
__all__ = ('Error',
__all__ = ('ErrorCode',
'Error',
'is_error',
'is_warning',
'has_errors',
......@@ -53,44 +54,44 @@ __all__ = ('Error',
'adjust_error_locations')
class ErrorCode(int):
pass
class Error:
__slots__ = ['message', 'level', 'code', '_pos', 'orig_pos', 'line', 'column', '_node_keep']
# error levels
NO_ERROR = 0
MESSAGE = 1
WARNING = 10
ERROR = 1000
NO_ERROR = ErrorCode(0)
MESSAGE = ErrorCode(1)
WARNING = ErrorCode(10)
ERROR = ErrorCode(1000)
HIGHEST = ERROR
# warning codes
REDEFINED_DIRECTIVE_WARNING = 101
REDECLARED_TOKEN_WARNING = 102
REDEFINED_DIRECTIVE_WARNING = ErrorCode(101)
REDECLARED_TOKEN_WARNING = ErrorCode(102)
UNDEFINED_SYMBOL_IN_TRANSFORMATION_TABLE = 601
UNDEFINED_SYMBOL_IN_TRANSFORMATION_TABLE = ErrorCode(601)
# error codes
MANDATORY_CONTINUATION = 1001
MANDATORY_CONTINUATION = ErrorCode(1001)
def __init__(self, message: str, code: int = ERROR, pos: int = -1,
orig_pos: int = -1, line: int = -1, column: int = -1,
node: Optional['Node'] = None) -> None:
self.message = message
def __init__(self, message: str, pos, code: ErrorCode = ERROR,
orig_pos: int = -1, line: int = -1, column: int = -1) -> None:
assert isinstance(code, ErrorCode)
assert not isinstance(pos, ErrorCode)
assert pos >= 0
assert code >= 0
self.code = code
self.message = message
self._pos = pos
self.code = code
self.orig_pos = orig_pos
self.line = line
self.column = column
if node is not None and node._pos >= 0:
assert self._pos < 0 or self._pos == node._pos
self._pos = node._pos
self._node_keep = None # if node is not needed, if pos has been set
else:
self._node_keep = node # redundant: consider removing, see RootNode.collect_errors
def __str__(self):
prefix = ''
......@@ -104,10 +105,6 @@ class Error:
@property
def pos(self):
if self._pos < 0:
assert self._node_keep and self._node_keep.pos >= 0, "pos value not ready yet"
self._pos = self._node_keep.pos # lazy evaluation of position
self._node_keep = None # forget node to allow GC to free memory
return self._pos
@property
......
......@@ -1258,9 +1258,9 @@ class ZeroOrMore(Option):
if not node:
break
if len(text) == n:
node.errors.append(Error("Infinite loop!", Error.MESSAGE, node=node))
node.errors.append(Error("Infinite loop!", node.pos, Error.MESSAGE))
infinite_loop_error = Error(dsl_error_msg(self, 'Infinite Loop encountered.'),
node=node)
node.pos)
results += (node,)
node = Node(self, results)
if infinite_loop_error:
......@@ -1308,9 +1308,9 @@ class OneOrMore(UnaryOperator):
if not node:
break
if len(text_) == n:
node.errors.append(Error("Infinite loop!", Error.MESSAGE, node=node))
node.errors.append(Error("Infinite loop!", node.pos, Error.MESSAGE))
infinite_loop_error = Error(dsl_error_msg(self, 'Infinite Loop encountered.'),
node=node)
node.pos)
results += (node,)
if results == ():
return None, text
......@@ -1375,11 +1375,11 @@ class Series(NaryOperator):
location = self.grammar.document_length__ - len(text_)
node = Node(self, text_[:i]).init_pos(location)
node.errors.append(Error("§ %s violation" % parser.repr,
Error.MESSAGE, location))
location, Error.MESSAGE))
if not mandatory_violation:
msg = '%s expected, "%s" found!' \
% (parser.repr, text_[:10].replace('\n', '\\n '))
mandatory_violation = Error(msg, Error.MANDATORY_CONTINUATION, location)
mandatory_violation = Error(msg, location, Error.MANDATORY_CONTINUATION)
text_ = text_[i:]
results += (node,)
# if node.error_flag: # break on first error
......
......@@ -274,7 +274,9 @@ class Node(collections.abc.Sized):
def __str__(self):
s = "".join(str(child) for child in self.children) if self.children else self.content
# s = self._content if self._content is not None else \
# "".join(str(child) for child in self.children) if self.children else self.content
s = self.content
if self.errors:
return ' <<< Error on "%s" | %s >>> ' % \
(s, '; '.join(e.message for e in self.errors))
......@@ -548,8 +550,6 @@ class Node(collections.abc.Sized):
txt.extend(' `(%s "%s")' % (k, v) for k, v in node.attributes.items())
if src:
txt.append(" `(pos %i %i %i)" % (node.pos, *line_col(lbreaks, node.pos)))
# if node.error_flag: # just for debugging error collecting
# txt += " HAS ERRORS"
if showerrors and node.errors:
txt.append(" `(err `%s)" % ' '.join(str(err) for err in node.errors))
return "".join(txt) + '\n'
......@@ -568,7 +568,7 @@ class Node(collections.abc.Sized):
def as_xml(self, src: str = None, showerrors: bool = True, indentation: int = 2,
inline_tags: Set[str]=set(), omit_tags: Set[str]=set(), ) -> str:
inline_tags: Set[str]=set(), omit_tags: Set[str]=set()) -> str:
"""
Returns content as XML-tree.
......@@ -703,7 +703,7 @@ class Node(collections.abc.Sized):
class RootNode(Node):
"""TODO: Add Documentation!!!
errors (list): A list of all errors that have occured so far during
all_errors (list): A list of all errors that have occured so far during
processing (i.e. parsing, AST-transformation, compiling)
of this tree.
......@@ -713,7 +713,6 @@ class RootNode(Node):
def __init__(self, node: Optional[Node] = None) -> 'RootNode':
super().__init__(ZOMBIE_PARSER, '')
self.all_errors = []
self.err_nodes_keep = []
self.error_flag = 0
if node is not None:
self.swallow(node)
......@@ -744,7 +743,6 @@ class RootNode(Node):
self.all_errors.append(error)
self.error_flag = max(self.error_flag, error.code)
node.errors.append(error)
self.err_nodes_keep.append(node)
return self
def new_error(self,
......@@ -758,27 +756,15 @@ class RootNode(Node):
message(str): A string with the error message.abs
code(int): An error code to identify the kind of error
"""
error = Error(message, code, node=node)
error = Error(message, node.pos, code)
self.add_error(node, error)
return self
def collect_errors(self) -> List[Error]:
"""Returns the list of errors, ordered bv their position.
"""
# for node in self.err_nodes: # lazy evaluation of positions
# for err in node.errors: # moved to error.Error.pos
# err.pos = node.pos
self.all_errors.sort(key=lambda e: e.pos)
for node in self.err_nodes_keep: # redundant: consider removing Error.Error._node_keep
for error in node.errors:
assert error._pos < 0 or node.pos <= error._pos <= node.pos + len(node)
if error._pos < 0:
error._pos = node.pos
self.err_nodes_keep = []
errors = self.all_errors
# for error in self.all_errors:
# _ = error.pos
return errors
return self.all_errors
ZOMBIE_NODE = Node(ZOMBIE_PARSER, '')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment