From 11cb5c7e34394b4de954478dc13a49d70ec344ec Mon Sep 17 00:00:00 2001 From: eckhart Date: Wed, 10 Jun 2020 21:22:10 +0200 Subject: [PATCH] parse.py: ensure cache neutrality for retrieved values --- DHParser/parse.py | 9 +++++++-- tests/test_parse.py | 29 ++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/DHParser/parse.py b/DHParser/parse.py index bcdd933..f4f0d38 100644 --- a/DHParser/parse.py +++ b/DHParser/parse.py @@ -1230,7 +1230,7 @@ class Grammar: # variables stored and recalled by Capture and Retrieve parsers self.variables__ = defaultdict(lambda: []) # type: DefaultDict[str, List[str]] self.rollback__ = [] # type: List[Tuple[int, Callable]] - self.last_rb__loc__ = -1 # type: int + self.last_rb__loc__ = -2 # type: int # support for call stack tracing self.call_stack__ = [] # type: List[CallItem] # tag_name, location # snapshots of call stacks @@ -1460,7 +1460,7 @@ class Grammar: # *line_col(self.document__, len(self.document__) - self.last_rb__loc__)) rollback_func() self.last_rb__loc__ = self.rollback__[-1][0] if self.rollback__ \ - else -1 # (self.document__.__len__() + 1) + else -2 # (self.document__.__len__() + 1) def as_ebnf(self) -> str: @@ -3024,6 +3024,8 @@ class Retrieve(UnaryParser): def _parse(self, text: StringView) -> Tuple[Optional[Node], StringView]: # auto-capture on first use if symbol was not captured before # ("or"-clause needed, because Forward parsers do not have a pname) + self.grammar.last_rb__loc__ = self.grammar.document_length__ - text._len + # set last_rb__loc__ to avoid caching of retrieved results if len(self.grammar.variables__[self.symbol_pname]) == 0: node, text_ = self.parser(text) # auto-capture value if node is None: @@ -3096,6 +3098,9 @@ class Pop(Retrieve): if node is not None and not id(node) in self.grammar.tree__.error_nodes: self.values.append(self.grammar.variables__[self.symbol_pname].pop()) self.grammar.push_rollback__(rollback_location(self, text, text_), self._rollback) + else: + # set last_rb__loc__ to avoid caching of retrieved results + self.grammar.last_rb__loc__ = self.grammar.document_length__ - text._len return node, text_ def __repr__(self): diff --git a/tests/test_parse.py b/tests/test_parse.py index 66a069a..d0b5f85 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -868,12 +868,31 @@ class TestPopRetrieve: st = gr(case) assert not st.errors case = 'AXX!' - set_config_value('history_tracking', True) - start_logging('LOGS') - set_tracer(gr, trace_history) + # set_config_value('history_tracking', True) + # start_logging('LOGS') + # set_tracer(gr, trace_history) st = gr(case) - log_parsing_history(gr, 'test_cache_neutrality_2') - print(st.as_sxpr()) + # log_parsing_history(gr, 'test_cache_neutrality_2') + assert not st.errors + assert str(st) == "AXX!" + # print(st.as_sxpr()) + + def test_cache_neutrality_3(selfself): + lang = r'''document = variantA | variantB + variantA = delimiter `X` check ::delimiter `!` + variantB = `A` delimiter check ::delimiter `!` + check = :delimiter + delimiter = `A` | `X` + ''' + gr = grammar_provider(lang)() + case = 'AXXX!' + # set_config_value('history_tracking', True) + # start_logging('LOGS') + # set_tracer(gr, trace_history) + st = gr(case) + # log_parsing_history(gr, 'test_cache_neutrality_3') + assert not st.errors + # print(st.as_sxpr()) def test_single_line(self): teststr = "Anfang ```code block `` <- keine Ende-Zeichen ! ``` Ende" -- GitLab