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