| @@ -14,8 +14,8 @@ from .parsers.lalr_parser import UnexpectedToken | |||
| from .common import is_terminal, GrammarError, LexerConf, ParserConf, PatternStr, PatternRE, TokenDef | |||
| from .grammar import RuleOptions, Rule | |||
| from .tree import Tree, Visitor, SlottedTree as ST | |||
| from .transformers import Transformer_Children, Transformer_ChildrenInline | |||
| from .tree import Tree, SlottedTree as ST | |||
| from .transformers import Transformer, Transformer_Children, Transformer_ChildrenInline, Visitor | |||
| __path__ = os.path.dirname(__file__) | |||
| IMPORT_PATHS = [os.path.join(__path__, 'grammars')] | |||
| @@ -200,17 +200,14 @@ class SimplifyRule_Visitor(Visitor): | |||
| # --> | |||
| # expansions( expansion(b, c, e), expansion(b, d, e) ) | |||
| while True: | |||
| self._flatten(tree) | |||
| for i, child in enumerate(tree.children): | |||
| if isinstance(child, Tree) and child.data == 'expansions': | |||
| tree.data = 'expansions' | |||
| tree.children = [self.visit(ST('expansion', [option if i==j else other | |||
| for j, other in enumerate(tree.children)])) | |||
| for option in set(child.children)] | |||
| break | |||
| else: | |||
| self._flatten(tree) | |||
| for i, child in enumerate(tree.children): | |||
| if isinstance(child, Tree) and child.data == 'expansions': | |||
| tree.data = 'expansions' | |||
| tree.children = [self.visit(ST('expansion', [option if i==j else other | |||
| for j, other in enumerate(tree.children)])) | |||
| for option in set(child.children)] | |||
| break | |||
| def alias(self, tree): | |||
| @@ -234,7 +231,7 @@ class RuleTreeToText(Transformer_Children): | |||
| return [sym.value for sym in symbols], None | |||
| def alias(self, x): | |||
| (expansion, _alias), alias = x | |||
| assert _alias is None, (alias, expansion, '-', _alias) | |||
| assert _alias is None, (alias, expansion, '-', _alias) # Double alias not allowed | |||
| return expansion, alias.value | |||
| @@ -14,7 +14,8 @@ | |||
| # Email : erezshin@gmail.com | |||
| from ..common import ParseError, UnexpectedToken, is_terminal | |||
| from ..tree import Tree, Transformer_NoRecurse | |||
| from ..tree import Tree | |||
| from ..transformers import InPlaceTransformer | |||
| from .grammar_analysis import GrammarAnalyzer | |||
| @@ -229,7 +230,7 @@ class Parser: | |||
| return ApplyCallbacks(self.postprocess).transform(tree) | |||
| class ApplyCallbacks(Transformer_NoRecurse): | |||
| class ApplyCallbacks(InPlaceTransformer): | |||
| def __init__(self, postprocess): | |||
| self.postprocess = postprocess | |||
| @@ -1,7 +1,7 @@ | |||
| from ..utils import compare | |||
| from functools import cmp_to_key | |||
| from ..tree import Tree, Visitor_NoRecurse | |||
| from ..tree import Tree | |||
| # Standard ambiguity resolver (uses comparison) | |||
| @@ -6,33 +6,25 @@ class Discard(Exception): | |||
| pass | |||
| class Transformer: | |||
| def _get_userfunc(self, name): | |||
| return getattr(self, name) | |||
| class Base: | |||
| def _call_userfunc(self, tree): | |||
| # Assumes tree is already transformed | |||
| try: | |||
| f = self._get_userfunc(tree.data) | |||
| except AttributeError: | |||
| return self.__default__(tree) | |||
| else: | |||
| return f(tree) | |||
| return getattr(self, tree.data, self.__default__)(tree) | |||
| def _transform(self, tree): | |||
| children = [] | |||
| for c in tree.children: | |||
| def __default__(self, tree): | |||
| return tree | |||
| class Transformer(Base): | |||
| def _transform_children(self, children): | |||
| for c in children: | |||
| try: | |||
| children.append(self._transform(c) if isinstance(c, Tree) else c) | |||
| yield self._transform(c) if isinstance(c, Tree) else c | |||
| except Discard: | |||
| pass | |||
| tree = Tree(tree.data, children) | |||
| def _transform(self, tree): | |||
| tree = Tree(tree.data, list(self._transform_children(tree.children))) | |||
| return self._call_userfunc(tree) | |||
| def __default__(self, tree): | |||
| return tree | |||
| def transform(self, tree): | |||
| return self._transform(tree) | |||
| @@ -43,7 +35,7 @@ class Transformer_Children(Transformer): | |||
| def _call_userfunc(self, tree): | |||
| # Assumes tree is already transformed | |||
| try: | |||
| f = self._get_userfunc(tree.data) | |||
| f = getattr(self, tree.data) | |||
| except AttributeError: | |||
| return self.__default__(tree) | |||
| else: | |||
| @@ -53,7 +45,7 @@ class Transformer_ChildrenInline(Transformer): | |||
| def _call_userfunc(self, tree): | |||
| # Assumes tree is already transformed | |||
| try: | |||
| f = self._get_userfunc(tree.data) | |||
| f = getattr(self, tree.data) | |||
| except AttributeError: | |||
| return self.__default__(tree) | |||
| else: | |||
| @@ -72,6 +64,45 @@ class TransformerChain(object): | |||
| def __mul__(self, other): | |||
| return TransformerChain(*self.transformers + (other,)) | |||
| class Visitor(Base): | |||
| # def visit(self, tree): | |||
| # for child in tree.children: | |||
| # if isinstance(child, Tree): | |||
| # self.visit(child) | |||
| # f = getattr(self, tree.data, self.__default__) | |||
| # f(tree) | |||
| # return tree | |||
| def visit(self, tree): | |||
| for subtree in tree.iter_subtrees(): | |||
| self._call_userfunc(subtree) | |||
| return tree | |||
| def __default__(self, tree): | |||
| pass | |||
| class InPlaceTransformer(Transformer): | |||
| # def _transform(self, tree): | |||
| # children = [] | |||
| # for c in tree.children: | |||
| # try: | |||
| # children.append(self._transform(c) if isinstance(c, Tree) else c) | |||
| # except Discard: | |||
| # pass | |||
| # tree.children = children | |||
| # return self._call_userfunc(tree) | |||
| def _transform(self, tree): | |||
| return self._call_userfunc(tree) | |||
| def transform(self, tree): | |||
| for subtree in tree.iter_subtrees(): | |||
| subtree.children = list(self._transform_children(subtree.children)) | |||
| return self._transform(tree) | |||
| #### XXX PSEUDOCODE TODO | |||
| @@ -12,8 +12,6 @@ class Meta: | |||
| ###{standalone | |||
| class Tree(object): | |||
| __slots__ = ('data', 'children', '_meta', 'rule') | |||
| def __init__(self, data, children): | |||
| self.data = data | |||
| self.children = children | |||
| @@ -141,77 +139,12 @@ class Transformer(object): | |||
| return TransformerChain(self, other) | |||
| class Discard(Exception): | |||
| pass | |||
| class TransformerChain(object): | |||
| def __init__(self, *transformers): | |||
| self.transformers = transformers | |||
| def transform(self, tree): | |||
| for t in self.transformers: | |||
| tree = t.transform(tree) | |||
| return tree | |||
| def __mul__(self, other): | |||
| return TransformerChain(*self.transformers + (other,)) | |||
| class InlineTransformer(Transformer): | |||
| def _get_func(self, name): # use super()._get_func | |||
| return inline_args(getattr(self, name)).__get__(self) | |||
| class Visitor(object): | |||
| def visit(self, tree): | |||
| for child in tree.children: | |||
| if isinstance(child, Tree): | |||
| self.visit(child) | |||
| f = getattr(self, tree.data, self.__default__) | |||
| f(tree) | |||
| return tree | |||
| def __default__(self, tree): | |||
| pass | |||
| class Visitor_NoRecurse(Visitor): | |||
| def visit(self, tree): | |||
| subtrees = list(tree.iter_subtrees()) | |||
| for subtree in (subtrees): | |||
| getattr(self, subtree.data, self.__default__)(subtree) | |||
| return tree | |||
| class Transformer_NoRecurse(Transformer): | |||
| def transform(self, tree): | |||
| subtrees = list(tree.iter_subtrees()) | |||
| def _t(t): | |||
| # Assumes t is already transformed | |||
| try: | |||
| f = self._get_func(t.data) | |||
| except AttributeError: | |||
| return self.__default__(t) | |||
| else: | |||
| return f(t) | |||
| for subtree in subtrees: | |||
| children = [] | |||
| for c in subtree.children: | |||
| try: | |||
| children.append(_t(c) if isinstance(c, Tree) else c) | |||
| except Discard: | |||
| pass | |||
| subtree.children = children | |||
| return _t(tree) | |||
| def __default__(self, t): | |||
| return t | |||
| ###} | |||