@@ -275,7 +275,9 @@ class SimplifyRule_Visitor(Visitor): | |||||
def expansions(self, tree): | def expansions(self, tree): | ||||
self._flatten(tree) | self._flatten(tree) | ||||
tree.children = dedup_list(tree.children) | |||||
# Ensure all children are unique | |||||
if len(set(tree.children)) != len(tree.children): | |||||
tree.children = dedup_list(tree.children) # dedup is expensive, so try to minimize its use | |||||
class RuleTreeToText(Transformer): | class RuleTreeToText(Transformer): | ||||
@@ -39,7 +39,8 @@ class Parser: | |||||
self.forest_sum_visitor = None | self.forest_sum_visitor = None | ||||
for rule in parser_conf.rules: | for rule in parser_conf.rules: | ||||
self.predictions[rule.origin] = [x.rule for x in analysis.expand_rule(rule.origin)] | |||||
if rule.origin not in self.predictions: | |||||
self.predictions[rule.origin] = [x.rule for x in analysis.expand_rule(rule.origin)] | |||||
## Detect if any rules have priorities set. If the user specified priority = "none" then | ## Detect if any rules have priorities set. If the user specified priority = "none" then | ||||
# the priorities will be stripped from all rules before they reach us, allowing us to | # the priorities will be stripped from all rules before they reach us, allowing us to | ||||
@@ -158,28 +158,30 @@ class Transformer_NonRecursive(Transformer): | |||||
"Non-recursive. Doesn't change the original tree." | "Non-recursive. Doesn't change the original tree." | ||||
def transform(self, tree): | def transform(self, tree): | ||||
q = [tree] | |||||
# Tree to postfix | # Tree to postfix | ||||
rev_postfix = [] | rev_postfix = [] | ||||
q = [tree] | |||||
while q: | while q: | ||||
t = q.pop() | t = q.pop() | ||||
rev_postfix.append( t ) | rev_postfix.append( t ) | ||||
if isinstance(t, Tree): | if isinstance(t, Tree): | ||||
q += t.children[::-1] | |||||
q += t.children | |||||
# Postfix to tree | # Postfix to tree | ||||
stack = [] | stack = [] | ||||
for x in reversed(rev_postfix): | for x in reversed(rev_postfix): | ||||
if isinstance(x, Tree): | if isinstance(x, Tree): | ||||
size = len(x.children) | size = len(x.children) | ||||
args = [stack.pop() for _ in range(size)] | |||||
if size: | |||||
args = stack[-size:] | |||||
del stack[-size:] | |||||
else: | |||||
args = [] | |||||
stack.append(self._call_userfunc(x, args)) | stack.append(self._call_userfunc(x, args)) | ||||
else: | else: | ||||
stack.append(x) | stack.append(x) | ||||
t ,= stack # We should have only one tree remaining | t ,= stack # We should have only one tree remaining | ||||
assert t == tree | |||||
return t | return t | ||||
@@ -35,6 +35,13 @@ def _read(n, *args): | |||||
return f.read() | return f.read() | ||||
class TestParsers(unittest.TestCase): | class TestParsers(unittest.TestCase): | ||||
def test_big_list(self): | |||||
Lark(r""" | |||||
start: {} | |||||
""".format( | |||||
"|".join(['"%s"'%i for i in range(250)]) | |||||
)) | |||||
def test_same_ast(self): | def test_same_ast(self): | ||||
"Tests that Earley and LALR parsers produce equal trees" | "Tests that Earley and LALR parsers produce equal trees" | ||||
g = Lark(r"""start: "(" name_list ("," "*" NAME)? ")" | g = Lark(r"""start: "(" name_list ("," "*" NAME)? ")" | ||||