|
|
@@ -12,8 +12,10 @@ from math import isinf |
|
|
|
from collections import deque |
|
|
|
from operator import attrgetter |
|
|
|
from importlib import import_module |
|
|
|
from functools import partial |
|
|
|
|
|
|
|
from .. visitors import Discard |
|
|
|
from ..parse_tree_builder import AmbiguousIntermediateExpander |
|
|
|
from ..visitors import Discard |
|
|
|
from ..lexer import Token |
|
|
|
from ..utils import logger |
|
|
|
from ..tree import Tree |
|
|
@@ -497,6 +499,83 @@ class ForestToParseTree(ForestTransformer): |
|
|
|
self._on_cycle_retreat = False |
|
|
|
return super(ForestToParseTree, self).visit_token_node(node) |
|
|
|
|
|
|
|
def handles_ambiguity(func): |
|
|
|
"""Decorator for methods of subclasses of TreeForestTransformer. |
|
|
|
Denotes that the method should receive a list of transformed derivations.""" |
|
|
|
func.handles_ambiguity = True |
|
|
|
return func |
|
|
|
|
|
|
|
class TreeForestTransformer(ForestToParseTree): |
|
|
|
"""A ForestTransformer with a tree-Transformer-like interface. |
|
|
|
By default, it will construct a tree. |
|
|
|
|
|
|
|
Methods provided via inheritance are called based on the rule/symbol |
|
|
|
names of nodes in the forest. |
|
|
|
|
|
|
|
Methods that act on rules will receive a list of the results of the |
|
|
|
transformations of the rule's children. By default, trees and tokens. |
|
|
|
|
|
|
|
Methods that act on tokens will receive a Token. |
|
|
|
|
|
|
|
Alternatively, methods that act on rules may be annotated with |
|
|
|
`handles_ambiguity`. In this case, the function will receive a list |
|
|
|
of all the transformations of all the derivations of the rule. |
|
|
|
By default, a list of trees where each tree.data is equal to the |
|
|
|
rule name or one of its aliases. |
|
|
|
|
|
|
|
Non-tree transformations are made possible by override of |
|
|
|
`__default__`, `__default_token__`, and `__default_ambig__`. |
|
|
|
""" |
|
|
|
|
|
|
|
def __init__(self, tree_class=Tree, prioritizer=ForestSumVisitor(), resolve_ambiguity=True): |
|
|
|
super(TreeForestTransformer, self).__init__(tree_class, dict(), prioritizer, resolve_ambiguity) |
|
|
|
|
|
|
|
def __default__(self, name, data): |
|
|
|
"""Default operation on tree (for override). |
|
|
|
|
|
|
|
Returns a tree with name with data as children. |
|
|
|
""" |
|
|
|
return self.tree_class(name, data) |
|
|
|
|
|
|
|
def __default_ambig__(self, name, data): |
|
|
|
"""Default operation on ambiguous rule (for override). |
|
|
|
|
|
|
|
Wraps data in an '_ambig_ node if it contains more than |
|
|
|
one element.' |
|
|
|
""" |
|
|
|
if len(data) > 1: |
|
|
|
return self.tree_class('_ambig', data) |
|
|
|
elif data: |
|
|
|
return data[0] |
|
|
|
raise Discard |
|
|
|
|
|
|
|
def __default_token__(self, node): |
|
|
|
"""Default operation on Token (for override). |
|
|
|
|
|
|
|
Returns node |
|
|
|
""" |
|
|
|
return node |
|
|
|
|
|
|
|
def transform_token_node(self, node): |
|
|
|
return getattr(self, node.type, self.__default_token__)(node) |
|
|
|
|
|
|
|
def _call_rule_func(self, node, data): |
|
|
|
name = node.rule.alias or node.rule.options.template_source or node.rule.origin.name |
|
|
|
user_func = getattr(self, name, self.__default__) |
|
|
|
if user_func == self.__default__ or hasattr(user_func, 'handles_ambiguity'): |
|
|
|
user_func = partial(self.__default__, name) |
|
|
|
if not self.resolve_ambiguity: |
|
|
|
wrapper = partial(AmbiguousIntermediateExpander, self.tree_class) |
|
|
|
user_func = wrapper(user_func) |
|
|
|
return user_func(data) |
|
|
|
|
|
|
|
def _call_ambig_func(self, node, data): |
|
|
|
name = node.s.name |
|
|
|
user_func = getattr(self, name, self.__default_ambig__) |
|
|
|
if user_func == self.__default_ambig__ or not hasattr(user_func, 'handles_ambiguity'): |
|
|
|
user_func = partial(self.__default_ambig__, name) |
|
|
|
return user_func(data) |
|
|
|
|
|
|
|
class ForestToPyDotVisitor(ForestVisitor): |
|
|
|
""" |
|
|
|
A Forest visitor which writes the SPPF to a PNG. |
|
|
|