| Index: third_party/logilab/common/visitor.py
|
| diff --git a/third_party/logilab/common/visitor.py b/third_party/logilab/common/visitor.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..802d2befced41e4574243f02e8f6ef202e7859eb
|
| --- /dev/null
|
| +++ b/third_party/logilab/common/visitor.py
|
| @@ -0,0 +1,107 @@
|
| +# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
|
| +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
|
| +#
|
| +# This file is part of logilab-common.
|
| +#
|
| +# logilab-common is free software: you can redistribute it and/or modify it under
|
| +# the terms of the GNU Lesser General Public License as published by the Free
|
| +# Software Foundation, either version 2.1 of the License, or (at your option) any
|
| +# later version.
|
| +#
|
| +# logilab-common is distributed in the hope that it will be useful, but WITHOUT
|
| +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
| +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
| +# details.
|
| +#
|
| +# You should have received a copy of the GNU Lesser General Public License along
|
| +# with logilab-common. If not, see <http://www.gnu.org/licenses/>.
|
| +"""A generic visitor abstract implementation.
|
| +
|
| +
|
| +
|
| +
|
| +"""
|
| +__docformat__ = "restructuredtext en"
|
| +
|
| +def no_filter(_):
|
| + return 1
|
| +
|
| +# Iterators ###################################################################
|
| +class FilteredIterator(object):
|
| +
|
| + def __init__(self, node, list_func, filter_func=None):
|
| + self._next = [(node, 0)]
|
| + if filter_func is None:
|
| + filter_func = no_filter
|
| + self._list = list_func(node, filter_func)
|
| +
|
| + def next(self):
|
| + try:
|
| + return self._list.pop(0)
|
| + except :
|
| + return None
|
| +
|
| +# Base Visitor ################################################################
|
| +class Visitor(object):
|
| +
|
| + def __init__(self, iterator_class, filter_func=None):
|
| + self._iter_class = iterator_class
|
| + self.filter = filter_func
|
| +
|
| + def visit(self, node, *args, **kargs):
|
| + """
|
| + launch the visit on a given node
|
| +
|
| + call 'open_visit' before the beginning of the visit, with extra args
|
| + given
|
| + when all nodes have been visited, call the 'close_visit' method
|
| + """
|
| + self.open_visit(node, *args, **kargs)
|
| + return self.close_visit(self._visit(node))
|
| +
|
| + def _visit(self, node):
|
| + iterator = self._get_iterator(node)
|
| + n = iterator.next()
|
| + while n:
|
| + result = n.accept(self)
|
| + n = iterator.next()
|
| + return result
|
| +
|
| + def _get_iterator(self, node):
|
| + return self._iter_class(node, self.filter)
|
| +
|
| + def open_visit(self, *args, **kargs):
|
| + """
|
| + method called at the beginning of the visit
|
| + """
|
| + pass
|
| +
|
| + def close_visit(self, result):
|
| + """
|
| + method called at the end of the visit
|
| + """
|
| + return result
|
| +
|
| +# standard visited mixin ######################################################
|
| +class VisitedMixIn(object):
|
| + """
|
| + Visited interface allow node visitors to use the node
|
| + """
|
| + def get_visit_name(self):
|
| + """
|
| + return the visit name for the mixed class. When calling 'accept', the
|
| + method <'visit_' + name returned by this method> will be called on the
|
| + visitor
|
| + """
|
| + try:
|
| + return self.TYPE.replace('-', '_')
|
| + except:
|
| + return self.__class__.__name__.lower()
|
| +
|
| + def accept(self, visitor, *args, **kwargs):
|
| + func = getattr(visitor, 'visit_%s' % self.get_visit_name())
|
| + return func(self, *args, **kwargs)
|
| +
|
| + def leave(self, visitor, *args, **kwargs):
|
| + func = getattr(visitor, 'leave_%s' % self.get_visit_name())
|
| + return func(self, *args, **kwargs)
|
|
|