xref: /aosp_15_r20/external/libchrome/third_party/jinja2/visitor.py (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker# -*- coding: utf-8 -*-
2*635a8641SAndroid Build Coastguard Worker"""
3*635a8641SAndroid Build Coastguard Worker    jinja2.visitor
4*635a8641SAndroid Build Coastguard Worker    ~~~~~~~~~~~~~~
5*635a8641SAndroid Build Coastguard Worker
6*635a8641SAndroid Build Coastguard Worker    This module implements a visitor for the nodes.
7*635a8641SAndroid Build Coastguard Worker
8*635a8641SAndroid Build Coastguard Worker    :copyright: (c) 2017 by the Jinja Team.
9*635a8641SAndroid Build Coastguard Worker    :license: BSD.
10*635a8641SAndroid Build Coastguard Worker"""
11*635a8641SAndroid Build Coastguard Workerfrom jinja2.nodes import Node
12*635a8641SAndroid Build Coastguard Worker
13*635a8641SAndroid Build Coastguard Worker
14*635a8641SAndroid Build Coastguard Workerclass NodeVisitor(object):
15*635a8641SAndroid Build Coastguard Worker    """Walks the abstract syntax tree and call visitor functions for every
16*635a8641SAndroid Build Coastguard Worker    node found.  The visitor functions may return values which will be
17*635a8641SAndroid Build Coastguard Worker    forwarded by the `visit` method.
18*635a8641SAndroid Build Coastguard Worker
19*635a8641SAndroid Build Coastguard Worker    Per default the visitor functions for the nodes are ``'visit_'`` +
20*635a8641SAndroid Build Coastguard Worker    class name of the node.  So a `TryFinally` node visit function would
21*635a8641SAndroid Build Coastguard Worker    be `visit_TryFinally`.  This behavior can be changed by overriding
22*635a8641SAndroid Build Coastguard Worker    the `get_visitor` function.  If no visitor function exists for a node
23*635a8641SAndroid Build Coastguard Worker    (return value `None`) the `generic_visit` visitor is used instead.
24*635a8641SAndroid Build Coastguard Worker    """
25*635a8641SAndroid Build Coastguard Worker
26*635a8641SAndroid Build Coastguard Worker    def get_visitor(self, node):
27*635a8641SAndroid Build Coastguard Worker        """Return the visitor function for this node or `None` if no visitor
28*635a8641SAndroid Build Coastguard Worker        exists for this node.  In that case the generic visit function is
29*635a8641SAndroid Build Coastguard Worker        used instead.
30*635a8641SAndroid Build Coastguard Worker        """
31*635a8641SAndroid Build Coastguard Worker        method = 'visit_' + node.__class__.__name__
32*635a8641SAndroid Build Coastguard Worker        return getattr(self, method, None)
33*635a8641SAndroid Build Coastguard Worker
34*635a8641SAndroid Build Coastguard Worker    def visit(self, node, *args, **kwargs):
35*635a8641SAndroid Build Coastguard Worker        """Visit a node."""
36*635a8641SAndroid Build Coastguard Worker        f = self.get_visitor(node)
37*635a8641SAndroid Build Coastguard Worker        if f is not None:
38*635a8641SAndroid Build Coastguard Worker            return f(node, *args, **kwargs)
39*635a8641SAndroid Build Coastguard Worker        return self.generic_visit(node, *args, **kwargs)
40*635a8641SAndroid Build Coastguard Worker
41*635a8641SAndroid Build Coastguard Worker    def generic_visit(self, node, *args, **kwargs):
42*635a8641SAndroid Build Coastguard Worker        """Called if no explicit visitor function exists for a node."""
43*635a8641SAndroid Build Coastguard Worker        for node in node.iter_child_nodes():
44*635a8641SAndroid Build Coastguard Worker            self.visit(node, *args, **kwargs)
45*635a8641SAndroid Build Coastguard Worker
46*635a8641SAndroid Build Coastguard Worker
47*635a8641SAndroid Build Coastguard Workerclass NodeTransformer(NodeVisitor):
48*635a8641SAndroid Build Coastguard Worker    """Walks the abstract syntax tree and allows modifications of nodes.
49*635a8641SAndroid Build Coastguard Worker
50*635a8641SAndroid Build Coastguard Worker    The `NodeTransformer` will walk the AST and use the return value of the
51*635a8641SAndroid Build Coastguard Worker    visitor functions to replace or remove the old node.  If the return
52*635a8641SAndroid Build Coastguard Worker    value of the visitor function is `None` the node will be removed
53*635a8641SAndroid Build Coastguard Worker    from the previous location otherwise it's replaced with the return
54*635a8641SAndroid Build Coastguard Worker    value.  The return value may be the original node in which case no
55*635a8641SAndroid Build Coastguard Worker    replacement takes place.
56*635a8641SAndroid Build Coastguard Worker    """
57*635a8641SAndroid Build Coastguard Worker
58*635a8641SAndroid Build Coastguard Worker    def generic_visit(self, node, *args, **kwargs):
59*635a8641SAndroid Build Coastguard Worker        for field, old_value in node.iter_fields():
60*635a8641SAndroid Build Coastguard Worker            if isinstance(old_value, list):
61*635a8641SAndroid Build Coastguard Worker                new_values = []
62*635a8641SAndroid Build Coastguard Worker                for value in old_value:
63*635a8641SAndroid Build Coastguard Worker                    if isinstance(value, Node):
64*635a8641SAndroid Build Coastguard Worker                        value = self.visit(value, *args, **kwargs)
65*635a8641SAndroid Build Coastguard Worker                        if value is None:
66*635a8641SAndroid Build Coastguard Worker                            continue
67*635a8641SAndroid Build Coastguard Worker                        elif not isinstance(value, Node):
68*635a8641SAndroid Build Coastguard Worker                            new_values.extend(value)
69*635a8641SAndroid Build Coastguard Worker                            continue
70*635a8641SAndroid Build Coastguard Worker                    new_values.append(value)
71*635a8641SAndroid Build Coastguard Worker                old_value[:] = new_values
72*635a8641SAndroid Build Coastguard Worker            elif isinstance(old_value, Node):
73*635a8641SAndroid Build Coastguard Worker                new_node = self.visit(old_value, *args, **kwargs)
74*635a8641SAndroid Build Coastguard Worker                if new_node is None:
75*635a8641SAndroid Build Coastguard Worker                    delattr(node, field)
76*635a8641SAndroid Build Coastguard Worker                else:
77*635a8641SAndroid Build Coastguard Worker                    setattr(node, field, new_node)
78*635a8641SAndroid Build Coastguard Worker        return node
79*635a8641SAndroid Build Coastguard Worker
80*635a8641SAndroid Build Coastguard Worker    def visit_list(self, node, *args, **kwargs):
81*635a8641SAndroid Build Coastguard Worker        """As transformers may return lists in some places this method
82*635a8641SAndroid Build Coastguard Worker        can be used to enforce a list as return value.
83*635a8641SAndroid Build Coastguard Worker        """
84*635a8641SAndroid Build Coastguard Worker        rv = self.visit(node, *args, **kwargs)
85*635a8641SAndroid Build Coastguard Worker        if not isinstance(rv, list):
86*635a8641SAndroid Build Coastguard Worker            rv = [rv]
87*635a8641SAndroid Build Coastguard Worker        return rv
88