| @@ -19,17 +19,22 @@ class Transformer: | |||||
| Can be used to implement map or reduce. | Can be used to implement map or reduce. | ||||
| """ | """ | ||||
| def _call_userfunc(self, data, children, meta): | |||||
| def _call_userfunc(self, tree, new_children=None): | |||||
| # Assumes tree is already transformed | # Assumes tree is already transformed | ||||
| children = new_children if new_children is not None else tree.children | |||||
| try: | try: | ||||
| f = getattr(self, data) | |||||
| f = getattr(self, tree.data) | |||||
| except AttributeError: | except AttributeError: | ||||
| return self.__default__(data, children, meta) | |||||
| return self.__default__(tree.data, children, tree.meta) | |||||
| else: | else: | ||||
| if getattr(f, 'meta', False): | if getattr(f, 'meta', False): | ||||
| return f(children, meta) | |||||
| return f(children, tree.meta) | |||||
| elif getattr(f, 'inline', False): | elif getattr(f, 'inline', False): | ||||
| return f(*children) | return f(*children) | ||||
| elif getattr(f, 'whole_tree', False): | |||||
| if new_children is not None: | |||||
| raise NotImplementedError("Doesn't work with the base Transformer class") | |||||
| return f(tree) | |||||
| else: | else: | ||||
| return f(children) | return f(children) | ||||
| @@ -42,7 +47,7 @@ class Transformer: | |||||
| def _transform_tree(self, tree): | def _transform_tree(self, tree): | ||||
| children = list(self._transform_children(tree.children)) | children = list(self._transform_children(tree.children)) | ||||
| return self._call_userfunc(tree.data, children, tree.meta) | |||||
| return self._call_userfunc(tree, children) | |||||
| def transform(self, tree): | def transform(self, tree): | ||||
| return self._transform_tree(tree) | return self._transform_tree(tree) | ||||
| @@ -68,12 +73,13 @@ class Transformer: | |||||
| class InlineTransformer(Transformer): # XXX Deprecated | class InlineTransformer(Transformer): # XXX Deprecated | ||||
| def _call_userfunc(self, data, children, meta): | |||||
| def _call_userfunc(self, tree, new_children=None): | |||||
| # Assumes tree is already transformed | # Assumes tree is already transformed | ||||
| children = new_children if new_children is not None else tree.children | |||||
| try: | try: | ||||
| f = getattr(self, data) | |||||
| f = getattr(self, tree.data) | |||||
| except AttributeError: | except AttributeError: | ||||
| return self.__default__(data, children, meta) | |||||
| return self.__default__(tree.data, children, tree.meta) | |||||
| else: | else: | ||||
| return f(*children) | return f(*children) | ||||
| @@ -94,7 +100,7 @@ class TransformerChain(object): | |||||
| class Transformer_InPlace(Transformer): | class Transformer_InPlace(Transformer): | ||||
| "Non-recursive. Changes the tree in-place instead of returning new instances" | "Non-recursive. Changes the tree in-place instead of returning new instances" | ||||
| def _transform_tree(self, tree): # Cancel recursion | def _transform_tree(self, tree): # Cancel recursion | ||||
| return self._call_userfunc(tree.data, tree.children, tree.meta) | |||||
| return self._call_userfunc(tree) | |||||
| def transform(self, tree): | def transform(self, tree): | ||||
| for subtree in tree.iter_subtrees(): | for subtree in tree.iter_subtrees(): | ||||
| @@ -107,7 +113,7 @@ class Transformer_InPlaceRecursive(Transformer): | |||||
| "Recursive. Changes the tree in-place instead of returning new instances" | "Recursive. Changes the tree in-place instead of returning new instances" | ||||
| def _transform_tree(self, tree): | def _transform_tree(self, tree): | ||||
| tree.children = list(self._transform_children(tree.children)) | tree.children = list(self._transform_children(tree.children)) | ||||
| return self._call_userfunc(tree.data, tree.children, tree.meta) | |||||
| return self._call_userfunc(tree) | |||||
| @@ -218,8 +224,8 @@ def inline_args(obj): # XXX Deprecated | |||||
| def _visitor_args_func_dec(func, inline=False, meta=False): | |||||
| assert not (inline and meta) | |||||
| def _visitor_args_func_dec(func, inline=False, meta=False, whole_tree=False): | |||||
| assert [whole_tree, meta, inline].count(True) <= 1 | |||||
| def create_decorator(_f, with_self): | def create_decorator(_f, with_self): | ||||
| if with_self: | if with_self: | ||||
| def f(self, *args, **kwargs): | def f(self, *args, **kwargs): | ||||
| @@ -232,14 +238,15 @@ def _visitor_args_func_dec(func, inline=False, meta=False): | |||||
| f = smart_decorator(func, create_decorator) | f = smart_decorator(func, create_decorator) | ||||
| f.inline = inline | f.inline = inline | ||||
| f.meta = meta | f.meta = meta | ||||
| f.whole_tree = whole_tree | |||||
| return f | return f | ||||
| def v_args(inline=False, meta=False): | |||||
| def v_args(inline=False, meta=False, tree=False): | |||||
| "A convenience decorator factory, for modifying the behavior of user-supplied visitor methods" | "A convenience decorator factory, for modifying the behavior of user-supplied visitor methods" | ||||
| if inline and meta: | |||||
| raise ValueError("Visitor functions can either accept meta, or be inlined. Not both.") | |||||
| if [tree, meta, inline].count(True) > 1: | |||||
| raise ValueError("Visitor functions can either accept tree, or meta, or be inlined. These cannot be combined.") | |||||
| def _visitor_args_dec(obj): | def _visitor_args_dec(obj): | ||||
| return _apply_decorator(obj, _visitor_args_func_dec, inline=inline, meta=meta) | |||||
| return _apply_decorator(obj, _visitor_args_func_dec, inline=inline, meta=meta, whole_tree=tree) | |||||
| return _visitor_args_dec | return _visitor_args_dec | ||||