05.11., 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit cc08caee authored by eckhart's avatar eckhart

- bug fix for resmue after failure

parent ecd84a51
......@@ -570,7 +570,6 @@ class EBNFCompiler(Compiler):
definitions.append((self.RAW_WS_KEYWORD, "r'{whitespace}'".format(**self.directives)))
definitions.append((self.COMMENT_KEYWORD, "r'{comment}'".format(**self.directives)))
definitions.append((self.RESUME_RULES_KEYWORD, repr(self.directives['resume'])))
print(self.directives['resume'])
# prepare parser class header and docstring and
# add EBNF grammar to the doc string of the parser class
......
......@@ -157,10 +157,13 @@ def reentry_point(rest: StringView, rules: ResumeList) -> int:
def add_parser_guard(parser_func):
"""
Add a wrapper function to a parser functions (i.e. Parser.__call__ method)
that takes care of memoizing, left recursion and, optionally, tracing
(aka "history tracking") of parser calls. Returns the wrapped call.
that takes care of memoizing, left recursion, error catching and,
optionally, tracing (aka "history tracking") of parser calls.
Returns the wrapped call.
"""
def guarded_call(parser: 'Parser', text: StringView) -> Tuple[Optional[Node], StringView]:
"""Wrapper method for Parser.__call__. This is used to add in an aspect-oriented
fashion the business intelligence that is common to all parsers."""
grammar = parser.grammar
location = grammar.document_length__ - len(text)
......@@ -193,7 +196,7 @@ def add_parser_guard(parser_func):
rules = grammar.resume_rules__.get(parser.name, [])
rest = error.rest[len(error.node):]
i = reentry_point(rest, rules)
if i >= 0 or parser == grammar.root__:
if i >= 0 or parser == grammar.start_parser__:
# apply reentry-rule or catch error at root-parser
if i < 0:
i = 1
......@@ -538,6 +541,10 @@ class Grammar:
Attributes:
all_parsers__: A set of all parsers connected to this grammar object
start_parser__: During parsing, the parser with which the parsing process
was started (see method `__call__`) or `None` if no parsing process
is running.
history_tracking__: A flag indicating that the parsing history shall
be tracked
......@@ -659,6 +666,7 @@ class Grammar:
def __init__(self, root: Parser = None) -> None:
self.all_parsers__ = set() # type: Set[ParserBase]
self.start_parser__ = None # type: ParserBase
self._dirty_flag__ = False # type: bool
self.history_tracking__ = False # type: bool
self.memoization__ = True # type: bool
......@@ -738,7 +746,10 @@ class Grammar:
parser.grammar = self
def __call__(self, document: str, start_parser="root__", track_history=False) -> RootNode:
def __call__(self,
document: str,
start_parser: Union[str, Parser] = "root__",
track_history: bool = False) -> RootNode:
"""
Parses a document with with parser-combinators.
......@@ -779,6 +790,7 @@ class Grammar:
self.document_lbreaks__ = linebreaks(document) if self.history_tracking__ else []
self.last_rb__loc__ = -1 # rollback location
parser = self[start_parser] if isinstance(start_parser, str) else start_parser
self.start_parser__ = parser
assert parser.grammar == self, "Cannot run parsers from a different grammar object!" \
" %s vs. %s" % (str(self), str(parser.grammar))
result = None # type: Optional[Node]
......@@ -865,6 +877,7 @@ class Grammar:
# result.collect_errors(self.document__)
if result:
self.tree__.swallow(result)
self.start_parser__ = None
return self.tree__
......
......@@ -59,6 +59,7 @@ class LaTeXGrammar(Grammar):
text_element = Forward()
source_hash__ = "79e85f223d89452f2ba796f9c40daac9"
parser_initialization__ = "upon instantiation"
resume_rules__ = {}
COMMENT__ = r'%.*'
WHITESPACE__ = r'[ \t]*(?:\n(?![ \t]*\n)[ \t]*)?'
WSP_RE__ = mixin_comment(whitespace=WHITESPACE__, comment=COMMENT__)
......
......@@ -624,6 +624,15 @@ class TestReentryAfterError:
assert cst.content == content
assert cst.pick('alpha').content.startswith('ALPHA')
def test_no_resume_rules_partial_parsing(self):
gr = self.gr; gr.resume_rules = dict()
content = 'ALPHA acb'
cst = gr(content, 'alpha')
# print(cst.as_sxpr())
assert cst.error_flag
assert cst.content == content
assert cst.pick('alpha').content.startswith('ALPHA')
def test_simple_resume_rule(self):
gr = self.gr; gr.resume_rules = dict()
gr.resume_rules__['alpha'] = ['BETA']
......
......@@ -315,7 +315,7 @@ class TestLookahead:
def test_unit_lookahead(self):
errata = grammar_unit(self.cases, self.grammar_fac, self.trans_fac)
assert not errata
assert not errata, str(errata)
errata = grammar_unit(self.fail_cases, self.grammar_fac, self.trans_fac)
assert errata
......
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