Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / astroid / transforms.py @ 745

History | View | Annotate | Download (3.74 KB)

1
# copyright 2003-2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
3
#
4
# This file is part of astroid.
5
#
6
# astroid is free software: you can redistribute it and/or modify it
7
# under the terms of the GNU Lesser General Public License as published by the
8
# Free Software Foundation, either version 2.1 of the License, or (at your
9
# option) any later version.
10
#
11
# astroid is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
14
# for more details.
15
#
16
# You should have received a copy of the GNU Lesser General Public License along
17
# with astroid. If not, see <http://www.gnu.org/licenses/>.
18

    
19
import collections
20
import warnings
21

    
22

    
23
class TransformVisitor(object):
24
    """A visitor for handling transforms.
25

26
    The standard approach of using it is to call
27
    :meth:`~visit` with an *astroid* module and the class
28
    will take care of the rest, walking the tree and running the
29
    transforms for each encountered node.
30
    """
31

    
32
    def __init__(self):
33
        self.transforms = collections.defaultdict(list)
34

    
35
    def _transform(self, node):
36
        """Call matching transforms for the given node if any and return the
37
        transformed node.
38
        """
39
        cls = node.__class__
40
        if cls not in self.transforms:
41
            # no transform registered for this class of node
42
            return node
43

    
44
        transforms = self.transforms[cls]
45
        orig_node = node  # copy the reference
46
        for transform_func, predicate in transforms:
47
            if predicate is None or predicate(node):
48
                ret = transform_func(node)
49
                # if the transformation function returns something, it's
50
                # expected to be a replacement for the node
51
                if ret is not None:
52
                    if node is not orig_node:
53
                        # node has already be modified by some previous
54
                        # transformation, warn about it
55
                        warnings.warn('node %s substituted multiple times' % node)
56
                    node = ret
57
        return node
58

    
59
    def _visit(self, node):
60
        if hasattr(node, '_astroid_fields'):
61
            for field in node._astroid_fields:
62
                value = getattr(node, field)
63
                visited = self._visit_generic(value)
64
                setattr(node, field, visited)
65
        return self._transform(node)
66

    
67
    def _visit_generic(self, node):
68
        if isinstance(node, list):
69
            return [self._visit_generic(child) for child in node]
70
        elif isinstance(node, tuple):
71
            return tuple(self._visit_generic(child) for child in node)
72
        else:
73
            return self._visit(node)
74

    
75
    def register_transform(self, node_class, transform, predicate=None):
76
        """Register `transform(node)` function to be applied on the given
77
        astroid's `node_class` if `predicate` is None or returns true
78
        when called with the node as argument.
79

80
        The transform function may return a value which is then used to
81
        substitute the original node in the tree.
82
        """
83
        self.transforms[node_class].append((transform, predicate))
84

    
85
    def unregister_transform(self, node_class, transform, predicate=None):
86
        """Unregister the given transform."""
87
        self.transforms[node_class].remove((transform, predicate))
88

    
89
    def visit(self, module):
90
        """Walk the given astroid *tree* and transform each encountered node
91

92
        Only the nodes which have transforms registered will actually
93
        be replaced or changed.
94
        """
95
        module.body = [self._visit(child) for child in module.body]
96
        return self._transform(module)