| @@ -13,7 +13,31 @@ class Discard(Exception): | |||||
| # Transformers | # Transformers | ||||
| class Transformer: | |||||
| class _Decoratable: | |||||
| @classmethod | |||||
| def _apply_decorator(cls, decorator, **kwargs): | |||||
| mro = getmro(cls) | |||||
| assert mro[0] is cls | |||||
| libmembers = {name for _cls in mro[1:] for name, _ in getmembers(_cls)} | |||||
| for name, value in getmembers(cls): | |||||
| # Make sure the function isn't inherited (unless it's overwritten) | |||||
| if name.startswith('_') or (name in libmembers and name not in cls.__dict__): | |||||
| continue | |||||
| if not callable(cls.__dict__[name]): | |||||
| continue | |||||
| # Skip if v_args already applied (at the function level) | |||||
| if hasattr(cls.__dict__[name], 'vargs_applied'): | |||||
| continue | |||||
| static = isinstance(cls.__dict__[name], (staticmethod, classmethod)) | |||||
| setattr(cls, name, decorator(value, static=static, **kwargs)) | |||||
| return cls | |||||
| class Transformer(_Decoratable): | |||||
| """Visits the tree recursively, starting with the leaves and finally the root (bottom-up) | """Visits the tree recursively, starting with the leaves and finally the root (bottom-up) | ||||
| Calls its methods (provided by user via inheritance) according to tree.data | Calls its methods (provided by user via inheritance) according to tree.data | ||||
| @@ -90,27 +114,6 @@ class Transformer: | |||||
| return token | return token | ||||
| @classmethod | |||||
| def _apply_decorator(cls, decorator, **kwargs): | |||||
| mro = getmro(cls) | |||||
| assert mro[0] is cls | |||||
| libmembers = {name for _cls in mro[1:] for name, _ in getmembers(_cls)} | |||||
| for name, value in getmembers(cls): | |||||
| # Make sure the function isn't inherited (unless it's overwritten) | |||||
| if name.startswith('_') or (name in libmembers and name not in cls.__dict__): | |||||
| continue | |||||
| if not callable(cls.__dict__[name]): | |||||
| continue | |||||
| # Skip if v_args already applied (at the function level) | |||||
| if hasattr(cls.__dict__[name], 'vargs_applied'): | |||||
| continue | |||||
| static = isinstance(cls.__dict__[name], (staticmethod, classmethod)) | |||||
| setattr(cls, name, decorator(value, static=static, **kwargs)) | |||||
| return cls | |||||
| class InlineTransformer(Transformer): # XXX Deprecated | class InlineTransformer(Transformer): # XXX Deprecated | ||||
| def _call_userfunc(self, tree, new_children=None): | def _call_userfunc(self, tree, new_children=None): | ||||
| @@ -221,7 +224,7 @@ def visit_children_decor(func): | |||||
| return inner | return inner | ||||
| class Interpreter: | |||||
| class Interpreter(_Decoratable): | |||||
| """Top-down visitor, recursive | """Top-down visitor, recursive | ||||
| Visits the tree, starting with the root and finally the leaves (top-down) | Visits the tree, starting with the root and finally the leaves (top-down) | ||||
| @@ -230,8 +233,14 @@ class Interpreter: | |||||
| Unlike Transformer and Visitor, the Interpreter doesn't automatically visit its sub-branches. | Unlike Transformer and Visitor, the Interpreter doesn't automatically visit its sub-branches. | ||||
| The user has to explicitly call visit_children, or use the @visit_children_decor | The user has to explicitly call visit_children, or use the @visit_children_decor | ||||
| """ | """ | ||||
| def visit(self, tree): | def visit(self, tree): | ||||
| return getattr(self, tree.data)(tree) | |||||
| f = getattr(self, tree.data) | |||||
| wrapper = getattr(f, 'visit_wrapper', None) | |||||
| if wrapper is not None: | |||||
| return f.visit_wrapper(f, tree.data, tree.children, tree.meta) | |||||
| else: | |||||
| return f(tree) | |||||
| def visit_children(self, tree): | def visit_children(self, tree): | ||||
| return [self.visit(child) if isinstance(child, Tree) else child | return [self.visit(child) if isinstance(child, Tree) else child | ||||