Commit 0c797ed8 authored by eckhart's avatar eckhart

- DHParser/parse.py MetaParser, OneOrMore, ZeroOrMore: multiple infinite loop...

- DHParser/parse.py MetaParser, OneOrMore, ZeroOrMore: multiple infinite loop error messages at the same location will be avoided.
parent 65f54dcc
......@@ -88,6 +88,7 @@ class Error:
MALFORMED_ERROR_STRING = ErrorCode(1060)
AMBIGUOUS_ERROR_HANDLING = ErrorCode(1070)
REDEFINED_DIRECTIVE = ErrorCode(1080)
INFINITE_LOOP = ErrorCode(1090)
def __init__(self, message: str, pos, code: ErrorCode = ERROR,
orig_pos: int = -1, line: int = -1, column: int = -1) -> None:
......
......@@ -1266,8 +1266,8 @@ class DropWhitespace(Whitespace):
class MetaParser(Parser):
def _return_value(self, node: Optional[Node]) -> Node:
"""
Generate a return node if a single node has been returned from
any descendant parsers. Empty nodes will be dropped silently.
Generates a return node if a single node has been returned from
any descendant parsers. Anonymous empty nodes will be dropped.
If `self` is an unnamed parser, a non-empty descendant node
will be passed through. If the descendant node is anonymous,
it will be dropped and only its result will be kept.
......@@ -1288,9 +1288,14 @@ class MetaParser(Parser):
return EMPTY_NODE # avoid creation of a node object for anonymous empty nodes
return Node(self.tag_name, node or ()) # unoptimized code
@cython.locals(N=cython.int)
def _return_values(self, results: Tuple[Node, ...]) -> Node:
"""
Generates a return node from a tuple of returned nodes from
descendant parsers. Anonymous empty nodes will be removed from
the tuple. Anonymous child nodes will be flattened if
`grammar.flatten_tree__` is True.
"""
assert isinstance(results, tuple)
N = len(results)
if N > 1:
......@@ -1311,6 +1316,21 @@ class MetaParser(Parser):
return EMPTY_NODE # avoid creation of a node object for anonymous empty nodes
return Node(self.tag_name, results) # unoptimized code
def add_infinite_loop_error(self, node):
"""
Add an "infitnite loop detected" error to the given node, unless an infinite
loop detection error has already been notified at the same location. (As a
consequence, only the innermost parser where an infinite loop is detected
will be set the error message, which is prefereble to a stack of error
messages from failed as well as its calling parsers.)
"""
if (not node.pos in
(err.pos for err in
filter(lambda e: e.code == Error.INFINITE_LOOP, self.grammar.tree__.errors))):
self.grammar.tree__.add_error(
node, Error(dsl_error_msg(self, 'Infinite Loop encountered.'),
node.pos, Error.INFINITE_LOOP))
class UnaryParser(MetaParser):
"""
......@@ -1447,8 +1467,7 @@ class ZeroOrMore(Option):
if not node:
break
if len(text) == n:
self.grammar.tree__.add_error(
node, Error(dsl_error_msg(self, 'Infinite Loop encountered.'), node.pos))
self.add_infinite_loop_error(node)
results += (node,)
nd = self._return_values(results) # type: Node
return nd, text
......@@ -1494,8 +1513,7 @@ class OneOrMore(UnaryParser):
if not node:
break
if len(text_) == n:
self.grammar.tree__.add_error(
node, Error(dsl_error_msg(self, 'Infinite Loop encountered.'), node.pos))
self.add_infinite_loop_error(node)
results += (node,)
if results == ():
return None, text
......
......@@ -57,10 +57,10 @@ class BibTeXGrammar(Grammar):
r"""Parser for a BibTeX source file.
"""
text = Forward()
source_hash__ = "4e4011722001b0019b7b980a02559de1"
source_hash__ = "d9a1a1b431a3185dab127be165a37719"
parser_initialization__ = ["upon instantiation"]
resume_rules__ = {}
COMMENT__ = r'(?i)%%.*\n'
COMMENT__ = r'//'
WHITESPACE__ = r'\s*'
WSP_RE__ = mixin_comment(whitespace=WHITESPACE__, comment=COMMENT__)
wsp__ = Whitespace(WSP_RE__)
......
......@@ -68,14 +68,8 @@ Match test "entry" for parser "entry" failed:
organization = {Wikipedia}
}
6:68: Error (1000): DSL parser specification error: Infinite Loop encountered. Caught by parser "CONTENT_STRING = {/(?i)[^{}%]+/ | /(?i)(?=%)/ ~}+".
6:68: Error (1090): DSL parser specification error: Infinite Loop encountered. Caught by parser "CONTENT_STRING = {/(?i)[^{}%]+/ | /(?i)(?=%)/ ~}+".
Call stack: entry->:ZeroOrMore->:Series->content->:Series->text->:Alternative->CONTENT_STRING->:Alternative->:Series->:Whitespace
6:68: Error (1000): DSL parser specification error: Infinite Loop encountered. Caught by parser "CONTENT_STRING = {/(?i)[^{}%]+/ | /(?i)(?=%)/ ~}+".
Call stack: entry->:ZeroOrMore->:Series->content->:Series->text->:Alternative->CONTENT_STRING->:Alternative->:Series->:Whitespace
6:68: Error (1000): DSL parser specification error: Infinite Loop encountered. Caught by parser "text = {CONTENT_STRING | '{' ~ text '}' ~}".
Call stack: entry->:ZeroOrMore->:Series->content->:Series->text->:Alternative->CONTENT_STRING
6:68: Error (1000): DSL parser specification error: Infinite Loop encountered. Caught by parser "COMMA_TERMINATED_STRING = {/(?i)[^,%]+/ | /(?i)(?=%)/ ~}".
Call stack: entry->:ZeroOrMore->:Series->content->plain_content->COMMA_TERMINATED_STRING->:Alternative
6:68: Error (1010): '}' ~ expected, "%E2\%80\%9" found!
6:69: Error (1040): Parser stopped before end! trying to recover but stopping history recording at this point.
7:1: Error (1020): Parser did not match!
......
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