| @@ -195,6 +195,86 @@ def maybe_create_ambiguous_expander(tree_class, expansion, keep_all_tokens): | |||||
| if to_expand: | if to_expand: | ||||
| return partial(AmbiguousExpander, to_expand, tree_class) | return partial(AmbiguousExpander, to_expand, tree_class) | ||||
| class AmbiguousIntermediateExpander: | |||||
| """ | |||||
| Propagate ambiguous intermediate nodes and their derivations up to the | |||||
| current rule. | |||||
| In general, converts | |||||
| rule | |||||
| _iambig | |||||
| _inter | |||||
| someChildren1 | |||||
| ... | |||||
| _inter | |||||
| someChildren2 | |||||
| ... | |||||
| someChildren3 | |||||
| ... | |||||
| to | |||||
| _ambig | |||||
| rule | |||||
| someChildren1 | |||||
| ... | |||||
| someChildren3 | |||||
| ... | |||||
| rule | |||||
| someChildren2 | |||||
| ... | |||||
| someChildren3 | |||||
| ... | |||||
| rule | |||||
| childrenFromNestedIambigs | |||||
| ... | |||||
| someChildren3 | |||||
| ... | |||||
| ... | |||||
| propagating up any nested '_iambig' nodes along the way. | |||||
| """ | |||||
| def __init__(self, tree_class, node_builder): | |||||
| self.node_builder = node_builder | |||||
| self.tree_class = tree_class | |||||
| def __call__(self, children): | |||||
| def _is_iambig_tree(child): | |||||
| return hasattr(child, 'data') and child.data == '_iambig' | |||||
| def _collapse_iambig(children): | |||||
| """ | |||||
| Recursively flatten the derivations of the parent of an '_iambig' | |||||
| node. Returns a list of '_inter' nodes guaranteed not | |||||
| to contain any nested '_iambig' nodes, or None if children does | |||||
| not contain an '_iambig' node. | |||||
| """ | |||||
| # Due to the structure of the SPPF, | |||||
| # an '_iambig' node can only appear as the first child | |||||
| if children and _is_iambig_tree(children[0]): | |||||
| iambig_node = children[0] | |||||
| result = [] | |||||
| for grandchild in iambig_node.children: | |||||
| collapsed = _collapse_iambig(grandchild.children) | |||||
| if collapsed: | |||||
| for child in collapsed: | |||||
| child.children += children[1:] | |||||
| result += collapsed | |||||
| else: | |||||
| new_tree = self.tree_class('_inter', grandchild.children + children[1:]) | |||||
| result.append(new_tree) | |||||
| return result | |||||
| collapsed = _collapse_iambig(children) | |||||
| if collapsed: | |||||
| processed_nodes = [self.node_builder(c.children) for c in collapsed] | |||||
| return self.tree_class('_ambig', processed_nodes) | |||||
| return self.node_builder(children) | |||||
| def ptb_inline_args(func): | def ptb_inline_args(func): | ||||
| @wraps(func) | @wraps(func) | ||||
| def f(children): | def f(children): | ||||
| @@ -239,6 +319,7 @@ class ParseTreeBuilder: | |||||
| maybe_create_child_filter(rule.expansion, keep_all_tokens, self.ambiguous, options.empty_indices if self.maybe_placeholders else None), | maybe_create_child_filter(rule.expansion, keep_all_tokens, self.ambiguous, options.empty_indices if self.maybe_placeholders else None), | ||||
| self.propagate_positions and PropagatePositions, | self.propagate_positions and PropagatePositions, | ||||
| self.ambiguous and maybe_create_ambiguous_expander(self.tree_class, rule.expansion, keep_all_tokens), | self.ambiguous and maybe_create_ambiguous_expander(self.tree_class, rule.expansion, keep_all_tokens), | ||||
| self.ambiguous and partial(AmbiguousIntermediateExpander, self.tree_class) | |||||
| ])) | ])) | ||||
| yield rule, wrapper_chain | yield rule, wrapper_chain | ||||