OLD | NEW |
(Empty) | |
| 1 # copyright 2003-2011 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 logilab-common. |
| 5 # |
| 6 # logilab-common is free software: you can redistribute it and/or modify it unde
r |
| 7 # the terms of the GNU Lesser General Public License as published by the Free |
| 8 # Software Foundation, either version 2.1 of the License, or (at your option) an
y |
| 9 # later version. |
| 10 # |
| 11 # logilab-common is distributed in the hope that it will be useful, but WITHOUT |
| 12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
| 14 # details. |
| 15 # |
| 16 # You should have received a copy of the GNU Lesser General Public License along |
| 17 # with logilab-common. If not, see <http://www.gnu.org/licenses/>. |
| 18 """A generic visitor abstract implementation. |
| 19 |
| 20 |
| 21 |
| 22 |
| 23 """ |
| 24 __docformat__ = "restructuredtext en" |
| 25 |
| 26 def no_filter(_): |
| 27 return 1 |
| 28 |
| 29 # Iterators ################################################################### |
| 30 class FilteredIterator(object): |
| 31 |
| 32 def __init__(self, node, list_func, filter_func=None): |
| 33 self._next = [(node, 0)] |
| 34 if filter_func is None: |
| 35 filter_func = no_filter |
| 36 self._list = list_func(node, filter_func) |
| 37 |
| 38 def next(self): |
| 39 try: |
| 40 return self._list.pop(0) |
| 41 except : |
| 42 return None |
| 43 |
| 44 # Base Visitor ################################################################ |
| 45 class Visitor(object): |
| 46 |
| 47 def __init__(self, iterator_class, filter_func=None): |
| 48 self._iter_class = iterator_class |
| 49 self.filter = filter_func |
| 50 |
| 51 def visit(self, node, *args, **kargs): |
| 52 """ |
| 53 launch the visit on a given node |
| 54 |
| 55 call 'open_visit' before the beginning of the visit, with extra args |
| 56 given |
| 57 when all nodes have been visited, call the 'close_visit' method |
| 58 """ |
| 59 self.open_visit(node, *args, **kargs) |
| 60 return self.close_visit(self._visit(node)) |
| 61 |
| 62 def _visit(self, node): |
| 63 iterator = self._get_iterator(node) |
| 64 n = iterator.next() |
| 65 while n: |
| 66 result = n.accept(self) |
| 67 n = iterator.next() |
| 68 return result |
| 69 |
| 70 def _get_iterator(self, node): |
| 71 return self._iter_class(node, self.filter) |
| 72 |
| 73 def open_visit(self, *args, **kargs): |
| 74 """ |
| 75 method called at the beginning of the visit |
| 76 """ |
| 77 pass |
| 78 |
| 79 def close_visit(self, result): |
| 80 """ |
| 81 method called at the end of the visit |
| 82 """ |
| 83 return result |
| 84 |
| 85 # standard visited mixin ###################################################### |
| 86 class VisitedMixIn(object): |
| 87 """ |
| 88 Visited interface allow node visitors to use the node |
| 89 """ |
| 90 def get_visit_name(self): |
| 91 """ |
| 92 return the visit name for the mixed class. When calling 'accept', the |
| 93 method <'visit_' + name returned by this method> will be called on the |
| 94 visitor |
| 95 """ |
| 96 try: |
| 97 return self.TYPE.replace('-', '_') |
| 98 except: |
| 99 return self.__class__.__name__.lower() |
| 100 |
| 101 def accept(self, visitor, *args, **kwargs): |
| 102 func = getattr(visitor, 'visit_%s' % self.get_visit_name()) |
| 103 return func(self, *args, **kwargs) |
| 104 |
| 105 def leave(self, visitor, *args, **kwargs): |
| 106 func = getattr(visitor, 'leave_%s' % self.get_visit_name()) |
| 107 return func(self, *args, **kwargs) |
OLD | NEW |