You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					88 lines
				
				3.2 KiB
			
		
		
			
		
	
	
					88 lines
				
				3.2 KiB
			| 
											8 years ago
										 | # -*- coding: utf-8 -*-
 | ||
|  | """
 | ||
|  |     jinja2.visitor
 | ||
|  |     ~~~~~~~~~~~~~~
 | ||
|  | 
 | ||
|  |     This module implements a visitor for the nodes.
 | ||
|  | 
 | ||
|  |     :copyright: (c) 2017 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
 |