Commit 11cb5c7e authored by eckhart's avatar eckhart

parse.py: ensure cache neutrality for retrieved values

parent 4f3afbd8
......@@ -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):
......
......@@ -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"
......
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