Commit a7ea5970 authored by Eckhart Arnold's avatar Eckhart Arnold

- refactor RootNode.errors()-Method

parent af64dde3
......@@ -246,7 +246,7 @@ def compile_source(source: str,
# messages.extend(syntax_tree.errors())
# syntax_tree.error_flag = max(syntax_tree.error_flag, efl)
messages = syntax_tree.errors()
messages = syntax_tree.errors_sorted
adjust_error_locations(messages, original_text, source_mapping)
return result, messages, ast
......
......@@ -193,7 +193,7 @@ class Node: # (collections.abc.Sized): Base class omitted for cython-compatibil
def __str__(self):
if isinstance(self, RootNode):
root = cast(RootNode, self)
errors = root.errors()
errors = root.errors_sorted
if errors:
e_pos = errors[0].pos
return self.content[:e_pos] + \
......@@ -743,7 +743,7 @@ PLACEHOLDER = Node('__PLACEHOLDER__', '')
class RootNode(Node):
"""TODO: Add Documentation!!!
all_errors (list): A list of all errors that have occured so far during
errors (list): A list of all errors that have occured so far during
processing (i.e. parsing, AST-transformation, compiling)
of this tree.
......@@ -753,7 +753,7 @@ class RootNode(Node):
def __init__(self, node: Optional[Node] = None):
super().__init__('__not_yet_ready__', '')
self.all_errors = [] # type: List[Error]
self.errors = [] # type: List[Error]
self.error_nodes = dict() # type: Dict[int, List[Error]] # id(node) -> error list
self.error_positions = dict() # type: Dict[int, Set[int]] # pos -> set of id(node)
self.error_flag = 0
......@@ -777,7 +777,7 @@ class RootNode(Node):
if self.attr_active():
duplicate.attr.update(copy.deepcopy(self._xml_attr))
# duplicate._xml_attr = copy.deepcopy(self._xml_attr) # this is blocked by cython
duplicate.all_errors = copy.copy(self.all_errors)
duplicate.errors = copy.copy(self.errors)
duplicate.error_nodes = copy.copy(self.error_nodes)
duplicate.error_positions = copy.deepcopy(self.error_positions)
duplicate.error_flag = self.error_flag
......@@ -818,11 +818,7 @@ class RootNode(Node):
"""
assert not isinstance(node, FrozenNode)
assert node.pos == error.pos
# self.all_errors.append(error)
for i in range(len(self.all_errors)):
if node.pos < self.all_errors[i].pos:
break
self.all_errors.insert(i, error)
self.errors.append(error)
self.error_flag = max(self.error_flag, error.code)
self.error_nodes.setdefault(id(node), []).append(error)
self.error_positions.setdefault(node.pos, set()).add(id(node))
......@@ -863,12 +859,12 @@ class RootNode(Node):
return errors
@property
def errors(self) -> List[Error]:
def errors_sorted(self) -> List[Error]:
"""
Returns the list of errors, ordered bv their position.
"""
# self.all_errors.sort(key=lambda e: e.pos)
return self.all_errors
self.errors.sort(key=lambda e: e.pos)
return self.errors
def customized_XML(self):
"""
......
......@@ -410,7 +410,7 @@ def grammar_unit(test_unit, parser_factory, transformer_factory, report=True, ve
transform(ast)
tests.setdefault('__ast__', {})[test_name] = ast
# log_ST(ast, "match_%s_%s.ast" % (parser_name, clean_test_name))
raw_errors = cst.errors()
raw_errors = cst.errors_sorted
if is_error(cst.error_flag) and not lookahead_artifact(parser, raw_errors):
errors = adjust_error_locations(raw_errors, test_code)
errata.append('Match test "%s" for parser "%s" failed:\n\tExpr.: %s\n\n\t%s\n\n' %
......@@ -454,7 +454,7 @@ def grammar_unit(test_unit, parser_factory, transformer_factory, report=True, ve
cst = RootNode(node).new_error(node, str(upe))
errata.append('Unknown parser "{}" in fail test "{}"!'.format(parser_name, test_name))
tests.setdefault('__err__', {})[test_name] = errata[-1]
if not is_error(cst.error_flag) and not lookahead_artifact(parser, cst.errors()):
if not is_error(cst.error_flag) and not lookahead_artifact(parser, cst.errors_sorted):
errata.append('Fail test "%s" for parser "%s" yields match instead of '
'expected failure!' % (test_name, parser_name))
tests.setdefault('__err__', {})[test_name] = errata[-1]
......@@ -463,7 +463,7 @@ def grammar_unit(test_unit, parser_factory, transformer_factory, report=True, ve
log_parsing_history(parser, "fail_%s_%s.log" % (parser_name, test_name))
if cst.error_flag:
tests.setdefault('__msg__', {})[test_name] = \
"\n".join(str(e) for e in cst.errors())
"\n".join(str(e) for e in cst.errors_sorted)
if verbose:
write(infostr + ("OK" if len(errata) == errflag else "FAIL"))
......
......@@ -207,4 +207,4 @@ syntax_tree = parser(markdown_text)
ASTTransform(syntax_tree, MDTransTable)
print(syntax_tree.as_sxpr())
print(error_messages(markdown_text, syntax_tree.errors()))
print(error_messages(markdown_text, syntax_tree.errors_sorted))
......@@ -283,4 +283,4 @@ syntax_tree = parse(markdown_text, parser)
ASTTransform(syntax_tree, MDTransTable)
print(syntax_tree.as_sxpr())
print(error_messages(markdown_text, syntax_tree.errors()))
print(error_messages(markdown_text, syntax_tree.errors_sorted()))
......@@ -50,7 +50,7 @@ compiler = get_compiler()
def fail_on_error(src, result):
if result.error_flag:
print(result.as_sxpr())
for e in result.errors():
for e in result.errors_sorted:
print(str(e))
sys.exit(1)
......
......@@ -52,7 +52,7 @@ class TestCompileFunctions:
assert callable(factory)
parser = factory()
result = parser("5 + 3 * 4")
assert not result.error_flag, str(result.errors())
assert not result.error_flag, str(result.errors_sorted)
result = parser("5A + 4B ** 4C")
assert is_error(result.error_flag)
......
......@@ -52,36 +52,36 @@ class TestDirectives:
assert parser
syntax_tree = parser("3 + 4 * 12")
# parser.log_parsing_history("WSP")
assert not syntax_tree.errors()
assert not syntax_tree.errors_sorted
syntax_tree = parser("3 + 4 \n * 12")
# parser.log_parsing_history("WSPLF")
assert not syntax_tree.errors()
assert not syntax_tree.errors_sorted
syntax_tree = parser("3 + 4 \n \n * 12")
assert syntax_tree.errors()
assert syntax_tree.errors_sorted
syntax_tree = parser("3 + 4 \n\n * 12")
assert syntax_tree.errors()
assert syntax_tree.errors_sorted
def test_whitespace_vertical(self):
lang = "@ whitespace = vertical\n" + self.mini_language
parser = grammar_provider(lang)()
assert parser
syntax_tree = parser("3 + 4 * 12")
assert not syntax_tree.errors()
assert not syntax_tree.errors_sorted
syntax_tree = parser("3 + 4 \n * 12")
assert not syntax_tree.errors()
assert not syntax_tree.errors_sorted
syntax_tree = parser("3 + 4 \n \n * 12")
assert not syntax_tree.errors()
assert not syntax_tree.errors_sorted
syntax_tree = parser("3 + 4 \n\n * 12")
assert not syntax_tree.errors()
assert not syntax_tree.errors_sorted
def test_whitespace_horizontal(self):
lang = "@ whitespace = horizontal\n" + self.mini_language
parser = grammar_provider(lang)()
assert parser
syntax_tree = parser("3 + 4 * 12")
assert not syntax_tree.errors()
assert not syntax_tree.errors_sorted
syntax_tree = parser("3 + 4 \n * 12")
assert syntax_tree.errors()
assert syntax_tree.errors_sorted
class TestReservedSymbols:
......@@ -176,7 +176,7 @@ class TestParserNameOverwriteBug:
get_ebnf_transformer()(st)
# print(st.as_sxpr())
result = get_ebnf_compiler()(st)
messages = st.errors()
messages = st.errors_sorted
assert not has_errors(messages), str(messages)
def test_single_mandatory_bug(self):
......@@ -194,9 +194,9 @@ class TestSemanticValidation:
def check(self, minilang, bool_filter=lambda x: x):
grammar = get_ebnf_grammar()
st = grammar(minilang)
assert not st.errors()
assert not st.errors_sorted
EBNFTransform()(st)
assert bool_filter(st.errors())
assert bool_filter(st.errors_sorted)
def test_illegal_nesting(self):
self.check('impossible = { [ "an optional requirement" ] }')
......@@ -477,12 +477,12 @@ class TestErrorCustomization:
st = parser("ABCD"); assert not st.error_flag
st = parser("A_CD"); assert not st.error_flag
st = parser("AB_D"); assert st.error_flag
assert st.errors()[0].code == Error.MANDATORY_CONTINUATION
assert st.errors()[0].message == "a user defined error message"
assert st.errors_sorted[0].code == Error.MANDATORY_CONTINUATION
assert st.errors_sorted[0].message == "a user defined error message"
# transitivity of mandatory-operator
st = parser("ABC_"); assert st.error_flag
assert st.errors()[0].code == Error.MANDATORY_CONTINUATION
assert st.errors()[0].message == "a user defined error message"
assert st.errors_sorted[0].code == Error.MANDATORY_CONTINUATION
assert st.errors_sorted[0].message == "a user defined error message"
def test_customized_error_case_sensitive(self):
lang = """
......@@ -493,8 +493,8 @@ class TestErrorCustomization:
"""
parser = grammar_provider(lang)()
st = parser("ABC_"); assert st.error_flag
assert st.errors()[0].code == Error.MANDATORY_CONTINUATION
assert st.errors()[0].message == "a user defined error message"
assert st.errors_sorted[0].code == Error.MANDATORY_CONTINUATION
assert st.errors_sorted[0].message == "a user defined error message"
def test_multiple_error_messages(self):
lang = """
......@@ -509,21 +509,21 @@ class TestErrorCustomization:
"""
parser = grammar_provider(lang)()
st = parser("AB*D"); assert st.error_flag
assert st.errors()[0].code == Error.MANDATORY_CONTINUATION
assert st.errors()[0].message == "the asterix is wrong in this place"
assert st.errors_sorted[0].code == Error.MANDATORY_CONTINUATION
assert st.errors_sorted[0].message == "the asterix is wrong in this place"
# transitivity of mandatory-operator
st = parser("ABC_"); assert st.error_flag
assert st.errors()[0].code == Error.MANDATORY_CONTINUATION
assert st.errors()[0].message == "the underscore is wrong in this place"
assert st.errors_sorted[0].code == Error.MANDATORY_CONTINUATION
assert st.errors_sorted[0].message == "the underscore is wrong in this place"
st = parser("ABiD"); assert st.error_flag
assert st.errors()[0].code == Error.MANDATORY_CONTINUATION
assert st.errors()[0].message.startswith('wrong letter')
assert st.errors_sorted[0].code == Error.MANDATORY_CONTINUATION
assert st.errors_sorted[0].message.startswith('wrong letter')
st = parser("AB+D"); assert st.error_flag
assert st.errors()[0].code == Error.MANDATORY_CONTINUATION
assert st.errors()[0].message == "fallback error message"
assert st.errors_sorted[0].code == Error.MANDATORY_CONTINUATION
assert st.errors_sorted[0].message == "fallback error message"
st = parser("ABCi"); assert st.error_flag
assert st.errors()[0].code == Error.MANDATORY_CONTINUATION
assert st.errors()[0].message.startswith('C cannot be followed by')
assert st.errors_sorted[0].code == Error.MANDATORY_CONTINUATION
assert st.errors_sorted[0].message.startswith('C cannot be followed by')
class TestErrorCustomizationErrors:
......@@ -600,7 +600,7 @@ class TestCustomizedResumeParsing:
assert cst.content == content
assert cst.pick('alpha').content.startswith('ALPHA')
# because of resuming, there should be only on error message
assert len(cst.errors()) == 1
assert len(cst.errors_sorted) == 1
content = 'ALPHA acb BETA bad GAMMA cab .'
cst = gr(content)
......@@ -609,7 +609,7 @@ class TestCustomizedResumeParsing:
assert cst.content == content
assert cst.pick('alpha').content.startswith('ALPHA')
# because of resuming, there should be only on error message
assert len(cst.errors()) == 2
assert len(cst.errors_sorted) == 2
content = 'ALPHA acb GAMMA cab .'
cst = gr(content)
......@@ -618,7 +618,7 @@ class TestCustomizedResumeParsing:
assert cst.content == content
assert cst.pick('alpha').content.startswith('ALPHA')
# because of resuming, there should be only on error message
assert len(cst.errors()) == 1
assert len(cst.errors_sorted) == 1
class TestInSeriesResume:
......@@ -634,29 +634,29 @@ class TestInSeriesResume:
st = self.gr('ABCDEFG')
assert not st.error_flag
st = self.gr('AB XYZ CDEFG')
errors = st.errors()
errors = st.errors_sorted
assert len(errors) == 1 and errors[0].code == Error.MANDATORY_CONTINUATION
st = self.gr('AB XYZ CDE XYZ FG')
errors = st.errors()
errors = st.errors_sorted
assert len(errors) == 2 and all(err.code == Error.MANDATORY_CONTINUATION for err in errors)
st = self.gr('AB XYZ CDE XNZ FG') # fails to resume parsing
errors = st.errors()
errors = st.errors_sorted
assert len(errors) >= 1 and errors[0].code == Error.MANDATORY_CONTINUATION
def test_series_gap(self):
st = self.gr('ABDEFG')
errors = st.errors()
errors = st.errors_sorted
assert len(errors) == 1 and errors[0].code == Error.MANDATORY_CONTINUATION
st = self.gr('ABXEFG') # two missing, one wrong element added
errors = st.errors()
errors = st.errors_sorted
assert len(errors) == 2 and all(err.code == Error.MANDATORY_CONTINUATION for err in errors)
st = self.gr('AB_DE_G')
errors = st.errors()
errors = st.errors_sorted
assert len(errors) == 2 and all(err.code == Error.MANDATORY_CONTINUATION for err in errors)
def test_series_permutation(self):
st = self.gr('ABEDFG')
errors = st.errors()
errors = st.errors_sorted
assert len(errors) >= 1 # cannot really recover from permutation errors
......@@ -674,7 +674,7 @@ class TestAllOfResume:
st = self.gr('GFCBAED')
assert not st.error_flag
st = self.gr('GFCB XYZ AED')
errors = st.errors()
errors = st.errors_sorted
assert errors[0].code == Error.MANDATORY_CONTINUATION
assert str(errors[0]).find(':-(') >= 0
......@@ -697,9 +697,9 @@ class TestAllOfResume:
assert not st.error_flag
st = gr('EDXYZ.')
assert st.error_flag
assert len(st.errors()) == 1
assert len(st.errors_sorted) == 1
st = gr('FCB_GAED.')
assert len(st.errors()) == 1
assert len(st.errors_sorted) == 1
def test_complex_resume_task(self):
......@@ -722,11 +722,11 @@ class TestAllOfResume:
assert not st.error_flag
st = gr('EDXYZ.')
assert st.error_flag
assert len(st.errors()) == 1
assert len(st.errors_sorted) == 1
st = gr('FCB_GAED.')
assert len(st.errors()) == 2
assert len(st.errors_sorted) == 2
st = gr('EXY EXYZ.')
assert len(st.errors()) == 1
assert len(st.errors_sorted) == 1
......
This diff is collapsed.
......@@ -91,7 +91,7 @@ class TestNode:
assert tree_copy.as_sxpr() == parse_sxpr('(a (b c) (d (e f) (h i)))').as_sxpr()
tree.add_error(tree, Error('Test Error', 0))
assert not tree_copy.all_errors
assert not tree_copy.errors
assert tree.as_sxpr() != parse_sxpr('(a (b c) (d (e f) (h i)))').as_sxpr()
assert tree_copy.as_sxpr() == parse_sxpr('(a (b c) (d (e f) (h i)))').as_sxpr()
......@@ -198,7 +198,7 @@ class TestRootNode:
root.new_error(tree.children[0], "error B")
root.swallow(tree)
assert root.error_flag
errors = root.errors()
errors = root.errors_sorted
assert root.error_flag
# assert errors == root.errors(True)
# assert not root.error_flag and not root.errors()
......
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