|
|
@@ -13,7 +13,31 @@ class Discard(Exception): |
|
|
|
|
|
|
|
# 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) |
|
|
|
|
|
|
|
Calls its methods (provided by user via inheritance) according to tree.data |
|
|
@@ -90,27 +114,6 @@ class Transformer: |
|
|
|
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 |
|
|
|
def _call_userfunc(self, tree, new_children=None): |
|
|
@@ -221,7 +224,7 @@ def visit_children_decor(func): |
|
|
|
return inner |
|
|
|
|
|
|
|
|
|
|
|
class Interpreter: |
|
|
|
class Interpreter(_Decoratable): |
|
|
|
"""Top-down visitor, recursive |
|
|
|
|
|
|
|
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. |
|
|
|
The user has to explicitly call visit_children, or use the @visit_children_decor |
|
|
|
""" |
|
|
|
|
|
|
|
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): |
|
|
|
return [self.visit(child) if isinstance(child, Tree) else child |
|
|
|