| # -*- coding: utf-8 -*- | 
 | """ | 
 |     jinja2.visitor | 
 |     ~~~~~~~~~~~~~~ | 
 |  | 
 |     This module implements a visitor for the nodes. | 
 |  | 
 |     :copyright: (c) 2010 by the Jinja Team. | 
 |     :license: BSD. | 
 | """ | 
 | from jinja2.nodes import Node | 
 |  | 
 |  | 
 | class NodeVisitor(object): | 
 |     """Walks the abstract syntax tree and call visitor functions for every | 
 |     node found.  The visitor functions may return values which will be | 
 |     forwarded by the `visit` method. | 
 |  | 
 |     Per default the visitor functions for the nodes are ``'visit_'`` + | 
 |     class name of the node.  So a `TryFinally` node visit function would | 
 |     be `visit_TryFinally`.  This behavior can be changed by overriding | 
 |     the `get_visitor` function.  If no visitor function exists for a node | 
 |     (return value `None`) the `generic_visit` visitor is used instead. | 
 |     """ | 
 |  | 
 |     def get_visitor(self, node): | 
 |         """Return the visitor function for this node or `None` if no visitor | 
 |         exists for this node.  In that case the generic visit function is | 
 |         used instead. | 
 |         """ | 
 |         method = 'visit_' + node.__class__.__name__ | 
 |         return getattr(self, method, None) | 
 |  | 
 |     def visit(self, node, *args, **kwargs): | 
 |         """Visit a node.""" | 
 |         f = self.get_visitor(node) | 
 |         if f is not None: | 
 |             return f(node, *args, **kwargs) | 
 |         return self.generic_visit(node, *args, **kwargs) | 
 |  | 
 |     def generic_visit(self, node, *args, **kwargs): | 
 |         """Called if no explicit visitor function exists for a node.""" | 
 |         for node in node.iter_child_nodes(): | 
 |             self.visit(node, *args, **kwargs) | 
 |  | 
 |  | 
 | class NodeTransformer(NodeVisitor): | 
 |     """Walks the abstract syntax tree and allows modifications of nodes. | 
 |  | 
 |     The `NodeTransformer` will walk the AST and use the return value of the | 
 |     visitor functions to replace or remove the old node.  If the return | 
 |     value of the visitor function is `None` the node will be removed | 
 |     from the previous location otherwise it's replaced with the return | 
 |     value.  The return value may be the original node in which case no | 
 |     replacement takes place. | 
 |     """ | 
 |  | 
 |     def generic_visit(self, node, *args, **kwargs): | 
 |         for field, old_value in node.iter_fields(): | 
 |             if isinstance(old_value, list): | 
 |                 new_values = [] | 
 |                 for value in old_value: | 
 |                     if isinstance(value, Node): | 
 |                         value = self.visit(value, *args, **kwargs) | 
 |                         if value is None: | 
 |                             continue | 
 |                         elif not isinstance(value, Node): | 
 |                             new_values.extend(value) | 
 |                             continue | 
 |                     new_values.append(value) | 
 |                 old_value[:] = new_values | 
 |             elif isinstance(old_value, Node): | 
 |                 new_node = self.visit(old_value, *args, **kwargs) | 
 |                 if new_node is None: | 
 |                     delattr(node, field) | 
 |                 else: | 
 |                     setattr(node, field, new_node) | 
 |         return node | 
 |  | 
 |     def visit_list(self, node, *args, **kwargs): | 
 |         """As transformers may return lists in some places this method | 
 |         can be used to enforce a list as return value. | 
 |         """ | 
 |         rv = self.visit(node, *args, **kwargs) | 
 |         if not isinstance(rv, list): | 
 |             rv = [rv] | 
 |         return rv |