Commit 2f87d91a authored by di68kap's avatar di68kap

- syntaxtree.py: error propagation added

parent 90bb9074
......@@ -782,10 +782,16 @@ class Grammar:
self.tree__.swallow(result)
return self.tree__
def add_error(self, text, error_msg, code=Error.ERROR):
"""Adds an error at the location of `text` whithin the whole document that is
def location(self, remaining: str) -> int:
"""Returns the location of the `remaining` text within the currently
parsed document.
"""
self.document_length__ - len(remaining)
def add_error(self, location, error_msg, code=Error.ERROR):
"""Adds an error at the location of `text` within the whole document that is
currently being parsed."""
self.tree__.add_errr(self.document_length__ - len(text), error_msg, code)
self.tree__.add_error(location, error_msg, code)
def push_rollback__(self, location, func):
"""
......@@ -863,18 +869,18 @@ class PreprocessorToken(Parser):
if text[0:1] == BEGIN_TOKEN:
end = text.find(END_TOKEN, 1)
if end < 0:
self.grammar.add_error(text,
self.grammar.add_error(self.grammar.location(text),
'END_TOKEN delimiter missing from preprocessor token. '
'(Most likely due to a preprocessor bug!)') # type: Node
return Node(self, ''), text[1:]
elif end == 0:
self.grammar.add_error(text,
self.grammar.add_error(self.grammar.location(text),
'Preprocessor-token cannot have zero length. '
'(Most likely due to a preprocessor bug!)')
return Node(self, ''), text[2:]
elif text.find(BEGIN_TOKEN, 1, end) >= 0:
node = Node(self, text[len(self.name) + 1:end])
self.grammar.add_error(text,
self.grammar.add_error(self.grammar.location(text),
'Preprocessor-tokens must not be nested or contain '
'BEGIN_TOKEN delimiter as part of their argument. '
'(Most likely due to a preprocessor bug!)')
......@@ -1256,7 +1262,8 @@ class ZeroOrMore(Option):
if not node:
break
if len(text) == n:
self.grammar.add_error(text, dsl_error_msg(self, 'Infinite Loop detected.'))
self.grammar.add_error(self.grammar.location(text),
dsl_error_msg(self, 'Infinite Loop detected.'))
results += (node,)
return Node(self, results), text
......@@ -1300,7 +1307,8 @@ class OneOrMore(UnaryOperator):
if not node:
break
if len(text_) == n:
self.grammar.add_error(text, dsl_error_msg(self, 'Infinite Loop detected.'))
self.grammar.add_error(self.grammar.location(text),
dsl_error_msg(self, 'Infinite Loop detected.'))
results += (node,)
if results == ():
return None, text
......@@ -1360,7 +1368,7 @@ class Series(NaryOperator):
i = max(1, text.index(match.regs[1][0])) if match else 1
node = Node(self, text_[:i]).init_pos(self.grammar.document_length__
- len(text_))
self.grammar.add_error(text, '%s expected; "%s" found!'
self.grammar.add_error(self.grammar.location(text), '%s expected; "%s" found!'
% (parser.repr, text_[:10].replace('\n', '\\n ')),
code=Error.MANDATORY_CONTINUATION)
text_ = text_[i:]
......@@ -1629,7 +1637,8 @@ def Required(parser: Parser) -> Parser:
# i = max(1, text.index(m.regs[1][0])) if m else 1
# node = Node(self, text[:i])
# text_ = text[i:]
# self.grammar.add_error(text, '%s expected; "%s" found!' % (str(self.parser),
# self.grammar.add_error(self.grammar.location(text),
# '%s expected; "%s" found!' % (str(self.parser),
# text[:10]), code=Error.MANDATORY_CONTINUATION)
# return node, text_
#
......@@ -1803,7 +1812,7 @@ class Retrieve(Parser):
stack = self.grammar.variables__[self.symbol.name]
value = self.filter(stack)
except (KeyError, IndexError):
self.grammar.add_error(text,
self.grammar.add_error(self.grammar.location(text),
dsl_error_msg(self, "'%s' undefined or exhausted." % self.symbol.name))
return Node(self, ''), text
if text.startswith(value):
......
......@@ -228,22 +228,22 @@ class Node(collections.abc.Sized):
At any rate, it should only be reassigned during the parsing
stage and never during or after the AST-transformation.
errors (list): A list of all errors that occured on this node.
attributes (dict): An optional dictionary of XML-attributes. This
dictionary is created lazily upon first usage. The attributes
will only be shown in the XML-Representation, not in the
S-Expression-output.
_parent (Node): SLOT RESERVED FOR FUTURE USE!
"""
__slots__ = ['_result', 'children', '_len', '_pos', 'parser', '_xml_attr', '_content']
__slots__ = ['_result', 'children', '_len', '_pos', 'parser', 'errors' '_xml_attr', '_content']
def __init__(self, parser, result: ResultType, leafhint: bool = False) -> None:
"""
Initializes the ``Node``-object with the ``Parser``-Instance
that generated the node and the parser's result.
"""
self.errors = [] # type: List[Error]
self._pos = -1 # type: int
# Assignment to self.result initializes the attributes _result, children and _len
# The following if-clause is merely an optimization, i.e. a fast-path for leaf-Nodes
......@@ -259,9 +259,9 @@ class Node(collections.abc.Sized):
def __str__(self):
s = "".join(str(child) for child in self.children) if self.children else self.content
if self._errors:
if self.errors:
return ' <<< Error on "%s" | %s >>> ' % \
(s, '; '.join(e.message for e in self._errors))
(s, '; '.join(e.message for e in self.errors))
return s
......@@ -391,14 +391,10 @@ class Node(collections.abc.Sized):
if isinstance(result, Node):
self.children = (result,)
self._result = self.children
self.error_flag = result.error_flag
else:
if isinstance(result, tuple):
self.children = result
self._result = result or ''
if result:
if self.error_flag == 0:
self.error_flag = max(child.error_flag for child in self.children)
else:
self.children = NoChildren
self._result = result
......@@ -448,7 +444,7 @@ class Node(collections.abc.Sized):
"""
if overwrite or self._pos < 0:
self._pos = pos
for err in self._errors:
for err in self.errors:
err.pos = pos
else:
assert self._pos == pos, str("%i != %i" % (self._pos, pos))
......@@ -466,7 +462,7 @@ class Node(collections.abc.Sized):
# Returns the errors that occurred at this Node,
# not including any errors from child nodes.
# """
# return self._errors.copy()
# return self.errors.copy()
@property
def attributes(self):
......@@ -681,26 +677,50 @@ class Node(collections.abc.Sized):
class RootNode(Node):
"""
errors (list): A list of parser- or compiler-errors:
tuple(position, string) attached to this node
errors (list): A list of all errors that have occured so far during
processing (i.e. parsing, AST-transformation, compiling)
of this tree.
error_flag (int): 0 if no error occurred in either the node
itself or any of its descendants. Otherwise contains the
highest warning or error level or all errors that occurred.
error_flag (int): the highest warning or error level of all errors
that occurred.
"""
def __init__(self):
super().__init__(ZOMBIE_PARSER, '')
self.errors = []
self.error_flag = 0
def _propagate_errors(self):
assert self.children
if not self.errors:
return
self.errors.sort(key=lambda e: e.pos)
errlist = copy.copy(self.errors)
for leaf in self.select(lambda nd: not nd.children, False):
leaf.errors = []
while errlist and leaf.pos <= errlist[0].pos < leaf.pos + leaf.len:
leaf.errors.append(errlist[0])
del errlist[0]
if not errlist:
break
def _propagate_new_error(self, error):
for leaf in self.select(lambda nd: not nd.children, False):
if leaf.pos <= error.pos < leaf.pos + leaf.len:
leaf.errord.append(error)
break
else:
assert False, "Error %s at pos %i out of bounds" % (str(error), error.pos)
def swallow(self, node):
self._result = node._result
self.children = node.children
self._len = node._len
self._pos = node._pos
self.parser = node.parser
self._xml_attr = node._xml_attr
if hasattr(node, '_xml_attr'):
self._xml_attr = node._xml_attr
self._content = node._content
self._propagate_errors()
def add_error(self,
pos: int,
......@@ -713,8 +733,11 @@ class RootNode(Node):
message(str): A string with the error message.abs
code(int): An error code to identify the kind of error
"""
self.errors.append(Error(message, code, pos))
error = Error(message, code, pos)
self.errors.append(error)
self.error_flag = max(self.error_flag, code)
if self.children:
self._propagate_new_error(error)
return self
def collect_errors(self, clear_errors=False) -> List[Error]:
......
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