Browse Source

Fix Ambiguous Expander problems with nested ambiguities

tags/gm/2021-09-23T00Z/github.com--lark-parser-lark/0.6.6
night199uk 6 years ago
parent
commit
d74781605d
1 changed files with 28 additions and 15 deletions
  1. +28
    -15
      lark/parse_tree_builder.py

+ 28
- 15
lark/parse_tree_builder.py View File

@@ -121,16 +121,6 @@ class ChildFilterLALR_NoPlaceholders(ChildFilter):
def _should_expand(sym): def _should_expand(sym):
return not sym.is_term and sym.name.startswith('_') return not sym.is_term and sym.name.startswith('_')


class AmbiguousExpander:
"""Deal with the case where we're expanding children ('_rule') into a parent but the children
are ambiguous. i.e. (parent->_ambig->_expand_this_rule). In this case, make the parent itself
ambiguous with as many copies as their are ambiguous children, and then copy the ambiguous children
into the right parents in the right places, essentially shifting the ambiguiuty up the tree."""
def __init__(self, to_expand, tree_class, node_builder):
self.node_builder = node_builder
self.tree_class = tree_class
self.to_expand = to_expand

def maybe_create_child_filter(expansion, keep_all_tokens, ambiguous, _empty_indices): def maybe_create_child_filter(expansion, keep_all_tokens, ambiguous, _empty_indices):
# Prepare empty_indices as: How many Nones to insert at each index? # Prepare empty_indices as: How many Nones to insert at each index?
if _empty_indices: if _empty_indices:
@@ -158,15 +148,38 @@ def maybe_create_child_filter(expansion, keep_all_tokens, ambiguous, _empty_indi
# LALR without placeholders # LALR without placeholders
return partial(ChildFilterLALR_NoPlaceholders, [(i, x) for i,x,_ in to_include]) return partial(ChildFilterLALR_NoPlaceholders, [(i, x) for i,x,_ in to_include])


class AmbiguousExpander:
"""Deal with the case where we're expanding children ('_rule') into a parent but the children
are ambiguous. i.e. (parent->_ambig->_expand_this_rule). In this case, make the parent itself
ambiguous with as many copies as their are ambiguous children, and then copy the ambiguous children
into the right parents in the right places, essentially shifting the ambiguiuty up the tree."""
def __init__(self, to_expand, tree_class, node_builder):
self.node_builder = node_builder
self.tree_class = tree_class
self.to_expand = to_expand

def __call__(self, children): def __call__(self, children):
def _is_ambig_tree(child): def _is_ambig_tree(child):
return hasattr(child, 'data') and child.data == '_ambig' return hasattr(child, 'data') and child.data == '_ambig'


ambiguous = [i for i in self.to_expand if _is_ambig_tree(children[i])]
if ambiguous:
expand = [iter(child.children) if i in ambiguous else repeat(child) for i, child in enumerate(children)]
return self.tree_class('_ambig', [self.node_builder(list(f[0])) for f in product(zip(*expand))])
return self.node_builder(children)
#### When we're repeatedly expanding ambiguities we can end up with nested ambiguities.
# All children of an _ambig node should be a derivation of that ambig node, hence
# it is safe to assume that if we see an _ambig node nested within an ambig node
# it is safe to simply expand it into the parent _ambig node as an alternative derivation.
ambiguous = []
for i, child in enumerate(children):
if _is_ambig_tree(child):
if i in self.to_expand:
ambiguous.append(i)

to_expand = [j for j, grandchild in enumerate(child.children) if _is_ambig_tree(grandchild)]
child.expand_kids_by_index(*to_expand)

if not ambiguous:
return self.node_builder(children)

expand = [ iter(child.children) if i in ambiguous else repeat(child) for i, child in enumerate(children) ]
return self.tree_class('_ambig', [self.node_builder(list(f[0])) for f in product(zip(*expand))])


def maybe_create_ambiguous_expander(tree_class, expansion, keep_all_tokens): def maybe_create_ambiguous_expander(tree_class, expansion, keep_all_tokens):
to_expand = [i for i, sym in enumerate(expansion) to_expand = [i for i, sym in enumerate(expansion)


Loading…
Cancel
Save