The expiration time for new job artifacts in CI/CD pipelines is now 30 days (GitLab default). Previously generated artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

Commit fde7e064 authored by eckhart's avatar eckhart
Browse files

- some refinements

parent f6c14f6c
......@@ -581,7 +581,7 @@ class EBNFCompiler(Compiler):
defined_symbols = set(self.rules.keys()) | self.RESERVED_SYMBOLS
for symbol in self.symbols:
if symbol not in defined_symbols:
self.tree.add_error(self.symbols[symbol],
self.tree.new_error(self.symbols[symbol],
"Missing definition for symbol '%s'" % symbol)
# root_node.error_flag = True
......@@ -599,9 +599,9 @@ class EBNFCompiler(Compiler):
remove_connections(self.root_symbol)
for leftover in defined_symbols:
self.tree.add_error(self.rules[leftover][0],
('Rule "%s" is not connected to parser root "%s" !') %
(leftover, self.root_symbol), Error.WARNING)
self.tree.new_error(self.rules[leftover][0],
('Rule "%s" is not connected to parser root "%s" !') %
(leftover, self.root_symbol), Error.WARNING)
# set root_symbol parser and assemble python grammar definition
......@@ -640,19 +640,19 @@ class EBNFCompiler(Compiler):
if rule in self.rules:
first = self.rules[rule][0]
if not first.errors:
self.tree.add_error(first, 'First definition of rule "%s" '
self.tree.new_error(first, 'First definition of rule "%s" '
'followed by illegal redefinitions.' % rule)
self.tree.add_error(node, 'A rule "%s" has already been defined earlier.' % rule)
self.tree.new_error(node, 'A rule "%s" has already been defined earlier.' % rule)
elif rule in EBNFCompiler.RESERVED_SYMBOLS:
self.tree.add_error(node, 'Symbol "%s" is a reserved symbol.' % rule)
self.tree.new_error(node, 'Symbol "%s" is a reserved symbol.' % rule)
elif not sane_parser_name(rule):
self.tree.add_error(node, 'Illegal symbol "%s". Symbols must not start or '
self.tree.new_error(node, 'Illegal symbol "%s". Symbols must not start or '
' end with a doube underscore "__".' % rule)
elif rule in self.directives['tokens']:
self.tree.add_error(node, 'Symbol "%s" has already been defined as '
self.tree.new_error(node, 'Symbol "%s" has already been defined as '
'a preprocessor token.' % rule)
elif keyword.iskeyword(rule):
self.tree.add_error(node, 'Python keyword "%s" may not be used as a symbol. '
self.tree.new_error(node, 'Python keyword "%s" may not be used as a symbol. '
% rule + '(This may change in the future.)')
try:
self.current_symbols = [node]
......@@ -669,7 +669,7 @@ class EBNFCompiler(Compiler):
trace = str(extract_tb(error.__traceback__)[-1])
errmsg = "%s (TypeError: %s; %s)\n%s" \
% (EBNFCompiler.AST_ERROR, str(error), trace, node.as_sxpr())
self.tree.add_error(node, errmsg)
self.tree.new_error(node, errmsg)
rule, defn = rule + ':error', '"' + errmsg + '"'
return rule, defn
......@@ -685,7 +685,7 @@ class EBNFCompiler(Compiler):
try:
re.compile(rx)
except Exception as re_error:
self.tree.add_error(node, "malformed regular expression %s: %s" %
self.tree.new_error(node, "malformed regular expression %s: %s" %
(repr(rx), str(re_error)))
return rx
......@@ -696,7 +696,7 @@ class EBNFCompiler(Compiler):
if key not in self.REPEATABLE_DIRECTIVES:
if key in self.defined_directives:
self.tree.add_error(node, 'Directive "%s" has already been defined earlier. '
self.tree.new_error(node, 'Directive "%s" has already been defined earlier. '
% key + 'Later definition will be ignored!',
code=Error.REDEFINED_DIRECTIVE_WARNING)
return ""
......@@ -705,26 +705,26 @@ class EBNFCompiler(Compiler):
if key in {'comment', 'whitespace'}:
if node.children[1].parser.name == "list_":
if len(node.children[1].result) != 1:
self.tree.add_error(node, 'Directive "%s" must have one, but not %i values.'
self.tree.new_error(node, 'Directive "%s" must have one, but not %i values.'
% (key, len(node.children[1].result)))
value = self.compile(node.children[1]).pop()
if key == 'whitespace' and value in EBNFCompiler.WHITESPACE:
value = EBNFCompiler.WHITESPACE[value] # replace whitespace-name by regex
else:
self.tree.add_error(node, 'Value "%s" not allowed for directive "%s".'
self.tree.new_error(node, 'Value "%s" not allowed for directive "%s".'
% (value, key))
else:
value = node.children[1].content.strip("~") # cast(str, node.children[
# 1].result).strip("~")
if value != node.children[1].content: # cast(str, node.children[1].result):
self.tree.add_error(node, "Whitespace marker '~' not allowed in definition "
self.tree.new_error(node, "Whitespace marker '~' not allowed in definition "
"of %s regular expression." % key)
if value[0] + value[-1] in {'""', "''"}:
value = escape_re(value[1:-1])
elif value[0] + value[-1] == '//':
value = self._check_rx(node, value[1:-1])
if key == 'whitespace' and not re.match(value, ''):
self.tree.add_error(node, "Implicit whitespace should always "
self.tree.new_error(node, "Implicit whitespace should always "
"match the empty string, /%s/ does not." % value)
self.directives[key] = value
......@@ -740,7 +740,7 @@ class EBNFCompiler(Compiler):
value = {item.lower() for item in self.compile(node.children[1])}
if ((value - {'left', 'right', 'both', 'none'})
or ('none' in value and len(value) > 1)):
self.tree.add_error(node, 'Directive "literalws" allows only `left`, `right`, '
self.tree.new_error(node, 'Directive "literalws" allows only `left`, `right`, '
'`both` or `none`, not `%s`' % ", ".join(value))
wsp = {'left', 'right'} if 'both' in value \
else {} if 'none' in value else value
......@@ -750,7 +750,7 @@ class EBNFCompiler(Compiler):
tokens = self.compile(node.children[1])
redeclared = self.directives['tokens'] & tokens
if redeclared:
self.tree.add_error(node, 'Tokens %s have already been declared earlier. '
self.tree.new_error(node, 'Tokens %s have already been declared earlier. '
% str(redeclared) + 'Later declaration will be ignored',
code=Error.REDECLARED_TOKEN_WARNING)
self.directives['tokens'] |= tokens - redeclared
......@@ -758,12 +758,12 @@ class EBNFCompiler(Compiler):
elif key.endswith('_filter'):
filter_set = self.compile(node.children[1])
if not isinstance(filter_set, set) or len(filter_set) != 1:
self.tree.add_error(node, 'Directive "%s" accepts exactly on symbol, not %s'
self.tree.new_error(node, 'Directive "%s" accepts exactly on symbol, not %s'
% (key, str(filter_set)))
self.directives['filter'][key[:-7]] = filter_set.pop()
else:
self.tree.add_error(node, 'Unknown directive %s ! (Known ones are %s .)' %
self.tree.new_error(node, 'Unknown directive %s ! (Known ones are %s .)' %
(key, ', '.join(list(self.directives.keys()))))
return ""
......@@ -794,10 +794,10 @@ class EBNFCompiler(Compiler):
if nd.parser.ptype == TOKEN_PTYPE and nd.content == "§":
mandatory_marker.append(len(filtered_children))
# if len(filtered_children) == 0:
# self.tree.add_error(nd.pos, 'First item of a series should not be mandatory.',
# self.tree.new_error(nd.pos, 'First item of a series should not be mandatory.',
# Error.WARNING)
if len(mandatory_marker) > 1:
self.tree.add_error(nd, 'One mandatory marker (§) sufficient to declare '
self.tree.new_error(nd, 'One mandatory marker (§) sufficient to declare '
'the rest of the series as mandatory.', Error.WARNING)
else:
filtered_children.append(nd)
......@@ -822,7 +822,7 @@ class EBNFCompiler(Compiler):
assert len(node.children) == 2
arg = node.children[-1]
if arg.parser.name != 'symbol':
self.tree.add_error(node, ('Retrieve Operator "%s" requires a symbol, '
self.tree.new_error(node, ('Retrieve Operator "%s" requires a symbol, '
'and not a %s.') % (prefix, str(arg.parser)))
return str(arg.result)
if str(arg) in self.directives['filter']:
......@@ -856,14 +856,14 @@ class EBNFCompiler(Compiler):
break
if (nd.parser.name != "regexp" or nd.content[:1] != '/'
or nd.content[-1:] != '/'):
self.tree.add_error(node, "Lookbehind-parser can only be used with RegExp"
self.tree.new_error(node, "Lookbehind-parser can only be used with RegExp"
"-parsers, not: " + nd.parser.name + nd.parser.ptype)
if not result.startswith('RegExp('):
self.deferred_tasks.append(lambda: check(node))
return result
except KeyError:
self.tree.add_error(node, 'Unknown prefix "%s".' % prefix)
self.tree.new_error(node, 'Unknown prefix "%s".' % prefix)
return ""
......@@ -889,14 +889,14 @@ class EBNFCompiler(Compiler):
nd = node.children[0]
for child in nd.children:
if child.parser.ptype == TOKEN_PTYPE and nd.content == "§":
self.tree.add_error(node, "No mandatory items § allowed in Unordered sequences.")
self.tree.new_error(node, "No mandatory items § allowed in Unordered sequences.")
args = ', '.join(self.compile(child) for child in nd.children)
if nd.parser.name == "term":
return "AllOf(" + args + ")"
elif nd.parser.name == "expression":
return "SomeOf(" + args + ")"
else:
self.tree.add_error(node, "Unordered sequence or alternative "
self.tree.new_error(node, "Unordered sequence or alternative "
"requires at least two elements.")
return ""
......@@ -951,7 +951,7 @@ class EBNFCompiler(Compiler):
trace = str(extract_tb(error.__traceback__)[-1])
errmsg = "%s (AttributeError: %s; %s)\n%s" \
% (EBNFCompiler.AST_ERROR, str(error), trace, node.as_sxpr())
self.tree.add_error(node, errmsg)
self.tree.new_error(node, errmsg)
return '"' + errmsg + '"'
return parser + ', '.join([arg] + name) + ')'
......
......@@ -166,7 +166,7 @@ def add_parser_guard(parser_func):
except RecursionError:
node = Node(None, str(text[:min(10, max(1, text.find("\n")))]) + " ...")
node._pos = location
grammar.tree__.add_error(node, "maximum recursion depth of parser reached; "
grammar.tree__.new_error(node, "maximum recursion depth of parser reached; "
"potentially due to too many errors!")
rest = EMPTY_STRING_VIEW
......@@ -728,7 +728,7 @@ class Grammar:
result, _ = parser(rest)
if result is None:
result = Node(None, '').init_pos(0)
self.tree__.add_error(result,
self.tree__.new_error(result,
'Parser "%s" did not match empty document.' % str(parser))
while rest and len(stitches) < MAX_DROPOUTS:
result, rest = parser(rest)
......@@ -749,7 +749,7 @@ class Grammar:
if len(stitches) < MAX_DROPOUTS
else " too often! Terminating parser.")
stitches.append(Node(None, skip).init_pos(tail_pos(stitches)))
self.tree__.add_error(stitches[-1], error_msg)
self.tree__.new_error(stitches[-1], error_msg)
if self.history_tracking__:
# # some parsers may have matched and left history records with nodes != None.
# # Because these are not connected to the stitched root node, their pos-
......@@ -775,10 +775,10 @@ class Grammar:
# of the error will be the end of the text. Otherwise, the error
# message above ("...after end of parsing") would appear illogical.
error_node = Node(ZOMBIE_PARSER, '').init_pos(tail_pos(result.children))
self.tree__.add_error(error_node, error_str)
self.tree__.new_error(error_node, error_str)
result.result = result.children + (error_node,)
else:
self.tree__.add_error(result, error_str)
self.tree__.new_error(result, error_str)
# result.pos = 0 # calculate all positions
# result.collect_errors(self.document__)
self.tree__.swallow(result)
......@@ -862,19 +862,19 @@ class PreprocessorToken(Parser):
end = text.find(END_TOKEN, 1)
if end < 0:
node = Node(self, '')
self.grammar.tree__.add_error(node,
self.grammar.tree__.new_error(node,
'END_TOKEN delimiter missing from preprocessor token. '
'(Most likely due to a preprocessor bug!)') # type: Node
return node, text[1:]
elif end == 0:
node = Node(self, '')
self.grammar.tree__.add_error(node,
self.grammar.tree__.new_error(node,
'Preprocessor-token cannot have zero length. '
'(Most likely due to a preprocessor bug!)')
return node, text[2:]
elif text.find(BEGIN_TOKEN, 1, end) >= 0:
node = Node(self, text[len(self.name) + 1:end])
self.grammar.tree__.add_error(node,
self.grammar.tree__.new_error(node,
'Preprocessor-tokens must not be nested or contain '
'BEGIN_TOKEN delimiter as part of their argument. '
'(Most likely due to a preprocessor bug!)')
......@@ -1257,13 +1257,13 @@ class ZeroOrMore(Option):
if not node:
break
if len(text) == n:
err_msg = dsl_error_msg(self, 'Infinite Loop encountered.')
node.errors.append(Error(err_msg, Error.MESSAGE, node=node))
infinite_loop_error = Error(err_msg, node=node)
node.errors.append(Error("Infinite loop!", Error.MESSAGE, node=node))
infinite_loop_error = Error(dsl_error_msg(self, 'Infinite Loop encountered.'),
node=node)
results += (node,)
node = Node(self, results)
if infinite_loop_error:
self.grammar.tree__.add_error_obj(node, infinite_loop_error)
self.grammar.tree__.add_error(node, infinite_loop_error)
return node, text
def __repr__(self):
......@@ -1307,15 +1307,15 @@ class OneOrMore(UnaryOperator):
if not node:
break
if len(text_) == n:
err_msg = dsl_error_msg(self, 'Infinite Loop encountered.')
node.errors.append(Error(err_msg, Error.MESSAGE, node=node))
infinite_loop_error = Error(err_msg, node=node)
node.errors.append(Error("Infinite loop!", Error.MESSAGE, node=node))
infinite_loop_error = Error(dsl_error_msg(self, 'Infinite Loop encountered.'),
node=node)
results += (node,)
if results == ():
return None, text
node = Node(self, results)
if infinite_loop_error:
self.grammar.tree__.add_error_obj(node, infinite_loop_error)
self.grammar.tree__.add_error(node, infinite_loop_error)
return node, text_
def __repr__(self):
......@@ -1387,7 +1387,7 @@ class Series(NaryOperator):
assert len(results) <= len(self.parsers)
node = Node(self, results)
if mandatory_violation:
self.grammar.tree__.add_error_obj(node, mandatory_violation)
self.grammar.tree__.add_error(node, mandatory_violation)
return node, text_
def __repr__(self):
......@@ -1648,7 +1648,7 @@ 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.tree__.add_error(node,
# self.grammar.tree__.new_error(node,
# '%s expected; "%s" found!' % (str(self.parser),
# text[:10]), code=Error.MANDATORY_CONTINUATION)
# return node, text_
......@@ -1824,7 +1824,7 @@ class Retrieve(Parser):
value = self.filter(stack)
except (KeyError, IndexError):
node = Node(self, '')
self.grammar.tree__.add_error(
self.grammar.tree__.new_error(
node, dsl_error_msg(self, "'%s' undefined or exhausted." % self.symbol.name))
return node, text
if text.startswith(value):
......
......@@ -717,26 +717,28 @@ class RootNode(Node):
self._content = node._content
return self
def add_error_obj(self, node: Node, error: Error) -> 'RootNode':
def add_error(self, node: Node, error: Error) -> 'RootNode':
"""Adds an Error object to the tree, locating it at a specific 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 add_error(self,
def new_error(self,
node: Node,
message: str,
code: int = Error.ERROR) -> 'RootNode':
"""
Adds an error to this tree.
Adds an error to this tree, locating it at a specific node.
Parameters:
pos(int): The position of the error in the source text
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)
self.add_error_obj(node, error)
self.add_error(node, error)
return self
def collect_errors(self) -> List[Error]:
......@@ -748,7 +750,7 @@ class RootNode(Node):
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.len
assert error._pos < 0 or node.pos <= error._pos <= node.pos + len(node)
error._pos = node.pos
self.err_nodes_keep = []
errors = self.all_errors
......
......@@ -355,7 +355,7 @@ def grammar_unit(test_unit, parser_factory, transformer_factory, report=True, ve
cst = parser(test_code, parser_name)
except UnknownParserError as upe:
node = Node(ZOMBIE_PARSER, "").init_pos(0)
cst = RootNode().swallow(node).add_error(node, str(upe))
cst = RootNode(node).new_error(node, str(upe))
if not is_error(cst.error_flag):
errata.append('Fail test "%s" for parser "%s" yields match instead of '
'expected failure!' % (test_name, parser_name))
......
......@@ -888,7 +888,7 @@ assert_has_children = error_on(lambda nd: nd.children, 'Element "%s" has no chil
def assert_content(context: List[Node], regexp: str):
node = context[-1]
if not has_content(context, regexp):
context[0].add_error(node, 'Element "%s" violates %s on %s' %
context[0].new_error(node, 'Element "%s" violates %s on %s' %
(node.parser.name, str(regexp), node.content))
......@@ -897,7 +897,7 @@ def require(context: List[Node], child_tags: AbstractSet[str]):
node = context[-1]
for child in node.children:
if child.tag_name not in child_tags:
context[0].add_error(node, 'Element "%s" is not allowed inside "%s".' %
context[0].new_error(node, 'Element "%s" is not allowed inside "%s".' %
(child.parser.name, node.parser.name))
......@@ -906,6 +906,6 @@ def forbid(context: List[Node], child_tags: AbstractSet[str]):
node = context[-1]
for child in node.children:
if child.tag_name in child_tags:
context[0].add_error(node, 'Element "%s" cannot be nested inside "%s".' %
context[0].new_error(node, 'Element "%s" cannot be nested inside "%s".' %
(child.parser.name, node.parser.name))
......@@ -526,7 +526,7 @@ S-Expression-output.</p>
<dl class="method">
<dt id="syntaxtree.Node.add_error">
<code class="descname">add_error</code><span class="sig-paren">(</span><em>message: str</em>, <em>code: int = 1000</em><span class="sig-paren">)</span> &#x2192; syntaxtree.Node<a class="reference internal" href="_modules/syntaxtree.html#Node.add_error"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#syntaxtree.Node.add_error" title="Permalink to this definition"></a></dt>
<code class="descname">add_error</code><span class="sig-paren">(</span><em>message: str</em>, <em>code: int = 1000</em><span class="sig-paren">)</span> &#x2192; syntaxtree.Node<a class="reference internal" href="_modules/syntaxtree.html#Node.new_error"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#syntaxtree.Node.new_error" title="Permalink to this definition"></a></dt>
<dd><p>Adds an error to this Node.
:param message: A string with the error message.abs
:type message: str
......
......@@ -633,7 +633,7 @@
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_errors</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<div class="viewcode-block" id="Node.add_error"><a class="viewcode-back" href="../ModuleReference.html#syntaxtree.Node.add_error">[docs]</a> <span class="k">def</span> <span class="nf">add_error</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
<div class="viewcode-block" id="Node.add_error"><a class="viewcode-back" href="../ModuleReference.html#syntaxtree.Node.new_error">[docs]</a> <span class="k">def</span> <span class="nf">new_error</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
<span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">code</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="n">Error</span><span class="o">.</span><span class="n">ERROR</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s1">&#39;Node&#39;</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;</span>
......
......@@ -199,7 +199,7 @@
<h2 id="A">A</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="ModuleReference.html#syntaxtree.Node.add_error">add_error() (Node method)</a>
<li><a href="ModuleReference.html#syntaxtree.Node.add_error">new_error() (Node method)</a>
</li>
<li><a href="ModuleReference.html#error.adjust_error_locations">adjust_error_locations() (in module error)</a>
</li>
......
......@@ -690,7 +690,7 @@ class LaTeXCompiler(Compiler):
if 'language' in node.attributes:
self.metadata['language'] = it
else:
self.tree.add_error(node, 'Only one document language supported. '
self.tree.new_error(node, 'Only one document language supported. '
'Using %s, ignoring %s.'
% (self.metadata['language'], it), Error.WARNING)
if node['text'] in self.KNOWN_DOCUMENT_CLASSES:
......
......@@ -30,8 +30,8 @@ from DHParser import parse_sxpr, Compiler
# B = next(tree.select(lambda node: str(node) == "1"))
# D = next(tree.select(lambda node: node.parser.name == "D"))
# F = next(tree.select(lambda node: str(node) == "3"))
# B.add_error("Error in child node")
# F.add_error("Error in child's child node")
# B.new_error("Error in child node")
# F.new_error("Error in child's child node")
# Compiler.propagate_error_flags(tree, lazy=True)
# assert A.error_flag
# assert not D.error_flag
......
......@@ -133,8 +133,8 @@ class TestRootNode:
tree = parse_sxpr('(A (B D) (C E))')
tree.init_pos(0)
root = RootNode()
root.add_error(tree.children[1], "error C")
root.add_error(tree.children[0], "error B")
root.new_error(tree.children[1], "error C")
root.new_error(tree.children[0], "error B")
root.swallow(tree)
assert root.error_flag
errors = root.collect_errors()
......@@ -152,7 +152,7 @@ class TestRootNode:
# def find_h(context):
# node = context[-1]
# if node.result == "h":
# node.add_error("an error deep inside the syntax tree")
# node.new_error("an error deep inside the syntax tree")
#
# assert not tree.error_flag
# traverse(tree, {"*": find_h})
......@@ -164,8 +164,8 @@ class TestRootNode:
# B = next(tree.select(lambda node: str(node) == "1"))
# D = next(tree.select(lambda node: node.parser.name == "D"))
# F = next(tree.select(lambda node: str(node) == "3"))
# B.add_error("Error in child node")
# F.add_error("Error in child's child node")
# B.new_error("Error in child node")
# F.new_error("Error in child's child node")
# tree.error_flag = Error.ERROR
# errors = tree.collect_errors()
# assert len(errors) == 2, str(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