Skip to content

Commit

Permalink
Merge pull request #1433 from chanicpanic/issue1283_no_ftpt_cache_reb…
Browse files Browse the repository at this point in the history
…ased

Disable ForestToParseTree cache when ambiguity='resolve'
  • Loading branch information
erezsh authored Jun 29, 2024
2 parents 33136b3 + 4c1507a commit 7910ade
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 4 deletions.
5 changes: 4 additions & 1 deletion lark/parsers/earley.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,10 @@ def parse(self, lexer, start):

if self.Tree is not None:
# Perform our SPPF -> AST conversion
transformer = ForestToParseTree(self.Tree, self.callbacks, self.forest_sum_visitor and self.forest_sum_visitor(), self.resolve_ambiguity)
# Disable the ForestToParseTree cache when ambiguity='resolve'
# to prevent a tree construction bug. See issue #1283
use_cache = not self.resolve_ambiguity
transformer = ForestToParseTree(self.Tree, self.callbacks, self.forest_sum_visitor and self.forest_sum_visitor(), self.resolve_ambiguity, use_cache)
solutions = [transformer.transform(s) for s in solutions]

if len(solutions) > 1:
Expand Down
7 changes: 4 additions & 3 deletions lark/parsers/earley_forest.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,9 +609,10 @@ def transform_packed_node(self, node, data):
children.append(data.left)
if data.right is not PackedData.NO_DATA:
children.append(data.right)
if node.parent.is_intermediate:
return self._cache.setdefault(id(node), children)
return self._cache.setdefault(id(node), self._call_rule_func(node, children))
transformed = children if node.parent.is_intermediate else self._call_rule_func(node, children)
if self._use_cache:
self._cache[id(node)] = transformed
return transformed

def visit_symbol_node_in(self, node):
super(ForestToParseTree, self).visit_symbol_node_in(node)
Expand Down
20 changes: 20 additions & 0 deletions tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,26 @@ def test_symbol_node_start_end_dynamic_lexer(self):
self.assertEqual(node.start, 0)
self.assertEqual(node.end, 3)

def test_resolve_ambiguity_with_shared_node(self):
grammar = """
start: (a+)*
!a.1: "A" |
"""

l = Lark(grammar, ambiguity='resolve', lexer=LEXER)
tree = l.parse("A")
self.assertEqual(tree, Tree('start', [Tree('a', []), Tree('a', []), Tree('a', ['A'])]))

def test_resolve_ambiguity_with_shared_node2(self):
grammar = """
start: _s x _s
x: "X"?
_s: " "?
"""

l = Lark(grammar, ambiguity='resolve', lexer=LEXER)
tree = l.parse("")
self.assertEqual(tree, Tree('start', [Tree('x', [])]))

_NAME = "TestFullEarley" + LEXER.capitalize()
_TestFullEarley.__name__ = _NAME
Expand Down

0 comments on commit 7910ade

Please sign in to comment.