xref: /aosp_15_r20/external/libchrome/third_party/jinja2/compiler.py (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker# -*- coding: utf-8 -*-
2*635a8641SAndroid Build Coastguard Worker"""
3*635a8641SAndroid Build Coastguard Worker    jinja2.compiler
4*635a8641SAndroid Build Coastguard Worker    ~~~~~~~~~~~~~~~
5*635a8641SAndroid Build Coastguard Worker
6*635a8641SAndroid Build Coastguard Worker    Compiles nodes into python code.
7*635a8641SAndroid Build Coastguard Worker
8*635a8641SAndroid Build Coastguard Worker    :copyright: (c) 2017 by the Jinja Team.
9*635a8641SAndroid Build Coastguard Worker    :license: BSD, see LICENSE for more details.
10*635a8641SAndroid Build Coastguard Worker"""
11*635a8641SAndroid Build Coastguard Workerfrom itertools import chain
12*635a8641SAndroid Build Coastguard Workerfrom copy import deepcopy
13*635a8641SAndroid Build Coastguard Workerfrom keyword import iskeyword as is_python_keyword
14*635a8641SAndroid Build Coastguard Workerfrom functools import update_wrapper
15*635a8641SAndroid Build Coastguard Workerfrom jinja2 import nodes
16*635a8641SAndroid Build Coastguard Workerfrom jinja2.nodes import EvalContext
17*635a8641SAndroid Build Coastguard Workerfrom jinja2.visitor import NodeVisitor
18*635a8641SAndroid Build Coastguard Workerfrom jinja2.optimizer import Optimizer
19*635a8641SAndroid Build Coastguard Workerfrom jinja2.exceptions import TemplateAssertionError
20*635a8641SAndroid Build Coastguard Workerfrom jinja2.utils import Markup, concat, escape
21*635a8641SAndroid Build Coastguard Workerfrom jinja2._compat import range_type, text_type, string_types, \
22*635a8641SAndroid Build Coastguard Worker     iteritems, NativeStringIO, imap, izip
23*635a8641SAndroid Build Coastguard Workerfrom jinja2.idtracking import Symbols, VAR_LOAD_PARAMETER, \
24*635a8641SAndroid Build Coastguard Worker     VAR_LOAD_RESOLVE, VAR_LOAD_ALIAS, VAR_LOAD_UNDEFINED
25*635a8641SAndroid Build Coastguard Worker
26*635a8641SAndroid Build Coastguard Worker
27*635a8641SAndroid Build Coastguard Workeroperators = {
28*635a8641SAndroid Build Coastguard Worker    'eq':       '==',
29*635a8641SAndroid Build Coastguard Worker    'ne':       '!=',
30*635a8641SAndroid Build Coastguard Worker    'gt':       '>',
31*635a8641SAndroid Build Coastguard Worker    'gteq':     '>=',
32*635a8641SAndroid Build Coastguard Worker    'lt':       '<',
33*635a8641SAndroid Build Coastguard Worker    'lteq':     '<=',
34*635a8641SAndroid Build Coastguard Worker    'in':       'in',
35*635a8641SAndroid Build Coastguard Worker    'notin':    'not in'
36*635a8641SAndroid Build Coastguard Worker}
37*635a8641SAndroid Build Coastguard Worker
38*635a8641SAndroid Build Coastguard Worker# what method to iterate over items do we want to use for dict iteration
39*635a8641SAndroid Build Coastguard Worker# in generated code?  on 2.x let's go with iteritems, on 3.x with items
40*635a8641SAndroid Build Coastguard Workerif hasattr(dict, 'iteritems'):
41*635a8641SAndroid Build Coastguard Worker    dict_item_iter = 'iteritems'
42*635a8641SAndroid Build Coastguard Workerelse:
43*635a8641SAndroid Build Coastguard Worker    dict_item_iter = 'items'
44*635a8641SAndroid Build Coastguard Worker
45*635a8641SAndroid Build Coastguard Workercode_features = ['division']
46*635a8641SAndroid Build Coastguard Worker
47*635a8641SAndroid Build Coastguard Worker# does this python version support generator stops? (PEP 0479)
48*635a8641SAndroid Build Coastguard Workertry:
49*635a8641SAndroid Build Coastguard Worker    exec('from __future__ import generator_stop')
50*635a8641SAndroid Build Coastguard Worker    code_features.append('generator_stop')
51*635a8641SAndroid Build Coastguard Workerexcept SyntaxError:
52*635a8641SAndroid Build Coastguard Worker    pass
53*635a8641SAndroid Build Coastguard Worker
54*635a8641SAndroid Build Coastguard Worker# does this python version support yield from?
55*635a8641SAndroid Build Coastguard Workertry:
56*635a8641SAndroid Build Coastguard Worker    exec('def f(): yield from x()')
57*635a8641SAndroid Build Coastguard Workerexcept SyntaxError:
58*635a8641SAndroid Build Coastguard Worker    supports_yield_from = False
59*635a8641SAndroid Build Coastguard Workerelse:
60*635a8641SAndroid Build Coastguard Worker    supports_yield_from = True
61*635a8641SAndroid Build Coastguard Worker
62*635a8641SAndroid Build Coastguard Worker
63*635a8641SAndroid Build Coastguard Workerdef optimizeconst(f):
64*635a8641SAndroid Build Coastguard Worker    def new_func(self, node, frame, **kwargs):
65*635a8641SAndroid Build Coastguard Worker        # Only optimize if the frame is not volatile
66*635a8641SAndroid Build Coastguard Worker        if self.optimized and not frame.eval_ctx.volatile:
67*635a8641SAndroid Build Coastguard Worker            new_node = self.optimizer.visit(node, frame.eval_ctx)
68*635a8641SAndroid Build Coastguard Worker            if new_node != node:
69*635a8641SAndroid Build Coastguard Worker                return self.visit(new_node, frame)
70*635a8641SAndroid Build Coastguard Worker        return f(self, node, frame, **kwargs)
71*635a8641SAndroid Build Coastguard Worker    return update_wrapper(new_func, f)
72*635a8641SAndroid Build Coastguard Worker
73*635a8641SAndroid Build Coastguard Worker
74*635a8641SAndroid Build Coastguard Workerdef generate(node, environment, name, filename, stream=None,
75*635a8641SAndroid Build Coastguard Worker             defer_init=False, optimized=True):
76*635a8641SAndroid Build Coastguard Worker    """Generate the python source for a node tree."""
77*635a8641SAndroid Build Coastguard Worker    if not isinstance(node, nodes.Template):
78*635a8641SAndroid Build Coastguard Worker        raise TypeError('Can\'t compile non template nodes')
79*635a8641SAndroid Build Coastguard Worker    generator = environment.code_generator_class(environment, name, filename,
80*635a8641SAndroid Build Coastguard Worker                                                 stream, defer_init,
81*635a8641SAndroid Build Coastguard Worker                                                 optimized)
82*635a8641SAndroid Build Coastguard Worker    generator.visit(node)
83*635a8641SAndroid Build Coastguard Worker    if stream is None:
84*635a8641SAndroid Build Coastguard Worker        return generator.stream.getvalue()
85*635a8641SAndroid Build Coastguard Worker
86*635a8641SAndroid Build Coastguard Worker
87*635a8641SAndroid Build Coastguard Workerdef has_safe_repr(value):
88*635a8641SAndroid Build Coastguard Worker    """Does the node have a safe representation?"""
89*635a8641SAndroid Build Coastguard Worker    if value is None or value is NotImplemented or value is Ellipsis:
90*635a8641SAndroid Build Coastguard Worker        return True
91*635a8641SAndroid Build Coastguard Worker    if type(value) in (bool, int, float, complex, range_type, Markup) + string_types:
92*635a8641SAndroid Build Coastguard Worker        return True
93*635a8641SAndroid Build Coastguard Worker    if type(value) in (tuple, list, set, frozenset):
94*635a8641SAndroid Build Coastguard Worker        for item in value:
95*635a8641SAndroid Build Coastguard Worker            if not has_safe_repr(item):
96*635a8641SAndroid Build Coastguard Worker                return False
97*635a8641SAndroid Build Coastguard Worker        return True
98*635a8641SAndroid Build Coastguard Worker    elif type(value) is dict:
99*635a8641SAndroid Build Coastguard Worker        for key, value in iteritems(value):
100*635a8641SAndroid Build Coastguard Worker            if not has_safe_repr(key):
101*635a8641SAndroid Build Coastguard Worker                return False
102*635a8641SAndroid Build Coastguard Worker            if not has_safe_repr(value):
103*635a8641SAndroid Build Coastguard Worker                return False
104*635a8641SAndroid Build Coastguard Worker        return True
105*635a8641SAndroid Build Coastguard Worker    return False
106*635a8641SAndroid Build Coastguard Worker
107*635a8641SAndroid Build Coastguard Worker
108*635a8641SAndroid Build Coastguard Workerdef find_undeclared(nodes, names):
109*635a8641SAndroid Build Coastguard Worker    """Check if the names passed are accessed undeclared.  The return value
110*635a8641SAndroid Build Coastguard Worker    is a set of all the undeclared names from the sequence of names found.
111*635a8641SAndroid Build Coastguard Worker    """
112*635a8641SAndroid Build Coastguard Worker    visitor = UndeclaredNameVisitor(names)
113*635a8641SAndroid Build Coastguard Worker    try:
114*635a8641SAndroid Build Coastguard Worker        for node in nodes:
115*635a8641SAndroid Build Coastguard Worker            visitor.visit(node)
116*635a8641SAndroid Build Coastguard Worker    except VisitorExit:
117*635a8641SAndroid Build Coastguard Worker        pass
118*635a8641SAndroid Build Coastguard Worker    return visitor.undeclared
119*635a8641SAndroid Build Coastguard Worker
120*635a8641SAndroid Build Coastguard Worker
121*635a8641SAndroid Build Coastguard Workerclass MacroRef(object):
122*635a8641SAndroid Build Coastguard Worker
123*635a8641SAndroid Build Coastguard Worker    def __init__(self, node):
124*635a8641SAndroid Build Coastguard Worker        self.node = node
125*635a8641SAndroid Build Coastguard Worker        self.accesses_caller = False
126*635a8641SAndroid Build Coastguard Worker        self.accesses_kwargs = False
127*635a8641SAndroid Build Coastguard Worker        self.accesses_varargs = False
128*635a8641SAndroid Build Coastguard Worker
129*635a8641SAndroid Build Coastguard Worker
130*635a8641SAndroid Build Coastguard Workerclass Frame(object):
131*635a8641SAndroid Build Coastguard Worker    """Holds compile time information for us."""
132*635a8641SAndroid Build Coastguard Worker
133*635a8641SAndroid Build Coastguard Worker    def __init__(self, eval_ctx, parent=None, level=None):
134*635a8641SAndroid Build Coastguard Worker        self.eval_ctx = eval_ctx
135*635a8641SAndroid Build Coastguard Worker        self.symbols = Symbols(parent and parent.symbols or None,
136*635a8641SAndroid Build Coastguard Worker                               level=level)
137*635a8641SAndroid Build Coastguard Worker
138*635a8641SAndroid Build Coastguard Worker        # a toplevel frame is the root + soft frames such as if conditions.
139*635a8641SAndroid Build Coastguard Worker        self.toplevel = False
140*635a8641SAndroid Build Coastguard Worker
141*635a8641SAndroid Build Coastguard Worker        # the root frame is basically just the outermost frame, so no if
142*635a8641SAndroid Build Coastguard Worker        # conditions.  This information is used to optimize inheritance
143*635a8641SAndroid Build Coastguard Worker        # situations.
144*635a8641SAndroid Build Coastguard Worker        self.rootlevel = False
145*635a8641SAndroid Build Coastguard Worker
146*635a8641SAndroid Build Coastguard Worker        # in some dynamic inheritance situations the compiler needs to add
147*635a8641SAndroid Build Coastguard Worker        # write tests around output statements.
148*635a8641SAndroid Build Coastguard Worker        self.require_output_check = parent and parent.require_output_check
149*635a8641SAndroid Build Coastguard Worker
150*635a8641SAndroid Build Coastguard Worker        # inside some tags we are using a buffer rather than yield statements.
151*635a8641SAndroid Build Coastguard Worker        # this for example affects {% filter %} or {% macro %}.  If a frame
152*635a8641SAndroid Build Coastguard Worker        # is buffered this variable points to the name of the list used as
153*635a8641SAndroid Build Coastguard Worker        # buffer.
154*635a8641SAndroid Build Coastguard Worker        self.buffer = None
155*635a8641SAndroid Build Coastguard Worker
156*635a8641SAndroid Build Coastguard Worker        # the name of the block we're in, otherwise None.
157*635a8641SAndroid Build Coastguard Worker        self.block = parent and parent.block or None
158*635a8641SAndroid Build Coastguard Worker
159*635a8641SAndroid Build Coastguard Worker        # the parent of this frame
160*635a8641SAndroid Build Coastguard Worker        self.parent = parent
161*635a8641SAndroid Build Coastguard Worker
162*635a8641SAndroid Build Coastguard Worker        if parent is not None:
163*635a8641SAndroid Build Coastguard Worker            self.buffer = parent.buffer
164*635a8641SAndroid Build Coastguard Worker
165*635a8641SAndroid Build Coastguard Worker    def copy(self):
166*635a8641SAndroid Build Coastguard Worker        """Create a copy of the current one."""
167*635a8641SAndroid Build Coastguard Worker        rv = object.__new__(self.__class__)
168*635a8641SAndroid Build Coastguard Worker        rv.__dict__.update(self.__dict__)
169*635a8641SAndroid Build Coastguard Worker        rv.symbols = self.symbols.copy()
170*635a8641SAndroid Build Coastguard Worker        return rv
171*635a8641SAndroid Build Coastguard Worker
172*635a8641SAndroid Build Coastguard Worker    def inner(self, isolated=False):
173*635a8641SAndroid Build Coastguard Worker        """Return an inner frame."""
174*635a8641SAndroid Build Coastguard Worker        if isolated:
175*635a8641SAndroid Build Coastguard Worker            return Frame(self.eval_ctx, level=self.symbols.level + 1)
176*635a8641SAndroid Build Coastguard Worker        return Frame(self.eval_ctx, self)
177*635a8641SAndroid Build Coastguard Worker
178*635a8641SAndroid Build Coastguard Worker    def soft(self):
179*635a8641SAndroid Build Coastguard Worker        """Return a soft frame.  A soft frame may not be modified as
180*635a8641SAndroid Build Coastguard Worker        standalone thing as it shares the resources with the frame it
181*635a8641SAndroid Build Coastguard Worker        was created of, but it's not a rootlevel frame any longer.
182*635a8641SAndroid Build Coastguard Worker
183*635a8641SAndroid Build Coastguard Worker        This is only used to implement if-statements.
184*635a8641SAndroid Build Coastguard Worker        """
185*635a8641SAndroid Build Coastguard Worker        rv = self.copy()
186*635a8641SAndroid Build Coastguard Worker        rv.rootlevel = False
187*635a8641SAndroid Build Coastguard Worker        return rv
188*635a8641SAndroid Build Coastguard Worker
189*635a8641SAndroid Build Coastguard Worker    __copy__ = copy
190*635a8641SAndroid Build Coastguard Worker
191*635a8641SAndroid Build Coastguard Worker
192*635a8641SAndroid Build Coastguard Workerclass VisitorExit(RuntimeError):
193*635a8641SAndroid Build Coastguard Worker    """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
194*635a8641SAndroid Build Coastguard Worker
195*635a8641SAndroid Build Coastguard Worker
196*635a8641SAndroid Build Coastguard Workerclass DependencyFinderVisitor(NodeVisitor):
197*635a8641SAndroid Build Coastguard Worker    """A visitor that collects filter and test calls."""
198*635a8641SAndroid Build Coastguard Worker
199*635a8641SAndroid Build Coastguard Worker    def __init__(self):
200*635a8641SAndroid Build Coastguard Worker        self.filters = set()
201*635a8641SAndroid Build Coastguard Worker        self.tests = set()
202*635a8641SAndroid Build Coastguard Worker
203*635a8641SAndroid Build Coastguard Worker    def visit_Filter(self, node):
204*635a8641SAndroid Build Coastguard Worker        self.generic_visit(node)
205*635a8641SAndroid Build Coastguard Worker        self.filters.add(node.name)
206*635a8641SAndroid Build Coastguard Worker
207*635a8641SAndroid Build Coastguard Worker    def visit_Test(self, node):
208*635a8641SAndroid Build Coastguard Worker        self.generic_visit(node)
209*635a8641SAndroid Build Coastguard Worker        self.tests.add(node.name)
210*635a8641SAndroid Build Coastguard Worker
211*635a8641SAndroid Build Coastguard Worker    def visit_Block(self, node):
212*635a8641SAndroid Build Coastguard Worker        """Stop visiting at blocks."""
213*635a8641SAndroid Build Coastguard Worker
214*635a8641SAndroid Build Coastguard Worker
215*635a8641SAndroid Build Coastguard Workerclass UndeclaredNameVisitor(NodeVisitor):
216*635a8641SAndroid Build Coastguard Worker    """A visitor that checks if a name is accessed without being
217*635a8641SAndroid Build Coastguard Worker    declared.  This is different from the frame visitor as it will
218*635a8641SAndroid Build Coastguard Worker    not stop at closure frames.
219*635a8641SAndroid Build Coastguard Worker    """
220*635a8641SAndroid Build Coastguard Worker
221*635a8641SAndroid Build Coastguard Worker    def __init__(self, names):
222*635a8641SAndroid Build Coastguard Worker        self.names = set(names)
223*635a8641SAndroid Build Coastguard Worker        self.undeclared = set()
224*635a8641SAndroid Build Coastguard Worker
225*635a8641SAndroid Build Coastguard Worker    def visit_Name(self, node):
226*635a8641SAndroid Build Coastguard Worker        if node.ctx == 'load' and node.name in self.names:
227*635a8641SAndroid Build Coastguard Worker            self.undeclared.add(node.name)
228*635a8641SAndroid Build Coastguard Worker            if self.undeclared == self.names:
229*635a8641SAndroid Build Coastguard Worker                raise VisitorExit()
230*635a8641SAndroid Build Coastguard Worker        else:
231*635a8641SAndroid Build Coastguard Worker            self.names.discard(node.name)
232*635a8641SAndroid Build Coastguard Worker
233*635a8641SAndroid Build Coastguard Worker    def visit_Block(self, node):
234*635a8641SAndroid Build Coastguard Worker        """Stop visiting a blocks."""
235*635a8641SAndroid Build Coastguard Worker
236*635a8641SAndroid Build Coastguard Worker
237*635a8641SAndroid Build Coastguard Workerclass CompilerExit(Exception):
238*635a8641SAndroid Build Coastguard Worker    """Raised if the compiler encountered a situation where it just
239*635a8641SAndroid Build Coastguard Worker    doesn't make sense to further process the code.  Any block that
240*635a8641SAndroid Build Coastguard Worker    raises such an exception is not further processed.
241*635a8641SAndroid Build Coastguard Worker    """
242*635a8641SAndroid Build Coastguard Worker
243*635a8641SAndroid Build Coastguard Worker
244*635a8641SAndroid Build Coastguard Workerclass CodeGenerator(NodeVisitor):
245*635a8641SAndroid Build Coastguard Worker
246*635a8641SAndroid Build Coastguard Worker    def __init__(self, environment, name, filename, stream=None,
247*635a8641SAndroid Build Coastguard Worker                 defer_init=False, optimized=True):
248*635a8641SAndroid Build Coastguard Worker        if stream is None:
249*635a8641SAndroid Build Coastguard Worker            stream = NativeStringIO()
250*635a8641SAndroid Build Coastguard Worker        self.environment = environment
251*635a8641SAndroid Build Coastguard Worker        self.name = name
252*635a8641SAndroid Build Coastguard Worker        self.filename = filename
253*635a8641SAndroid Build Coastguard Worker        self.stream = stream
254*635a8641SAndroid Build Coastguard Worker        self.created_block_context = False
255*635a8641SAndroid Build Coastguard Worker        self.defer_init = defer_init
256*635a8641SAndroid Build Coastguard Worker        self.optimized = optimized
257*635a8641SAndroid Build Coastguard Worker        if optimized:
258*635a8641SAndroid Build Coastguard Worker            self.optimizer = Optimizer(environment)
259*635a8641SAndroid Build Coastguard Worker
260*635a8641SAndroid Build Coastguard Worker        # aliases for imports
261*635a8641SAndroid Build Coastguard Worker        self.import_aliases = {}
262*635a8641SAndroid Build Coastguard Worker
263*635a8641SAndroid Build Coastguard Worker        # a registry for all blocks.  Because blocks are moved out
264*635a8641SAndroid Build Coastguard Worker        # into the global python scope they are registered here
265*635a8641SAndroid Build Coastguard Worker        self.blocks = {}
266*635a8641SAndroid Build Coastguard Worker
267*635a8641SAndroid Build Coastguard Worker        # the number of extends statements so far
268*635a8641SAndroid Build Coastguard Worker        self.extends_so_far = 0
269*635a8641SAndroid Build Coastguard Worker
270*635a8641SAndroid Build Coastguard Worker        # some templates have a rootlevel extends.  In this case we
271*635a8641SAndroid Build Coastguard Worker        # can safely assume that we're a child template and do some
272*635a8641SAndroid Build Coastguard Worker        # more optimizations.
273*635a8641SAndroid Build Coastguard Worker        self.has_known_extends = False
274*635a8641SAndroid Build Coastguard Worker
275*635a8641SAndroid Build Coastguard Worker        # the current line number
276*635a8641SAndroid Build Coastguard Worker        self.code_lineno = 1
277*635a8641SAndroid Build Coastguard Worker
278*635a8641SAndroid Build Coastguard Worker        # registry of all filters and tests (global, not block local)
279*635a8641SAndroid Build Coastguard Worker        self.tests = {}
280*635a8641SAndroid Build Coastguard Worker        self.filters = {}
281*635a8641SAndroid Build Coastguard Worker
282*635a8641SAndroid Build Coastguard Worker        # the debug information
283*635a8641SAndroid Build Coastguard Worker        self.debug_info = []
284*635a8641SAndroid Build Coastguard Worker        self._write_debug_info = None
285*635a8641SAndroid Build Coastguard Worker
286*635a8641SAndroid Build Coastguard Worker        # the number of new lines before the next write()
287*635a8641SAndroid Build Coastguard Worker        self._new_lines = 0
288*635a8641SAndroid Build Coastguard Worker
289*635a8641SAndroid Build Coastguard Worker        # the line number of the last written statement
290*635a8641SAndroid Build Coastguard Worker        self._last_line = 0
291*635a8641SAndroid Build Coastguard Worker
292*635a8641SAndroid Build Coastguard Worker        # true if nothing was written so far.
293*635a8641SAndroid Build Coastguard Worker        self._first_write = True
294*635a8641SAndroid Build Coastguard Worker
295*635a8641SAndroid Build Coastguard Worker        # used by the `temporary_identifier` method to get new
296*635a8641SAndroid Build Coastguard Worker        # unique, temporary identifier
297*635a8641SAndroid Build Coastguard Worker        self._last_identifier = 0
298*635a8641SAndroid Build Coastguard Worker
299*635a8641SAndroid Build Coastguard Worker        # the current indentation
300*635a8641SAndroid Build Coastguard Worker        self._indentation = 0
301*635a8641SAndroid Build Coastguard Worker
302*635a8641SAndroid Build Coastguard Worker        # Tracks toplevel assignments
303*635a8641SAndroid Build Coastguard Worker        self._assign_stack = []
304*635a8641SAndroid Build Coastguard Worker
305*635a8641SAndroid Build Coastguard Worker        # Tracks parameter definition blocks
306*635a8641SAndroid Build Coastguard Worker        self._param_def_block = []
307*635a8641SAndroid Build Coastguard Worker
308*635a8641SAndroid Build Coastguard Worker        # Tracks the current context.
309*635a8641SAndroid Build Coastguard Worker        self._context_reference_stack = ['context']
310*635a8641SAndroid Build Coastguard Worker
311*635a8641SAndroid Build Coastguard Worker    # -- Various compilation helpers
312*635a8641SAndroid Build Coastguard Worker
313*635a8641SAndroid Build Coastguard Worker    def fail(self, msg, lineno):
314*635a8641SAndroid Build Coastguard Worker        """Fail with a :exc:`TemplateAssertionError`."""
315*635a8641SAndroid Build Coastguard Worker        raise TemplateAssertionError(msg, lineno, self.name, self.filename)
316*635a8641SAndroid Build Coastguard Worker
317*635a8641SAndroid Build Coastguard Worker    def temporary_identifier(self):
318*635a8641SAndroid Build Coastguard Worker        """Get a new unique identifier."""
319*635a8641SAndroid Build Coastguard Worker        self._last_identifier += 1
320*635a8641SAndroid Build Coastguard Worker        return 't_%d' % self._last_identifier
321*635a8641SAndroid Build Coastguard Worker
322*635a8641SAndroid Build Coastguard Worker    def buffer(self, frame):
323*635a8641SAndroid Build Coastguard Worker        """Enable buffering for the frame from that point onwards."""
324*635a8641SAndroid Build Coastguard Worker        frame.buffer = self.temporary_identifier()
325*635a8641SAndroid Build Coastguard Worker        self.writeline('%s = []' % frame.buffer)
326*635a8641SAndroid Build Coastguard Worker
327*635a8641SAndroid Build Coastguard Worker    def return_buffer_contents(self, frame, force_unescaped=False):
328*635a8641SAndroid Build Coastguard Worker        """Return the buffer contents of the frame."""
329*635a8641SAndroid Build Coastguard Worker        if not force_unescaped:
330*635a8641SAndroid Build Coastguard Worker            if frame.eval_ctx.volatile:
331*635a8641SAndroid Build Coastguard Worker                self.writeline('if context.eval_ctx.autoescape:')
332*635a8641SAndroid Build Coastguard Worker                self.indent()
333*635a8641SAndroid Build Coastguard Worker                self.writeline('return Markup(concat(%s))' % frame.buffer)
334*635a8641SAndroid Build Coastguard Worker                self.outdent()
335*635a8641SAndroid Build Coastguard Worker                self.writeline('else:')
336*635a8641SAndroid Build Coastguard Worker                self.indent()
337*635a8641SAndroid Build Coastguard Worker                self.writeline('return concat(%s)' % frame.buffer)
338*635a8641SAndroid Build Coastguard Worker                self.outdent()
339*635a8641SAndroid Build Coastguard Worker                return
340*635a8641SAndroid Build Coastguard Worker            elif frame.eval_ctx.autoescape:
341*635a8641SAndroid Build Coastguard Worker                self.writeline('return Markup(concat(%s))' % frame.buffer)
342*635a8641SAndroid Build Coastguard Worker                return
343*635a8641SAndroid Build Coastguard Worker        self.writeline('return concat(%s)' % frame.buffer)
344*635a8641SAndroid Build Coastguard Worker
345*635a8641SAndroid Build Coastguard Worker    def indent(self):
346*635a8641SAndroid Build Coastguard Worker        """Indent by one."""
347*635a8641SAndroid Build Coastguard Worker        self._indentation += 1
348*635a8641SAndroid Build Coastguard Worker
349*635a8641SAndroid Build Coastguard Worker    def outdent(self, step=1):
350*635a8641SAndroid Build Coastguard Worker        """Outdent by step."""
351*635a8641SAndroid Build Coastguard Worker        self._indentation -= step
352*635a8641SAndroid Build Coastguard Worker
353*635a8641SAndroid Build Coastguard Worker    def start_write(self, frame, node=None):
354*635a8641SAndroid Build Coastguard Worker        """Yield or write into the frame buffer."""
355*635a8641SAndroid Build Coastguard Worker        if frame.buffer is None:
356*635a8641SAndroid Build Coastguard Worker            self.writeline('yield ', node)
357*635a8641SAndroid Build Coastguard Worker        else:
358*635a8641SAndroid Build Coastguard Worker            self.writeline('%s.append(' % frame.buffer, node)
359*635a8641SAndroid Build Coastguard Worker
360*635a8641SAndroid Build Coastguard Worker    def end_write(self, frame):
361*635a8641SAndroid Build Coastguard Worker        """End the writing process started by `start_write`."""
362*635a8641SAndroid Build Coastguard Worker        if frame.buffer is not None:
363*635a8641SAndroid Build Coastguard Worker            self.write(')')
364*635a8641SAndroid Build Coastguard Worker
365*635a8641SAndroid Build Coastguard Worker    def simple_write(self, s, frame, node=None):
366*635a8641SAndroid Build Coastguard Worker        """Simple shortcut for start_write + write + end_write."""
367*635a8641SAndroid Build Coastguard Worker        self.start_write(frame, node)
368*635a8641SAndroid Build Coastguard Worker        self.write(s)
369*635a8641SAndroid Build Coastguard Worker        self.end_write(frame)
370*635a8641SAndroid Build Coastguard Worker
371*635a8641SAndroid Build Coastguard Worker    def blockvisit(self, nodes, frame):
372*635a8641SAndroid Build Coastguard Worker        """Visit a list of nodes as block in a frame.  If the current frame
373*635a8641SAndroid Build Coastguard Worker        is no buffer a dummy ``if 0: yield None`` is written automatically.
374*635a8641SAndroid Build Coastguard Worker        """
375*635a8641SAndroid Build Coastguard Worker        try:
376*635a8641SAndroid Build Coastguard Worker            self.writeline('pass')
377*635a8641SAndroid Build Coastguard Worker            for node in nodes:
378*635a8641SAndroid Build Coastguard Worker                self.visit(node, frame)
379*635a8641SAndroid Build Coastguard Worker        except CompilerExit:
380*635a8641SAndroid Build Coastguard Worker            pass
381*635a8641SAndroid Build Coastguard Worker
382*635a8641SAndroid Build Coastguard Worker    def write(self, x):
383*635a8641SAndroid Build Coastguard Worker        """Write a string into the output stream."""
384*635a8641SAndroid Build Coastguard Worker        if self._new_lines:
385*635a8641SAndroid Build Coastguard Worker            if not self._first_write:
386*635a8641SAndroid Build Coastguard Worker                self.stream.write('\n' * self._new_lines)
387*635a8641SAndroid Build Coastguard Worker                self.code_lineno += self._new_lines
388*635a8641SAndroid Build Coastguard Worker                if self._write_debug_info is not None:
389*635a8641SAndroid Build Coastguard Worker                    self.debug_info.append((self._write_debug_info,
390*635a8641SAndroid Build Coastguard Worker                                            self.code_lineno))
391*635a8641SAndroid Build Coastguard Worker                    self._write_debug_info = None
392*635a8641SAndroid Build Coastguard Worker            self._first_write = False
393*635a8641SAndroid Build Coastguard Worker            self.stream.write('    ' * self._indentation)
394*635a8641SAndroid Build Coastguard Worker            self._new_lines = 0
395*635a8641SAndroid Build Coastguard Worker        self.stream.write(x)
396*635a8641SAndroid Build Coastguard Worker
397*635a8641SAndroid Build Coastguard Worker    def writeline(self, x, node=None, extra=0):
398*635a8641SAndroid Build Coastguard Worker        """Combination of newline and write."""
399*635a8641SAndroid Build Coastguard Worker        self.newline(node, extra)
400*635a8641SAndroid Build Coastguard Worker        self.write(x)
401*635a8641SAndroid Build Coastguard Worker
402*635a8641SAndroid Build Coastguard Worker    def newline(self, node=None, extra=0):
403*635a8641SAndroid Build Coastguard Worker        """Add one or more newlines before the next write."""
404*635a8641SAndroid Build Coastguard Worker        self._new_lines = max(self._new_lines, 1 + extra)
405*635a8641SAndroid Build Coastguard Worker        if node is not None and node.lineno != self._last_line:
406*635a8641SAndroid Build Coastguard Worker            self._write_debug_info = node.lineno
407*635a8641SAndroid Build Coastguard Worker            self._last_line = node.lineno
408*635a8641SAndroid Build Coastguard Worker
409*635a8641SAndroid Build Coastguard Worker    def signature(self, node, frame, extra_kwargs=None):
410*635a8641SAndroid Build Coastguard Worker        """Writes a function call to the stream for the current node.
411*635a8641SAndroid Build Coastguard Worker        A leading comma is added automatically.  The extra keyword
412*635a8641SAndroid Build Coastguard Worker        arguments may not include python keywords otherwise a syntax
413*635a8641SAndroid Build Coastguard Worker        error could occour.  The extra keyword arguments should be given
414*635a8641SAndroid Build Coastguard Worker        as python dict.
415*635a8641SAndroid Build Coastguard Worker        """
416*635a8641SAndroid Build Coastguard Worker        # if any of the given keyword arguments is a python keyword
417*635a8641SAndroid Build Coastguard Worker        # we have to make sure that no invalid call is created.
418*635a8641SAndroid Build Coastguard Worker        kwarg_workaround = False
419*635a8641SAndroid Build Coastguard Worker        for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
420*635a8641SAndroid Build Coastguard Worker            if is_python_keyword(kwarg):
421*635a8641SAndroid Build Coastguard Worker                kwarg_workaround = True
422*635a8641SAndroid Build Coastguard Worker                break
423*635a8641SAndroid Build Coastguard Worker
424*635a8641SAndroid Build Coastguard Worker        for arg in node.args:
425*635a8641SAndroid Build Coastguard Worker            self.write(', ')
426*635a8641SAndroid Build Coastguard Worker            self.visit(arg, frame)
427*635a8641SAndroid Build Coastguard Worker
428*635a8641SAndroid Build Coastguard Worker        if not kwarg_workaround:
429*635a8641SAndroid Build Coastguard Worker            for kwarg in node.kwargs:
430*635a8641SAndroid Build Coastguard Worker                self.write(', ')
431*635a8641SAndroid Build Coastguard Worker                self.visit(kwarg, frame)
432*635a8641SAndroid Build Coastguard Worker            if extra_kwargs is not None:
433*635a8641SAndroid Build Coastguard Worker                for key, value in iteritems(extra_kwargs):
434*635a8641SAndroid Build Coastguard Worker                    self.write(', %s=%s' % (key, value))
435*635a8641SAndroid Build Coastguard Worker        if node.dyn_args:
436*635a8641SAndroid Build Coastguard Worker            self.write(', *')
437*635a8641SAndroid Build Coastguard Worker            self.visit(node.dyn_args, frame)
438*635a8641SAndroid Build Coastguard Worker
439*635a8641SAndroid Build Coastguard Worker        if kwarg_workaround:
440*635a8641SAndroid Build Coastguard Worker            if node.dyn_kwargs is not None:
441*635a8641SAndroid Build Coastguard Worker                self.write(', **dict({')
442*635a8641SAndroid Build Coastguard Worker            else:
443*635a8641SAndroid Build Coastguard Worker                self.write(', **{')
444*635a8641SAndroid Build Coastguard Worker            for kwarg in node.kwargs:
445*635a8641SAndroid Build Coastguard Worker                self.write('%r: ' % kwarg.key)
446*635a8641SAndroid Build Coastguard Worker                self.visit(kwarg.value, frame)
447*635a8641SAndroid Build Coastguard Worker                self.write(', ')
448*635a8641SAndroid Build Coastguard Worker            if extra_kwargs is not None:
449*635a8641SAndroid Build Coastguard Worker                for key, value in iteritems(extra_kwargs):
450*635a8641SAndroid Build Coastguard Worker                    self.write('%r: %s, ' % (key, value))
451*635a8641SAndroid Build Coastguard Worker            if node.dyn_kwargs is not None:
452*635a8641SAndroid Build Coastguard Worker                self.write('}, **')
453*635a8641SAndroid Build Coastguard Worker                self.visit(node.dyn_kwargs, frame)
454*635a8641SAndroid Build Coastguard Worker                self.write(')')
455*635a8641SAndroid Build Coastguard Worker            else:
456*635a8641SAndroid Build Coastguard Worker                self.write('}')
457*635a8641SAndroid Build Coastguard Worker
458*635a8641SAndroid Build Coastguard Worker        elif node.dyn_kwargs is not None:
459*635a8641SAndroid Build Coastguard Worker            self.write(', **')
460*635a8641SAndroid Build Coastguard Worker            self.visit(node.dyn_kwargs, frame)
461*635a8641SAndroid Build Coastguard Worker
462*635a8641SAndroid Build Coastguard Worker    def pull_dependencies(self, nodes):
463*635a8641SAndroid Build Coastguard Worker        """Pull all the dependencies."""
464*635a8641SAndroid Build Coastguard Worker        visitor = DependencyFinderVisitor()
465*635a8641SAndroid Build Coastguard Worker        for node in nodes:
466*635a8641SAndroid Build Coastguard Worker            visitor.visit(node)
467*635a8641SAndroid Build Coastguard Worker        for dependency in 'filters', 'tests':
468*635a8641SAndroid Build Coastguard Worker            mapping = getattr(self, dependency)
469*635a8641SAndroid Build Coastguard Worker            for name in getattr(visitor, dependency):
470*635a8641SAndroid Build Coastguard Worker                if name not in mapping:
471*635a8641SAndroid Build Coastguard Worker                    mapping[name] = self.temporary_identifier()
472*635a8641SAndroid Build Coastguard Worker                self.writeline('%s = environment.%s[%r]' %
473*635a8641SAndroid Build Coastguard Worker                               (mapping[name], dependency, name))
474*635a8641SAndroid Build Coastguard Worker
475*635a8641SAndroid Build Coastguard Worker    def enter_frame(self, frame):
476*635a8641SAndroid Build Coastguard Worker        undefs = []
477*635a8641SAndroid Build Coastguard Worker        for target, (action, param) in iteritems(frame.symbols.loads):
478*635a8641SAndroid Build Coastguard Worker            if action == VAR_LOAD_PARAMETER:
479*635a8641SAndroid Build Coastguard Worker                pass
480*635a8641SAndroid Build Coastguard Worker            elif action == VAR_LOAD_RESOLVE:
481*635a8641SAndroid Build Coastguard Worker                self.writeline('%s = %s(%r)' %
482*635a8641SAndroid Build Coastguard Worker                               (target, self.get_resolve_func(), param))
483*635a8641SAndroid Build Coastguard Worker            elif action == VAR_LOAD_ALIAS:
484*635a8641SAndroid Build Coastguard Worker                self.writeline('%s = %s' % (target, param))
485*635a8641SAndroid Build Coastguard Worker            elif action == VAR_LOAD_UNDEFINED:
486*635a8641SAndroid Build Coastguard Worker                undefs.append(target)
487*635a8641SAndroid Build Coastguard Worker            else:
488*635a8641SAndroid Build Coastguard Worker                raise NotImplementedError('unknown load instruction')
489*635a8641SAndroid Build Coastguard Worker        if undefs:
490*635a8641SAndroid Build Coastguard Worker            self.writeline('%s = missing' % ' = '.join(undefs))
491*635a8641SAndroid Build Coastguard Worker
492*635a8641SAndroid Build Coastguard Worker    def leave_frame(self, frame, with_python_scope=False):
493*635a8641SAndroid Build Coastguard Worker        if not with_python_scope:
494*635a8641SAndroid Build Coastguard Worker            undefs = []
495*635a8641SAndroid Build Coastguard Worker            for target, _ in iteritems(frame.symbols.loads):
496*635a8641SAndroid Build Coastguard Worker                undefs.append(target)
497*635a8641SAndroid Build Coastguard Worker            if undefs:
498*635a8641SAndroid Build Coastguard Worker                self.writeline('%s = missing' % ' = '.join(undefs))
499*635a8641SAndroid Build Coastguard Worker
500*635a8641SAndroid Build Coastguard Worker    def func(self, name):
501*635a8641SAndroid Build Coastguard Worker        if self.environment.is_async:
502*635a8641SAndroid Build Coastguard Worker            return 'async def %s' % name
503*635a8641SAndroid Build Coastguard Worker        return 'def %s' % name
504*635a8641SAndroid Build Coastguard Worker
505*635a8641SAndroid Build Coastguard Worker    def macro_body(self, node, frame):
506*635a8641SAndroid Build Coastguard Worker        """Dump the function def of a macro or call block."""
507*635a8641SAndroid Build Coastguard Worker        frame = frame.inner()
508*635a8641SAndroid Build Coastguard Worker        frame.symbols.analyze_node(node)
509*635a8641SAndroid Build Coastguard Worker        macro_ref = MacroRef(node)
510*635a8641SAndroid Build Coastguard Worker
511*635a8641SAndroid Build Coastguard Worker        explicit_caller = None
512*635a8641SAndroid Build Coastguard Worker        skip_special_params = set()
513*635a8641SAndroid Build Coastguard Worker        args = []
514*635a8641SAndroid Build Coastguard Worker        for idx, arg in enumerate(node.args):
515*635a8641SAndroid Build Coastguard Worker            if arg.name == 'caller':
516*635a8641SAndroid Build Coastguard Worker                explicit_caller = idx
517*635a8641SAndroid Build Coastguard Worker            if arg.name in ('kwargs', 'varargs'):
518*635a8641SAndroid Build Coastguard Worker                skip_special_params.add(arg.name)
519*635a8641SAndroid Build Coastguard Worker            args.append(frame.symbols.ref(arg.name))
520*635a8641SAndroid Build Coastguard Worker
521*635a8641SAndroid Build Coastguard Worker        undeclared = find_undeclared(node.body, ('caller', 'kwargs', 'varargs'))
522*635a8641SAndroid Build Coastguard Worker
523*635a8641SAndroid Build Coastguard Worker        if 'caller' in undeclared:
524*635a8641SAndroid Build Coastguard Worker            # In older Jinja2 versions there was a bug that allowed caller
525*635a8641SAndroid Build Coastguard Worker            # to retain the special behavior even if it was mentioned in
526*635a8641SAndroid Build Coastguard Worker            # the argument list.  However thankfully this was only really
527*635a8641SAndroid Build Coastguard Worker            # working if it was the last argument.  So we are explicitly
528*635a8641SAndroid Build Coastguard Worker            # checking this now and error out if it is anywhere else in
529*635a8641SAndroid Build Coastguard Worker            # the argument list.
530*635a8641SAndroid Build Coastguard Worker            if explicit_caller is not None:
531*635a8641SAndroid Build Coastguard Worker                try:
532*635a8641SAndroid Build Coastguard Worker                    node.defaults[explicit_caller - len(node.args)]
533*635a8641SAndroid Build Coastguard Worker                except IndexError:
534*635a8641SAndroid Build Coastguard Worker                    self.fail('When defining macros or call blocks the '
535*635a8641SAndroid Build Coastguard Worker                              'special "caller" argument must be omitted '
536*635a8641SAndroid Build Coastguard Worker                              'or be given a default.', node.lineno)
537*635a8641SAndroid Build Coastguard Worker            else:
538*635a8641SAndroid Build Coastguard Worker                args.append(frame.symbols.declare_parameter('caller'))
539*635a8641SAndroid Build Coastguard Worker            macro_ref.accesses_caller = True
540*635a8641SAndroid Build Coastguard Worker        if 'kwargs' in undeclared and not 'kwargs' in skip_special_params:
541*635a8641SAndroid Build Coastguard Worker            args.append(frame.symbols.declare_parameter('kwargs'))
542*635a8641SAndroid Build Coastguard Worker            macro_ref.accesses_kwargs = True
543*635a8641SAndroid Build Coastguard Worker        if 'varargs' in undeclared and not 'varargs' in skip_special_params:
544*635a8641SAndroid Build Coastguard Worker            args.append(frame.symbols.declare_parameter('varargs'))
545*635a8641SAndroid Build Coastguard Worker            macro_ref.accesses_varargs = True
546*635a8641SAndroid Build Coastguard Worker
547*635a8641SAndroid Build Coastguard Worker        # macros are delayed, they never require output checks
548*635a8641SAndroid Build Coastguard Worker        frame.require_output_check = False
549*635a8641SAndroid Build Coastguard Worker        frame.symbols.analyze_node(node)
550*635a8641SAndroid Build Coastguard Worker        self.writeline('%s(%s):' % (self.func('macro'), ', '.join(args)), node)
551*635a8641SAndroid Build Coastguard Worker        self.indent()
552*635a8641SAndroid Build Coastguard Worker
553*635a8641SAndroid Build Coastguard Worker        self.buffer(frame)
554*635a8641SAndroid Build Coastguard Worker        self.enter_frame(frame)
555*635a8641SAndroid Build Coastguard Worker
556*635a8641SAndroid Build Coastguard Worker        self.push_parameter_definitions(frame)
557*635a8641SAndroid Build Coastguard Worker        for idx, arg in enumerate(node.args):
558*635a8641SAndroid Build Coastguard Worker            ref = frame.symbols.ref(arg.name)
559*635a8641SAndroid Build Coastguard Worker            self.writeline('if %s is missing:' % ref)
560*635a8641SAndroid Build Coastguard Worker            self.indent()
561*635a8641SAndroid Build Coastguard Worker            try:
562*635a8641SAndroid Build Coastguard Worker                default = node.defaults[idx - len(node.args)]
563*635a8641SAndroid Build Coastguard Worker            except IndexError:
564*635a8641SAndroid Build Coastguard Worker                self.writeline('%s = undefined(%r, name=%r)' % (
565*635a8641SAndroid Build Coastguard Worker                    ref,
566*635a8641SAndroid Build Coastguard Worker                    'parameter %r was not provided' % arg.name,
567*635a8641SAndroid Build Coastguard Worker                    arg.name))
568*635a8641SAndroid Build Coastguard Worker            else:
569*635a8641SAndroid Build Coastguard Worker                self.writeline('%s = ' % ref)
570*635a8641SAndroid Build Coastguard Worker                self.visit(default, frame)
571*635a8641SAndroid Build Coastguard Worker            self.mark_parameter_stored(ref)
572*635a8641SAndroid Build Coastguard Worker            self.outdent()
573*635a8641SAndroid Build Coastguard Worker        self.pop_parameter_definitions()
574*635a8641SAndroid Build Coastguard Worker
575*635a8641SAndroid Build Coastguard Worker        self.blockvisit(node.body, frame)
576*635a8641SAndroid Build Coastguard Worker        self.return_buffer_contents(frame, force_unescaped=True)
577*635a8641SAndroid Build Coastguard Worker        self.leave_frame(frame, with_python_scope=True)
578*635a8641SAndroid Build Coastguard Worker        self.outdent()
579*635a8641SAndroid Build Coastguard Worker
580*635a8641SAndroid Build Coastguard Worker        return frame, macro_ref
581*635a8641SAndroid Build Coastguard Worker
582*635a8641SAndroid Build Coastguard Worker    def macro_def(self, macro_ref, frame):
583*635a8641SAndroid Build Coastguard Worker        """Dump the macro definition for the def created by macro_body."""
584*635a8641SAndroid Build Coastguard Worker        arg_tuple = ', '.join(repr(x.name) for x in macro_ref.node.args)
585*635a8641SAndroid Build Coastguard Worker        name = getattr(macro_ref.node, 'name', None)
586*635a8641SAndroid Build Coastguard Worker        if len(macro_ref.node.args) == 1:
587*635a8641SAndroid Build Coastguard Worker            arg_tuple += ','
588*635a8641SAndroid Build Coastguard Worker        self.write('Macro(environment, macro, %r, (%s), %r, %r, %r, '
589*635a8641SAndroid Build Coastguard Worker                   'context.eval_ctx.autoescape)' %
590*635a8641SAndroid Build Coastguard Worker                   (name, arg_tuple, macro_ref.accesses_kwargs,
591*635a8641SAndroid Build Coastguard Worker                    macro_ref.accesses_varargs, macro_ref.accesses_caller))
592*635a8641SAndroid Build Coastguard Worker
593*635a8641SAndroid Build Coastguard Worker    def position(self, node):
594*635a8641SAndroid Build Coastguard Worker        """Return a human readable position for the node."""
595*635a8641SAndroid Build Coastguard Worker        rv = 'line %d' % node.lineno
596*635a8641SAndroid Build Coastguard Worker        if self.name is not None:
597*635a8641SAndroid Build Coastguard Worker            rv += ' in ' + repr(self.name)
598*635a8641SAndroid Build Coastguard Worker        return rv
599*635a8641SAndroid Build Coastguard Worker
600*635a8641SAndroid Build Coastguard Worker    def dump_local_context(self, frame):
601*635a8641SAndroid Build Coastguard Worker        return '{%s}' % ', '.join(
602*635a8641SAndroid Build Coastguard Worker            '%r: %s' % (name, target) for name, target
603*635a8641SAndroid Build Coastguard Worker            in iteritems(frame.symbols.dump_stores()))
604*635a8641SAndroid Build Coastguard Worker
605*635a8641SAndroid Build Coastguard Worker    def write_commons(self):
606*635a8641SAndroid Build Coastguard Worker        """Writes a common preamble that is used by root and block functions.
607*635a8641SAndroid Build Coastguard Worker        Primarily this sets up common local helpers and enforces a generator
608*635a8641SAndroid Build Coastguard Worker        through a dead branch.
609*635a8641SAndroid Build Coastguard Worker        """
610*635a8641SAndroid Build Coastguard Worker        self.writeline('resolve = context.resolve_or_missing')
611*635a8641SAndroid Build Coastguard Worker        self.writeline('undefined = environment.undefined')
612*635a8641SAndroid Build Coastguard Worker        self.writeline('if 0: yield None')
613*635a8641SAndroid Build Coastguard Worker
614*635a8641SAndroid Build Coastguard Worker    def push_parameter_definitions(self, frame):
615*635a8641SAndroid Build Coastguard Worker        """Pushes all parameter targets from the given frame into a local
616*635a8641SAndroid Build Coastguard Worker        stack that permits tracking of yet to be assigned parameters.  In
617*635a8641SAndroid Build Coastguard Worker        particular this enables the optimization from `visit_Name` to skip
618*635a8641SAndroid Build Coastguard Worker        undefined expressions for parameters in macros as macros can reference
619*635a8641SAndroid Build Coastguard Worker        otherwise unbound parameters.
620*635a8641SAndroid Build Coastguard Worker        """
621*635a8641SAndroid Build Coastguard Worker        self._param_def_block.append(frame.symbols.dump_param_targets())
622*635a8641SAndroid Build Coastguard Worker
623*635a8641SAndroid Build Coastguard Worker    def pop_parameter_definitions(self):
624*635a8641SAndroid Build Coastguard Worker        """Pops the current parameter definitions set."""
625*635a8641SAndroid Build Coastguard Worker        self._param_def_block.pop()
626*635a8641SAndroid Build Coastguard Worker
627*635a8641SAndroid Build Coastguard Worker    def mark_parameter_stored(self, target):
628*635a8641SAndroid Build Coastguard Worker        """Marks a parameter in the current parameter definitions as stored.
629*635a8641SAndroid Build Coastguard Worker        This will skip the enforced undefined checks.
630*635a8641SAndroid Build Coastguard Worker        """
631*635a8641SAndroid Build Coastguard Worker        if self._param_def_block:
632*635a8641SAndroid Build Coastguard Worker            self._param_def_block[-1].discard(target)
633*635a8641SAndroid Build Coastguard Worker
634*635a8641SAndroid Build Coastguard Worker    def push_context_reference(self, target):
635*635a8641SAndroid Build Coastguard Worker        self._context_reference_stack.append(target)
636*635a8641SAndroid Build Coastguard Worker
637*635a8641SAndroid Build Coastguard Worker    def pop_context_reference(self):
638*635a8641SAndroid Build Coastguard Worker        self._context_reference_stack.pop()
639*635a8641SAndroid Build Coastguard Worker
640*635a8641SAndroid Build Coastguard Worker    def get_context_ref(self):
641*635a8641SAndroid Build Coastguard Worker        return self._context_reference_stack[-1]
642*635a8641SAndroid Build Coastguard Worker
643*635a8641SAndroid Build Coastguard Worker    def get_resolve_func(self):
644*635a8641SAndroid Build Coastguard Worker        target = self._context_reference_stack[-1]
645*635a8641SAndroid Build Coastguard Worker        if target == 'context':
646*635a8641SAndroid Build Coastguard Worker            return 'resolve'
647*635a8641SAndroid Build Coastguard Worker        return '%s.resolve' % target
648*635a8641SAndroid Build Coastguard Worker
649*635a8641SAndroid Build Coastguard Worker    def derive_context(self, frame):
650*635a8641SAndroid Build Coastguard Worker        return '%s.derived(%s)' % (
651*635a8641SAndroid Build Coastguard Worker            self.get_context_ref(),
652*635a8641SAndroid Build Coastguard Worker            self.dump_local_context(frame),
653*635a8641SAndroid Build Coastguard Worker        )
654*635a8641SAndroid Build Coastguard Worker
655*635a8641SAndroid Build Coastguard Worker    def parameter_is_undeclared(self, target):
656*635a8641SAndroid Build Coastguard Worker        """Checks if a given target is an undeclared parameter."""
657*635a8641SAndroid Build Coastguard Worker        if not self._param_def_block:
658*635a8641SAndroid Build Coastguard Worker            return False
659*635a8641SAndroid Build Coastguard Worker        return target in self._param_def_block[-1]
660*635a8641SAndroid Build Coastguard Worker
661*635a8641SAndroid Build Coastguard Worker    def push_assign_tracking(self):
662*635a8641SAndroid Build Coastguard Worker        """Pushes a new layer for assignment tracking."""
663*635a8641SAndroid Build Coastguard Worker        self._assign_stack.append(set())
664*635a8641SAndroid Build Coastguard Worker
665*635a8641SAndroid Build Coastguard Worker    def pop_assign_tracking(self, frame):
666*635a8641SAndroid Build Coastguard Worker        """Pops the topmost level for assignment tracking and updates the
667*635a8641SAndroid Build Coastguard Worker        context variables if necessary.
668*635a8641SAndroid Build Coastguard Worker        """
669*635a8641SAndroid Build Coastguard Worker        vars = self._assign_stack.pop()
670*635a8641SAndroid Build Coastguard Worker        if not frame.toplevel or not vars:
671*635a8641SAndroid Build Coastguard Worker            return
672*635a8641SAndroid Build Coastguard Worker        public_names = [x for x in vars if x[:1] != '_']
673*635a8641SAndroid Build Coastguard Worker        if len(vars) == 1:
674*635a8641SAndroid Build Coastguard Worker            name = next(iter(vars))
675*635a8641SAndroid Build Coastguard Worker            ref = frame.symbols.ref(name)
676*635a8641SAndroid Build Coastguard Worker            self.writeline('context.vars[%r] = %s' % (name, ref))
677*635a8641SAndroid Build Coastguard Worker        else:
678*635a8641SAndroid Build Coastguard Worker            self.writeline('context.vars.update({')
679*635a8641SAndroid Build Coastguard Worker            for idx, name in enumerate(vars):
680*635a8641SAndroid Build Coastguard Worker                if idx:
681*635a8641SAndroid Build Coastguard Worker                    self.write(', ')
682*635a8641SAndroid Build Coastguard Worker                ref = frame.symbols.ref(name)
683*635a8641SAndroid Build Coastguard Worker                self.write('%r: %s' % (name, ref))
684*635a8641SAndroid Build Coastguard Worker            self.write('})')
685*635a8641SAndroid Build Coastguard Worker        if public_names:
686*635a8641SAndroid Build Coastguard Worker            if len(public_names) == 1:
687*635a8641SAndroid Build Coastguard Worker                self.writeline('context.exported_vars.add(%r)' %
688*635a8641SAndroid Build Coastguard Worker                               public_names[0])
689*635a8641SAndroid Build Coastguard Worker            else:
690*635a8641SAndroid Build Coastguard Worker                self.writeline('context.exported_vars.update((%s))' %
691*635a8641SAndroid Build Coastguard Worker                               ', '.join(imap(repr, public_names)))
692*635a8641SAndroid Build Coastguard Worker
693*635a8641SAndroid Build Coastguard Worker    # -- Statement Visitors
694*635a8641SAndroid Build Coastguard Worker
695*635a8641SAndroid Build Coastguard Worker    def visit_Template(self, node, frame=None):
696*635a8641SAndroid Build Coastguard Worker        assert frame is None, 'no root frame allowed'
697*635a8641SAndroid Build Coastguard Worker        eval_ctx = EvalContext(self.environment, self.name)
698*635a8641SAndroid Build Coastguard Worker
699*635a8641SAndroid Build Coastguard Worker        from jinja2.runtime import __all__ as exported
700*635a8641SAndroid Build Coastguard Worker        self.writeline('from __future__ import %s' % ', '.join(code_features))
701*635a8641SAndroid Build Coastguard Worker        self.writeline('from jinja2.runtime import ' + ', '.join(exported))
702*635a8641SAndroid Build Coastguard Worker
703*635a8641SAndroid Build Coastguard Worker        if self.environment.is_async:
704*635a8641SAndroid Build Coastguard Worker            self.writeline('from jinja2.asyncsupport import auto_await, '
705*635a8641SAndroid Build Coastguard Worker                           'auto_aiter, make_async_loop_context')
706*635a8641SAndroid Build Coastguard Worker
707*635a8641SAndroid Build Coastguard Worker        # if we want a deferred initialization we cannot move the
708*635a8641SAndroid Build Coastguard Worker        # environment into a local name
709*635a8641SAndroid Build Coastguard Worker        envenv = not self.defer_init and ', environment=environment' or ''
710*635a8641SAndroid Build Coastguard Worker
711*635a8641SAndroid Build Coastguard Worker        # do we have an extends tag at all?  If not, we can save some
712*635a8641SAndroid Build Coastguard Worker        # overhead by just not processing any inheritance code.
713*635a8641SAndroid Build Coastguard Worker        have_extends = node.find(nodes.Extends) is not None
714*635a8641SAndroid Build Coastguard Worker
715*635a8641SAndroid Build Coastguard Worker        # find all blocks
716*635a8641SAndroid Build Coastguard Worker        for block in node.find_all(nodes.Block):
717*635a8641SAndroid Build Coastguard Worker            if block.name in self.blocks:
718*635a8641SAndroid Build Coastguard Worker                self.fail('block %r defined twice' % block.name, block.lineno)
719*635a8641SAndroid Build Coastguard Worker            self.blocks[block.name] = block
720*635a8641SAndroid Build Coastguard Worker
721*635a8641SAndroid Build Coastguard Worker        # find all imports and import them
722*635a8641SAndroid Build Coastguard Worker        for import_ in node.find_all(nodes.ImportedName):
723*635a8641SAndroid Build Coastguard Worker            if import_.importname not in self.import_aliases:
724*635a8641SAndroid Build Coastguard Worker                imp = import_.importname
725*635a8641SAndroid Build Coastguard Worker                self.import_aliases[imp] = alias = self.temporary_identifier()
726*635a8641SAndroid Build Coastguard Worker                if '.' in imp:
727*635a8641SAndroid Build Coastguard Worker                    module, obj = imp.rsplit('.', 1)
728*635a8641SAndroid Build Coastguard Worker                    self.writeline('from %s import %s as %s' %
729*635a8641SAndroid Build Coastguard Worker                                   (module, obj, alias))
730*635a8641SAndroid Build Coastguard Worker                else:
731*635a8641SAndroid Build Coastguard Worker                    self.writeline('import %s as %s' % (imp, alias))
732*635a8641SAndroid Build Coastguard Worker
733*635a8641SAndroid Build Coastguard Worker        # add the load name
734*635a8641SAndroid Build Coastguard Worker        self.writeline('name = %r' % self.name)
735*635a8641SAndroid Build Coastguard Worker
736*635a8641SAndroid Build Coastguard Worker        # generate the root render function.
737*635a8641SAndroid Build Coastguard Worker        self.writeline('%s(context, missing=missing%s):' %
738*635a8641SAndroid Build Coastguard Worker                       (self.func('root'), envenv), extra=1)
739*635a8641SAndroid Build Coastguard Worker        self.indent()
740*635a8641SAndroid Build Coastguard Worker        self.write_commons()
741*635a8641SAndroid Build Coastguard Worker
742*635a8641SAndroid Build Coastguard Worker        # process the root
743*635a8641SAndroid Build Coastguard Worker        frame = Frame(eval_ctx)
744*635a8641SAndroid Build Coastguard Worker        if 'self' in find_undeclared(node.body, ('self',)):
745*635a8641SAndroid Build Coastguard Worker            ref = frame.symbols.declare_parameter('self')
746*635a8641SAndroid Build Coastguard Worker            self.writeline('%s = TemplateReference(context)' % ref)
747*635a8641SAndroid Build Coastguard Worker        frame.symbols.analyze_node(node)
748*635a8641SAndroid Build Coastguard Worker        frame.toplevel = frame.rootlevel = True
749*635a8641SAndroid Build Coastguard Worker        frame.require_output_check = have_extends and not self.has_known_extends
750*635a8641SAndroid Build Coastguard Worker        if have_extends:
751*635a8641SAndroid Build Coastguard Worker            self.writeline('parent_template = None')
752*635a8641SAndroid Build Coastguard Worker        self.enter_frame(frame)
753*635a8641SAndroid Build Coastguard Worker        self.pull_dependencies(node.body)
754*635a8641SAndroid Build Coastguard Worker        self.blockvisit(node.body, frame)
755*635a8641SAndroid Build Coastguard Worker        self.leave_frame(frame, with_python_scope=True)
756*635a8641SAndroid Build Coastguard Worker        self.outdent()
757*635a8641SAndroid Build Coastguard Worker
758*635a8641SAndroid Build Coastguard Worker        # make sure that the parent root is called.
759*635a8641SAndroid Build Coastguard Worker        if have_extends:
760*635a8641SAndroid Build Coastguard Worker            if not self.has_known_extends:
761*635a8641SAndroid Build Coastguard Worker                self.indent()
762*635a8641SAndroid Build Coastguard Worker                self.writeline('if parent_template is not None:')
763*635a8641SAndroid Build Coastguard Worker            self.indent()
764*635a8641SAndroid Build Coastguard Worker            if supports_yield_from and not self.environment.is_async:
765*635a8641SAndroid Build Coastguard Worker                self.writeline('yield from parent_template.'
766*635a8641SAndroid Build Coastguard Worker                               'root_render_func(context)')
767*635a8641SAndroid Build Coastguard Worker            else:
768*635a8641SAndroid Build Coastguard Worker                self.writeline('%sfor event in parent_template.'
769*635a8641SAndroid Build Coastguard Worker                               'root_render_func(context):' %
770*635a8641SAndroid Build Coastguard Worker                               (self.environment.is_async and 'async ' or ''))
771*635a8641SAndroid Build Coastguard Worker                self.indent()
772*635a8641SAndroid Build Coastguard Worker                self.writeline('yield event')
773*635a8641SAndroid Build Coastguard Worker                self.outdent()
774*635a8641SAndroid Build Coastguard Worker            self.outdent(1 + (not self.has_known_extends))
775*635a8641SAndroid Build Coastguard Worker
776*635a8641SAndroid Build Coastguard Worker        # at this point we now have the blocks collected and can visit them too.
777*635a8641SAndroid Build Coastguard Worker        for name, block in iteritems(self.blocks):
778*635a8641SAndroid Build Coastguard Worker            self.writeline('%s(context, missing=missing%s):' %
779*635a8641SAndroid Build Coastguard Worker                           (self.func('block_' + name), envenv),
780*635a8641SAndroid Build Coastguard Worker                           block, 1)
781*635a8641SAndroid Build Coastguard Worker            self.indent()
782*635a8641SAndroid Build Coastguard Worker            self.write_commons()
783*635a8641SAndroid Build Coastguard Worker            # It's important that we do not make this frame a child of the
784*635a8641SAndroid Build Coastguard Worker            # toplevel template.  This would cause a variety of
785*635a8641SAndroid Build Coastguard Worker            # interesting issues with identifier tracking.
786*635a8641SAndroid Build Coastguard Worker            block_frame = Frame(eval_ctx)
787*635a8641SAndroid Build Coastguard Worker            undeclared = find_undeclared(block.body, ('self', 'super'))
788*635a8641SAndroid Build Coastguard Worker            if 'self' in undeclared:
789*635a8641SAndroid Build Coastguard Worker                ref = block_frame.symbols.declare_parameter('self')
790*635a8641SAndroid Build Coastguard Worker                self.writeline('%s = TemplateReference(context)' % ref)
791*635a8641SAndroid Build Coastguard Worker            if 'super' in undeclared:
792*635a8641SAndroid Build Coastguard Worker                ref = block_frame.symbols.declare_parameter('super')
793*635a8641SAndroid Build Coastguard Worker                self.writeline('%s = context.super(%r, '
794*635a8641SAndroid Build Coastguard Worker                               'block_%s)' % (ref, name, name))
795*635a8641SAndroid Build Coastguard Worker            block_frame.symbols.analyze_node(block)
796*635a8641SAndroid Build Coastguard Worker            block_frame.block = name
797*635a8641SAndroid Build Coastguard Worker            self.enter_frame(block_frame)
798*635a8641SAndroid Build Coastguard Worker            self.pull_dependencies(block.body)
799*635a8641SAndroid Build Coastguard Worker            self.blockvisit(block.body, block_frame)
800*635a8641SAndroid Build Coastguard Worker            self.leave_frame(block_frame, with_python_scope=True)
801*635a8641SAndroid Build Coastguard Worker            self.outdent()
802*635a8641SAndroid Build Coastguard Worker
803*635a8641SAndroid Build Coastguard Worker        self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
804*635a8641SAndroid Build Coastguard Worker                                                   for x in self.blocks),
805*635a8641SAndroid Build Coastguard Worker                       extra=1)
806*635a8641SAndroid Build Coastguard Worker
807*635a8641SAndroid Build Coastguard Worker        # add a function that returns the debug info
808*635a8641SAndroid Build Coastguard Worker        self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
809*635a8641SAndroid Build Coastguard Worker                                                    in self.debug_info))
810*635a8641SAndroid Build Coastguard Worker
811*635a8641SAndroid Build Coastguard Worker    def visit_Block(self, node, frame):
812*635a8641SAndroid Build Coastguard Worker        """Call a block and register it for the template."""
813*635a8641SAndroid Build Coastguard Worker        level = 0
814*635a8641SAndroid Build Coastguard Worker        if frame.toplevel:
815*635a8641SAndroid Build Coastguard Worker            # if we know that we are a child template, there is no need to
816*635a8641SAndroid Build Coastguard Worker            # check if we are one
817*635a8641SAndroid Build Coastguard Worker            if self.has_known_extends:
818*635a8641SAndroid Build Coastguard Worker                return
819*635a8641SAndroid Build Coastguard Worker            if self.extends_so_far > 0:
820*635a8641SAndroid Build Coastguard Worker                self.writeline('if parent_template is None:')
821*635a8641SAndroid Build Coastguard Worker                self.indent()
822*635a8641SAndroid Build Coastguard Worker                level += 1
823*635a8641SAndroid Build Coastguard Worker
824*635a8641SAndroid Build Coastguard Worker        if node.scoped:
825*635a8641SAndroid Build Coastguard Worker            context = self.derive_context(frame)
826*635a8641SAndroid Build Coastguard Worker        else:
827*635a8641SAndroid Build Coastguard Worker            context = self.get_context_ref()
828*635a8641SAndroid Build Coastguard Worker
829*635a8641SAndroid Build Coastguard Worker        if supports_yield_from and not self.environment.is_async and \
830*635a8641SAndroid Build Coastguard Worker           frame.buffer is None:
831*635a8641SAndroid Build Coastguard Worker            self.writeline('yield from context.blocks[%r][0](%s)' % (
832*635a8641SAndroid Build Coastguard Worker                           node.name, context), node)
833*635a8641SAndroid Build Coastguard Worker        else:
834*635a8641SAndroid Build Coastguard Worker            loop = self.environment.is_async and 'async for' or 'for'
835*635a8641SAndroid Build Coastguard Worker            self.writeline('%s event in context.blocks[%r][0](%s):' % (
836*635a8641SAndroid Build Coastguard Worker                           loop, node.name, context), node)
837*635a8641SAndroid Build Coastguard Worker            self.indent()
838*635a8641SAndroid Build Coastguard Worker            self.simple_write('event', frame)
839*635a8641SAndroid Build Coastguard Worker            self.outdent()
840*635a8641SAndroid Build Coastguard Worker
841*635a8641SAndroid Build Coastguard Worker        self.outdent(level)
842*635a8641SAndroid Build Coastguard Worker
843*635a8641SAndroid Build Coastguard Worker    def visit_Extends(self, node, frame):
844*635a8641SAndroid Build Coastguard Worker        """Calls the extender."""
845*635a8641SAndroid Build Coastguard Worker        if not frame.toplevel:
846*635a8641SAndroid Build Coastguard Worker            self.fail('cannot use extend from a non top-level scope',
847*635a8641SAndroid Build Coastguard Worker                      node.lineno)
848*635a8641SAndroid Build Coastguard Worker
849*635a8641SAndroid Build Coastguard Worker        # if the number of extends statements in general is zero so
850*635a8641SAndroid Build Coastguard Worker        # far, we don't have to add a check if something extended
851*635a8641SAndroid Build Coastguard Worker        # the template before this one.
852*635a8641SAndroid Build Coastguard Worker        if self.extends_so_far > 0:
853*635a8641SAndroid Build Coastguard Worker
854*635a8641SAndroid Build Coastguard Worker            # if we have a known extends we just add a template runtime
855*635a8641SAndroid Build Coastguard Worker            # error into the generated code.  We could catch that at compile
856*635a8641SAndroid Build Coastguard Worker            # time too, but i welcome it not to confuse users by throwing the
857*635a8641SAndroid Build Coastguard Worker            # same error at different times just "because we can".
858*635a8641SAndroid Build Coastguard Worker            if not self.has_known_extends:
859*635a8641SAndroid Build Coastguard Worker                self.writeline('if parent_template is not None:')
860*635a8641SAndroid Build Coastguard Worker                self.indent()
861*635a8641SAndroid Build Coastguard Worker            self.writeline('raise TemplateRuntimeError(%r)' %
862*635a8641SAndroid Build Coastguard Worker                           'extended multiple times')
863*635a8641SAndroid Build Coastguard Worker
864*635a8641SAndroid Build Coastguard Worker            # if we have a known extends already we don't need that code here
865*635a8641SAndroid Build Coastguard Worker            # as we know that the template execution will end here.
866*635a8641SAndroid Build Coastguard Worker            if self.has_known_extends:
867*635a8641SAndroid Build Coastguard Worker                raise CompilerExit()
868*635a8641SAndroid Build Coastguard Worker            else:
869*635a8641SAndroid Build Coastguard Worker                self.outdent()
870*635a8641SAndroid Build Coastguard Worker
871*635a8641SAndroid Build Coastguard Worker        self.writeline('parent_template = environment.get_template(', node)
872*635a8641SAndroid Build Coastguard Worker        self.visit(node.template, frame)
873*635a8641SAndroid Build Coastguard Worker        self.write(', %r)' % self.name)
874*635a8641SAndroid Build Coastguard Worker        self.writeline('for name, parent_block in parent_template.'
875*635a8641SAndroid Build Coastguard Worker                       'blocks.%s():' % dict_item_iter)
876*635a8641SAndroid Build Coastguard Worker        self.indent()
877*635a8641SAndroid Build Coastguard Worker        self.writeline('context.blocks.setdefault(name, []).'
878*635a8641SAndroid Build Coastguard Worker                       'append(parent_block)')
879*635a8641SAndroid Build Coastguard Worker        self.outdent()
880*635a8641SAndroid Build Coastguard Worker
881*635a8641SAndroid Build Coastguard Worker        # if this extends statement was in the root level we can take
882*635a8641SAndroid Build Coastguard Worker        # advantage of that information and simplify the generated code
883*635a8641SAndroid Build Coastguard Worker        # in the top level from this point onwards
884*635a8641SAndroid Build Coastguard Worker        if frame.rootlevel:
885*635a8641SAndroid Build Coastguard Worker            self.has_known_extends = True
886*635a8641SAndroid Build Coastguard Worker
887*635a8641SAndroid Build Coastguard Worker        # and now we have one more
888*635a8641SAndroid Build Coastguard Worker        self.extends_so_far += 1
889*635a8641SAndroid Build Coastguard Worker
890*635a8641SAndroid Build Coastguard Worker    def visit_Include(self, node, frame):
891*635a8641SAndroid Build Coastguard Worker        """Handles includes."""
892*635a8641SAndroid Build Coastguard Worker        if node.ignore_missing:
893*635a8641SAndroid Build Coastguard Worker            self.writeline('try:')
894*635a8641SAndroid Build Coastguard Worker            self.indent()
895*635a8641SAndroid Build Coastguard Worker
896*635a8641SAndroid Build Coastguard Worker        func_name = 'get_or_select_template'
897*635a8641SAndroid Build Coastguard Worker        if isinstance(node.template, nodes.Const):
898*635a8641SAndroid Build Coastguard Worker            if isinstance(node.template.value, string_types):
899*635a8641SAndroid Build Coastguard Worker                func_name = 'get_template'
900*635a8641SAndroid Build Coastguard Worker            elif isinstance(node.template.value, (tuple, list)):
901*635a8641SAndroid Build Coastguard Worker                func_name = 'select_template'
902*635a8641SAndroid Build Coastguard Worker        elif isinstance(node.template, (nodes.Tuple, nodes.List)):
903*635a8641SAndroid Build Coastguard Worker            func_name = 'select_template'
904*635a8641SAndroid Build Coastguard Worker
905*635a8641SAndroid Build Coastguard Worker        self.writeline('template = environment.%s(' % func_name, node)
906*635a8641SAndroid Build Coastguard Worker        self.visit(node.template, frame)
907*635a8641SAndroid Build Coastguard Worker        self.write(', %r)' % self.name)
908*635a8641SAndroid Build Coastguard Worker        if node.ignore_missing:
909*635a8641SAndroid Build Coastguard Worker            self.outdent()
910*635a8641SAndroid Build Coastguard Worker            self.writeline('except TemplateNotFound:')
911*635a8641SAndroid Build Coastguard Worker            self.indent()
912*635a8641SAndroid Build Coastguard Worker            self.writeline('pass')
913*635a8641SAndroid Build Coastguard Worker            self.outdent()
914*635a8641SAndroid Build Coastguard Worker            self.writeline('else:')
915*635a8641SAndroid Build Coastguard Worker            self.indent()
916*635a8641SAndroid Build Coastguard Worker
917*635a8641SAndroid Build Coastguard Worker        skip_event_yield = False
918*635a8641SAndroid Build Coastguard Worker        if node.with_context:
919*635a8641SAndroid Build Coastguard Worker            loop = self.environment.is_async and 'async for' or 'for'
920*635a8641SAndroid Build Coastguard Worker            self.writeline('%s event in template.root_render_func('
921*635a8641SAndroid Build Coastguard Worker                           'template.new_context(context.get_all(), True, '
922*635a8641SAndroid Build Coastguard Worker                           '%s)):' % (loop, self.dump_local_context(frame)))
923*635a8641SAndroid Build Coastguard Worker        elif self.environment.is_async:
924*635a8641SAndroid Build Coastguard Worker            self.writeline('for event in (await '
925*635a8641SAndroid Build Coastguard Worker                           'template._get_default_module_async())'
926*635a8641SAndroid Build Coastguard Worker                           '._body_stream:')
927*635a8641SAndroid Build Coastguard Worker        else:
928*635a8641SAndroid Build Coastguard Worker            if supports_yield_from:
929*635a8641SAndroid Build Coastguard Worker                self.writeline('yield from template._get_default_module()'
930*635a8641SAndroid Build Coastguard Worker                               '._body_stream')
931*635a8641SAndroid Build Coastguard Worker                skip_event_yield = True
932*635a8641SAndroid Build Coastguard Worker            else:
933*635a8641SAndroid Build Coastguard Worker                self.writeline('for event in template._get_default_module()'
934*635a8641SAndroid Build Coastguard Worker                               '._body_stream:')
935*635a8641SAndroid Build Coastguard Worker
936*635a8641SAndroid Build Coastguard Worker        if not skip_event_yield:
937*635a8641SAndroid Build Coastguard Worker            self.indent()
938*635a8641SAndroid Build Coastguard Worker            self.simple_write('event', frame)
939*635a8641SAndroid Build Coastguard Worker            self.outdent()
940*635a8641SAndroid Build Coastguard Worker
941*635a8641SAndroid Build Coastguard Worker        if node.ignore_missing:
942*635a8641SAndroid Build Coastguard Worker            self.outdent()
943*635a8641SAndroid Build Coastguard Worker
944*635a8641SAndroid Build Coastguard Worker    def visit_Import(self, node, frame):
945*635a8641SAndroid Build Coastguard Worker        """Visit regular imports."""
946*635a8641SAndroid Build Coastguard Worker        self.writeline('%s = ' % frame.symbols.ref(node.target), node)
947*635a8641SAndroid Build Coastguard Worker        if frame.toplevel:
948*635a8641SAndroid Build Coastguard Worker            self.write('context.vars[%r] = ' % node.target)
949*635a8641SAndroid Build Coastguard Worker        if self.environment.is_async:
950*635a8641SAndroid Build Coastguard Worker            self.write('await ')
951*635a8641SAndroid Build Coastguard Worker        self.write('environment.get_template(')
952*635a8641SAndroid Build Coastguard Worker        self.visit(node.template, frame)
953*635a8641SAndroid Build Coastguard Worker        self.write(', %r).' % self.name)
954*635a8641SAndroid Build Coastguard Worker        if node.with_context:
955*635a8641SAndroid Build Coastguard Worker            self.write('make_module%s(context.get_all(), True, %s)'
956*635a8641SAndroid Build Coastguard Worker                       % (self.environment.is_async and '_async' or '',
957*635a8641SAndroid Build Coastguard Worker                          self.dump_local_context(frame)))
958*635a8641SAndroid Build Coastguard Worker        elif self.environment.is_async:
959*635a8641SAndroid Build Coastguard Worker            self.write('_get_default_module_async()')
960*635a8641SAndroid Build Coastguard Worker        else:
961*635a8641SAndroid Build Coastguard Worker            self.write('_get_default_module()')
962*635a8641SAndroid Build Coastguard Worker        if frame.toplevel and not node.target.startswith('_'):
963*635a8641SAndroid Build Coastguard Worker            self.writeline('context.exported_vars.discard(%r)' % node.target)
964*635a8641SAndroid Build Coastguard Worker
965*635a8641SAndroid Build Coastguard Worker    def visit_FromImport(self, node, frame):
966*635a8641SAndroid Build Coastguard Worker        """Visit named imports."""
967*635a8641SAndroid Build Coastguard Worker        self.newline(node)
968*635a8641SAndroid Build Coastguard Worker        self.write('included_template = %senvironment.get_template('
969*635a8641SAndroid Build Coastguard Worker                   % (self.environment.is_async and 'await ' or ''))
970*635a8641SAndroid Build Coastguard Worker        self.visit(node.template, frame)
971*635a8641SAndroid Build Coastguard Worker        self.write(', %r).' % self.name)
972*635a8641SAndroid Build Coastguard Worker        if node.with_context:
973*635a8641SAndroid Build Coastguard Worker            self.write('make_module%s(context.get_all(), True, %s)'
974*635a8641SAndroid Build Coastguard Worker                       % (self.environment.is_async and '_async' or '',
975*635a8641SAndroid Build Coastguard Worker                          self.dump_local_context(frame)))
976*635a8641SAndroid Build Coastguard Worker        elif self.environment.is_async:
977*635a8641SAndroid Build Coastguard Worker            self.write('_get_default_module_async()')
978*635a8641SAndroid Build Coastguard Worker        else:
979*635a8641SAndroid Build Coastguard Worker            self.write('_get_default_module()')
980*635a8641SAndroid Build Coastguard Worker
981*635a8641SAndroid Build Coastguard Worker        var_names = []
982*635a8641SAndroid Build Coastguard Worker        discarded_names = []
983*635a8641SAndroid Build Coastguard Worker        for name in node.names:
984*635a8641SAndroid Build Coastguard Worker            if isinstance(name, tuple):
985*635a8641SAndroid Build Coastguard Worker                name, alias = name
986*635a8641SAndroid Build Coastguard Worker            else:
987*635a8641SAndroid Build Coastguard Worker                alias = name
988*635a8641SAndroid Build Coastguard Worker            self.writeline('%s = getattr(included_template, '
989*635a8641SAndroid Build Coastguard Worker                           '%r, missing)' % (frame.symbols.ref(alias), name))
990*635a8641SAndroid Build Coastguard Worker            self.writeline('if %s is missing:' % frame.symbols.ref(alias))
991*635a8641SAndroid Build Coastguard Worker            self.indent()
992*635a8641SAndroid Build Coastguard Worker            self.writeline('%s = undefined(%r %% '
993*635a8641SAndroid Build Coastguard Worker                           'included_template.__name__, '
994*635a8641SAndroid Build Coastguard Worker                           'name=%r)' %
995*635a8641SAndroid Build Coastguard Worker                           (frame.symbols.ref(alias),
996*635a8641SAndroid Build Coastguard Worker                            'the template %%r (imported on %s) does '
997*635a8641SAndroid Build Coastguard Worker                            'not export the requested name %s' % (
998*635a8641SAndroid Build Coastguard Worker                                self.position(node),
999*635a8641SAndroid Build Coastguard Worker                                repr(name)
1000*635a8641SAndroid Build Coastguard Worker                           ), name))
1001*635a8641SAndroid Build Coastguard Worker            self.outdent()
1002*635a8641SAndroid Build Coastguard Worker            if frame.toplevel:
1003*635a8641SAndroid Build Coastguard Worker                var_names.append(alias)
1004*635a8641SAndroid Build Coastguard Worker                if not alias.startswith('_'):
1005*635a8641SAndroid Build Coastguard Worker                    discarded_names.append(alias)
1006*635a8641SAndroid Build Coastguard Worker
1007*635a8641SAndroid Build Coastguard Worker        if var_names:
1008*635a8641SAndroid Build Coastguard Worker            if len(var_names) == 1:
1009*635a8641SAndroid Build Coastguard Worker                name = var_names[0]
1010*635a8641SAndroid Build Coastguard Worker                self.writeline('context.vars[%r] = %s' %
1011*635a8641SAndroid Build Coastguard Worker                               (name, frame.symbols.ref(name)))
1012*635a8641SAndroid Build Coastguard Worker            else:
1013*635a8641SAndroid Build Coastguard Worker                self.writeline('context.vars.update({%s})' % ', '.join(
1014*635a8641SAndroid Build Coastguard Worker                    '%r: %s' % (name, frame.symbols.ref(name)) for name in var_names
1015*635a8641SAndroid Build Coastguard Worker                ))
1016*635a8641SAndroid Build Coastguard Worker        if discarded_names:
1017*635a8641SAndroid Build Coastguard Worker            if len(discarded_names) == 1:
1018*635a8641SAndroid Build Coastguard Worker                self.writeline('context.exported_vars.discard(%r)' %
1019*635a8641SAndroid Build Coastguard Worker                               discarded_names[0])
1020*635a8641SAndroid Build Coastguard Worker            else:
1021*635a8641SAndroid Build Coastguard Worker                self.writeline('context.exported_vars.difference_'
1022*635a8641SAndroid Build Coastguard Worker                               'update((%s))' % ', '.join(imap(repr, discarded_names)))
1023*635a8641SAndroid Build Coastguard Worker
1024*635a8641SAndroid Build Coastguard Worker    def visit_For(self, node, frame):
1025*635a8641SAndroid Build Coastguard Worker        loop_frame = frame.inner()
1026*635a8641SAndroid Build Coastguard Worker        test_frame = frame.inner()
1027*635a8641SAndroid Build Coastguard Worker        else_frame = frame.inner()
1028*635a8641SAndroid Build Coastguard Worker
1029*635a8641SAndroid Build Coastguard Worker        # try to figure out if we have an extended loop.  An extended loop
1030*635a8641SAndroid Build Coastguard Worker        # is necessary if the loop is in recursive mode if the special loop
1031*635a8641SAndroid Build Coastguard Worker        # variable is accessed in the body.
1032*635a8641SAndroid Build Coastguard Worker        extended_loop = node.recursive or 'loop' in \
1033*635a8641SAndroid Build Coastguard Worker                        find_undeclared(node.iter_child_nodes(
1034*635a8641SAndroid Build Coastguard Worker                            only=('body',)), ('loop',))
1035*635a8641SAndroid Build Coastguard Worker
1036*635a8641SAndroid Build Coastguard Worker        loop_ref = None
1037*635a8641SAndroid Build Coastguard Worker        if extended_loop:
1038*635a8641SAndroid Build Coastguard Worker            loop_ref = loop_frame.symbols.declare_parameter('loop')
1039*635a8641SAndroid Build Coastguard Worker
1040*635a8641SAndroid Build Coastguard Worker        loop_frame.symbols.analyze_node(node, for_branch='body')
1041*635a8641SAndroid Build Coastguard Worker        if node.else_:
1042*635a8641SAndroid Build Coastguard Worker            else_frame.symbols.analyze_node(node, for_branch='else')
1043*635a8641SAndroid Build Coastguard Worker
1044*635a8641SAndroid Build Coastguard Worker        if node.test:
1045*635a8641SAndroid Build Coastguard Worker            loop_filter_func = self.temporary_identifier()
1046*635a8641SAndroid Build Coastguard Worker            test_frame.symbols.analyze_node(node, for_branch='test')
1047*635a8641SAndroid Build Coastguard Worker            self.writeline('%s(fiter):' % self.func(loop_filter_func), node.test)
1048*635a8641SAndroid Build Coastguard Worker            self.indent()
1049*635a8641SAndroid Build Coastguard Worker            self.enter_frame(test_frame)
1050*635a8641SAndroid Build Coastguard Worker            self.writeline(self.environment.is_async and 'async for ' or 'for ')
1051*635a8641SAndroid Build Coastguard Worker            self.visit(node.target, loop_frame)
1052*635a8641SAndroid Build Coastguard Worker            self.write(' in ')
1053*635a8641SAndroid Build Coastguard Worker            self.write(self.environment.is_async and 'auto_aiter(fiter)' or 'fiter')
1054*635a8641SAndroid Build Coastguard Worker            self.write(':')
1055*635a8641SAndroid Build Coastguard Worker            self.indent()
1056*635a8641SAndroid Build Coastguard Worker            self.writeline('if ', node.test)
1057*635a8641SAndroid Build Coastguard Worker            self.visit(node.test, test_frame)
1058*635a8641SAndroid Build Coastguard Worker            self.write(':')
1059*635a8641SAndroid Build Coastguard Worker            self.indent()
1060*635a8641SAndroid Build Coastguard Worker            self.writeline('yield ')
1061*635a8641SAndroid Build Coastguard Worker            self.visit(node.target, loop_frame)
1062*635a8641SAndroid Build Coastguard Worker            self.outdent(3)
1063*635a8641SAndroid Build Coastguard Worker            self.leave_frame(test_frame, with_python_scope=True)
1064*635a8641SAndroid Build Coastguard Worker
1065*635a8641SAndroid Build Coastguard Worker        # if we don't have an recursive loop we have to find the shadowed
1066*635a8641SAndroid Build Coastguard Worker        # variables at that point.  Because loops can be nested but the loop
1067*635a8641SAndroid Build Coastguard Worker        # variable is a special one we have to enforce aliasing for it.
1068*635a8641SAndroid Build Coastguard Worker        if node.recursive:
1069*635a8641SAndroid Build Coastguard Worker            self.writeline('%s(reciter, loop_render_func, depth=0):' %
1070*635a8641SAndroid Build Coastguard Worker                           self.func('loop'), node)
1071*635a8641SAndroid Build Coastguard Worker            self.indent()
1072*635a8641SAndroid Build Coastguard Worker            self.buffer(loop_frame)
1073*635a8641SAndroid Build Coastguard Worker
1074*635a8641SAndroid Build Coastguard Worker            # Use the same buffer for the else frame
1075*635a8641SAndroid Build Coastguard Worker            else_frame.buffer = loop_frame.buffer
1076*635a8641SAndroid Build Coastguard Worker
1077*635a8641SAndroid Build Coastguard Worker        # make sure the loop variable is a special one and raise a template
1078*635a8641SAndroid Build Coastguard Worker        # assertion error if a loop tries to write to loop
1079*635a8641SAndroid Build Coastguard Worker        if extended_loop:
1080*635a8641SAndroid Build Coastguard Worker            self.writeline('%s = missing' % loop_ref)
1081*635a8641SAndroid Build Coastguard Worker
1082*635a8641SAndroid Build Coastguard Worker        for name in node.find_all(nodes.Name):
1083*635a8641SAndroid Build Coastguard Worker            if name.ctx == 'store' and name.name == 'loop':
1084*635a8641SAndroid Build Coastguard Worker                self.fail('Can\'t assign to special loop variable '
1085*635a8641SAndroid Build Coastguard Worker                          'in for-loop target', name.lineno)
1086*635a8641SAndroid Build Coastguard Worker
1087*635a8641SAndroid Build Coastguard Worker        if node.else_:
1088*635a8641SAndroid Build Coastguard Worker            iteration_indicator = self.temporary_identifier()
1089*635a8641SAndroid Build Coastguard Worker            self.writeline('%s = 1' % iteration_indicator)
1090*635a8641SAndroid Build Coastguard Worker
1091*635a8641SAndroid Build Coastguard Worker        self.writeline(self.environment.is_async and 'async for ' or 'for ', node)
1092*635a8641SAndroid Build Coastguard Worker        self.visit(node.target, loop_frame)
1093*635a8641SAndroid Build Coastguard Worker        if extended_loop:
1094*635a8641SAndroid Build Coastguard Worker            if self.environment.is_async:
1095*635a8641SAndroid Build Coastguard Worker                self.write(', %s in await make_async_loop_context(' % loop_ref)
1096*635a8641SAndroid Build Coastguard Worker            else:
1097*635a8641SAndroid Build Coastguard Worker                self.write(', %s in LoopContext(' % loop_ref)
1098*635a8641SAndroid Build Coastguard Worker        else:
1099*635a8641SAndroid Build Coastguard Worker            self.write(' in ')
1100*635a8641SAndroid Build Coastguard Worker
1101*635a8641SAndroid Build Coastguard Worker        if node.test:
1102*635a8641SAndroid Build Coastguard Worker            self.write('%s(' % loop_filter_func)
1103*635a8641SAndroid Build Coastguard Worker        if node.recursive:
1104*635a8641SAndroid Build Coastguard Worker            self.write('reciter')
1105*635a8641SAndroid Build Coastguard Worker        else:
1106*635a8641SAndroid Build Coastguard Worker            if self.environment.is_async and not extended_loop:
1107*635a8641SAndroid Build Coastguard Worker                self.write('auto_aiter(')
1108*635a8641SAndroid Build Coastguard Worker            self.visit(node.iter, frame)
1109*635a8641SAndroid Build Coastguard Worker            if self.environment.is_async and not extended_loop:
1110*635a8641SAndroid Build Coastguard Worker                self.write(')')
1111*635a8641SAndroid Build Coastguard Worker        if node.test:
1112*635a8641SAndroid Build Coastguard Worker            self.write(')')
1113*635a8641SAndroid Build Coastguard Worker
1114*635a8641SAndroid Build Coastguard Worker        if node.recursive:
1115*635a8641SAndroid Build Coastguard Worker            self.write(', undefined, loop_render_func, depth):')
1116*635a8641SAndroid Build Coastguard Worker        else:
1117*635a8641SAndroid Build Coastguard Worker            self.write(extended_loop and ', undefined):' or ':')
1118*635a8641SAndroid Build Coastguard Worker
1119*635a8641SAndroid Build Coastguard Worker        self.indent()
1120*635a8641SAndroid Build Coastguard Worker        self.enter_frame(loop_frame)
1121*635a8641SAndroid Build Coastguard Worker
1122*635a8641SAndroid Build Coastguard Worker        self.blockvisit(node.body, loop_frame)
1123*635a8641SAndroid Build Coastguard Worker        if node.else_:
1124*635a8641SAndroid Build Coastguard Worker            self.writeline('%s = 0' % iteration_indicator)
1125*635a8641SAndroid Build Coastguard Worker        self.outdent()
1126*635a8641SAndroid Build Coastguard Worker        self.leave_frame(loop_frame, with_python_scope=node.recursive
1127*635a8641SAndroid Build Coastguard Worker                         and not node.else_)
1128*635a8641SAndroid Build Coastguard Worker
1129*635a8641SAndroid Build Coastguard Worker        if node.else_:
1130*635a8641SAndroid Build Coastguard Worker            self.writeline('if %s:' % iteration_indicator)
1131*635a8641SAndroid Build Coastguard Worker            self.indent()
1132*635a8641SAndroid Build Coastguard Worker            self.enter_frame(else_frame)
1133*635a8641SAndroid Build Coastguard Worker            self.blockvisit(node.else_, else_frame)
1134*635a8641SAndroid Build Coastguard Worker            self.leave_frame(else_frame)
1135*635a8641SAndroid Build Coastguard Worker            self.outdent()
1136*635a8641SAndroid Build Coastguard Worker
1137*635a8641SAndroid Build Coastguard Worker        # if the node was recursive we have to return the buffer contents
1138*635a8641SAndroid Build Coastguard Worker        # and start the iteration code
1139*635a8641SAndroid Build Coastguard Worker        if node.recursive:
1140*635a8641SAndroid Build Coastguard Worker            self.return_buffer_contents(loop_frame)
1141*635a8641SAndroid Build Coastguard Worker            self.outdent()
1142*635a8641SAndroid Build Coastguard Worker            self.start_write(frame, node)
1143*635a8641SAndroid Build Coastguard Worker            if self.environment.is_async:
1144*635a8641SAndroid Build Coastguard Worker                self.write('await ')
1145*635a8641SAndroid Build Coastguard Worker            self.write('loop(')
1146*635a8641SAndroid Build Coastguard Worker            if self.environment.is_async:
1147*635a8641SAndroid Build Coastguard Worker                self.write('auto_aiter(')
1148*635a8641SAndroid Build Coastguard Worker            self.visit(node.iter, frame)
1149*635a8641SAndroid Build Coastguard Worker            if self.environment.is_async:
1150*635a8641SAndroid Build Coastguard Worker                self.write(')')
1151*635a8641SAndroid Build Coastguard Worker            self.write(', loop)')
1152*635a8641SAndroid Build Coastguard Worker            self.end_write(frame)
1153*635a8641SAndroid Build Coastguard Worker
1154*635a8641SAndroid Build Coastguard Worker    def visit_If(self, node, frame):
1155*635a8641SAndroid Build Coastguard Worker        if_frame = frame.soft()
1156*635a8641SAndroid Build Coastguard Worker        self.writeline('if ', node)
1157*635a8641SAndroid Build Coastguard Worker        self.visit(node.test, if_frame)
1158*635a8641SAndroid Build Coastguard Worker        self.write(':')
1159*635a8641SAndroid Build Coastguard Worker        self.indent()
1160*635a8641SAndroid Build Coastguard Worker        self.blockvisit(node.body, if_frame)
1161*635a8641SAndroid Build Coastguard Worker        self.outdent()
1162*635a8641SAndroid Build Coastguard Worker        for elif_ in node.elif_:
1163*635a8641SAndroid Build Coastguard Worker            self.writeline('elif ', elif_)
1164*635a8641SAndroid Build Coastguard Worker            self.visit(elif_.test, if_frame)
1165*635a8641SAndroid Build Coastguard Worker            self.write(':')
1166*635a8641SAndroid Build Coastguard Worker            self.indent()
1167*635a8641SAndroid Build Coastguard Worker            self.blockvisit(elif_.body, if_frame)
1168*635a8641SAndroid Build Coastguard Worker            self.outdent()
1169*635a8641SAndroid Build Coastguard Worker        if node.else_:
1170*635a8641SAndroid Build Coastguard Worker            self.writeline('else:')
1171*635a8641SAndroid Build Coastguard Worker            self.indent()
1172*635a8641SAndroid Build Coastguard Worker            self.blockvisit(node.else_, if_frame)
1173*635a8641SAndroid Build Coastguard Worker            self.outdent()
1174*635a8641SAndroid Build Coastguard Worker
1175*635a8641SAndroid Build Coastguard Worker    def visit_Macro(self, node, frame):
1176*635a8641SAndroid Build Coastguard Worker        macro_frame, macro_ref = self.macro_body(node, frame)
1177*635a8641SAndroid Build Coastguard Worker        self.newline()
1178*635a8641SAndroid Build Coastguard Worker        if frame.toplevel:
1179*635a8641SAndroid Build Coastguard Worker            if not node.name.startswith('_'):
1180*635a8641SAndroid Build Coastguard Worker                self.write('context.exported_vars.add(%r)' % node.name)
1181*635a8641SAndroid Build Coastguard Worker            ref = frame.symbols.ref(node.name)
1182*635a8641SAndroid Build Coastguard Worker            self.writeline('context.vars[%r] = ' % node.name)
1183*635a8641SAndroid Build Coastguard Worker        self.write('%s = ' % frame.symbols.ref(node.name))
1184*635a8641SAndroid Build Coastguard Worker        self.macro_def(macro_ref, macro_frame)
1185*635a8641SAndroid Build Coastguard Worker
1186*635a8641SAndroid Build Coastguard Worker    def visit_CallBlock(self, node, frame):
1187*635a8641SAndroid Build Coastguard Worker        call_frame, macro_ref = self.macro_body(node, frame)
1188*635a8641SAndroid Build Coastguard Worker        self.writeline('caller = ')
1189*635a8641SAndroid Build Coastguard Worker        self.macro_def(macro_ref, call_frame)
1190*635a8641SAndroid Build Coastguard Worker        self.start_write(frame, node)
1191*635a8641SAndroid Build Coastguard Worker        self.visit_Call(node.call, frame, forward_caller=True)
1192*635a8641SAndroid Build Coastguard Worker        self.end_write(frame)
1193*635a8641SAndroid Build Coastguard Worker
1194*635a8641SAndroid Build Coastguard Worker    def visit_FilterBlock(self, node, frame):
1195*635a8641SAndroid Build Coastguard Worker        filter_frame = frame.inner()
1196*635a8641SAndroid Build Coastguard Worker        filter_frame.symbols.analyze_node(node)
1197*635a8641SAndroid Build Coastguard Worker        self.enter_frame(filter_frame)
1198*635a8641SAndroid Build Coastguard Worker        self.buffer(filter_frame)
1199*635a8641SAndroid Build Coastguard Worker        self.blockvisit(node.body, filter_frame)
1200*635a8641SAndroid Build Coastguard Worker        self.start_write(frame, node)
1201*635a8641SAndroid Build Coastguard Worker        self.visit_Filter(node.filter, filter_frame)
1202*635a8641SAndroid Build Coastguard Worker        self.end_write(frame)
1203*635a8641SAndroid Build Coastguard Worker        self.leave_frame(filter_frame)
1204*635a8641SAndroid Build Coastguard Worker
1205*635a8641SAndroid Build Coastguard Worker    def visit_With(self, node, frame):
1206*635a8641SAndroid Build Coastguard Worker        with_frame = frame.inner()
1207*635a8641SAndroid Build Coastguard Worker        with_frame.symbols.analyze_node(node)
1208*635a8641SAndroid Build Coastguard Worker        self.enter_frame(with_frame)
1209*635a8641SAndroid Build Coastguard Worker        for idx, (target, expr) in enumerate(izip(node.targets, node.values)):
1210*635a8641SAndroid Build Coastguard Worker            self.newline()
1211*635a8641SAndroid Build Coastguard Worker            self.visit(target, with_frame)
1212*635a8641SAndroid Build Coastguard Worker            self.write(' = ')
1213*635a8641SAndroid Build Coastguard Worker            self.visit(expr, frame)
1214*635a8641SAndroid Build Coastguard Worker        self.blockvisit(node.body, with_frame)
1215*635a8641SAndroid Build Coastguard Worker        self.leave_frame(with_frame)
1216*635a8641SAndroid Build Coastguard Worker
1217*635a8641SAndroid Build Coastguard Worker    def visit_ExprStmt(self, node, frame):
1218*635a8641SAndroid Build Coastguard Worker        self.newline(node)
1219*635a8641SAndroid Build Coastguard Worker        self.visit(node.node, frame)
1220*635a8641SAndroid Build Coastguard Worker
1221*635a8641SAndroid Build Coastguard Worker    def visit_Output(self, node, frame):
1222*635a8641SAndroid Build Coastguard Worker        # if we have a known extends statement, we don't output anything
1223*635a8641SAndroid Build Coastguard Worker        # if we are in a require_output_check section
1224*635a8641SAndroid Build Coastguard Worker        if self.has_known_extends and frame.require_output_check:
1225*635a8641SAndroid Build Coastguard Worker            return
1226*635a8641SAndroid Build Coastguard Worker
1227*635a8641SAndroid Build Coastguard Worker        allow_constant_finalize = True
1228*635a8641SAndroid Build Coastguard Worker        if self.environment.finalize:
1229*635a8641SAndroid Build Coastguard Worker            func = self.environment.finalize
1230*635a8641SAndroid Build Coastguard Worker            if getattr(func, 'contextfunction', False) or \
1231*635a8641SAndroid Build Coastguard Worker               getattr(func, 'evalcontextfunction', False):
1232*635a8641SAndroid Build Coastguard Worker                allow_constant_finalize = False
1233*635a8641SAndroid Build Coastguard Worker            elif getattr(func, 'environmentfunction', False):
1234*635a8641SAndroid Build Coastguard Worker                finalize = lambda x: text_type(
1235*635a8641SAndroid Build Coastguard Worker                    self.environment.finalize(self.environment, x))
1236*635a8641SAndroid Build Coastguard Worker            else:
1237*635a8641SAndroid Build Coastguard Worker                finalize = lambda x: text_type(self.environment.finalize(x))
1238*635a8641SAndroid Build Coastguard Worker        else:
1239*635a8641SAndroid Build Coastguard Worker            finalize = text_type
1240*635a8641SAndroid Build Coastguard Worker
1241*635a8641SAndroid Build Coastguard Worker        # if we are inside a frame that requires output checking, we do so
1242*635a8641SAndroid Build Coastguard Worker        outdent_later = False
1243*635a8641SAndroid Build Coastguard Worker        if frame.require_output_check:
1244*635a8641SAndroid Build Coastguard Worker            self.writeline('if parent_template is None:')
1245*635a8641SAndroid Build Coastguard Worker            self.indent()
1246*635a8641SAndroid Build Coastguard Worker            outdent_later = True
1247*635a8641SAndroid Build Coastguard Worker
1248*635a8641SAndroid Build Coastguard Worker        # try to evaluate as many chunks as possible into a static
1249*635a8641SAndroid Build Coastguard Worker        # string at compile time.
1250*635a8641SAndroid Build Coastguard Worker        body = []
1251*635a8641SAndroid Build Coastguard Worker        for child in node.nodes:
1252*635a8641SAndroid Build Coastguard Worker            try:
1253*635a8641SAndroid Build Coastguard Worker                if not allow_constant_finalize:
1254*635a8641SAndroid Build Coastguard Worker                    raise nodes.Impossible()
1255*635a8641SAndroid Build Coastguard Worker                const = child.as_const(frame.eval_ctx)
1256*635a8641SAndroid Build Coastguard Worker            except nodes.Impossible:
1257*635a8641SAndroid Build Coastguard Worker                body.append(child)
1258*635a8641SAndroid Build Coastguard Worker                continue
1259*635a8641SAndroid Build Coastguard Worker            # the frame can't be volatile here, becaus otherwise the
1260*635a8641SAndroid Build Coastguard Worker            # as_const() function would raise an Impossible exception
1261*635a8641SAndroid Build Coastguard Worker            # at that point.
1262*635a8641SAndroid Build Coastguard Worker            try:
1263*635a8641SAndroid Build Coastguard Worker                if frame.eval_ctx.autoescape:
1264*635a8641SAndroid Build Coastguard Worker                    if hasattr(const, '__html__'):
1265*635a8641SAndroid Build Coastguard Worker                        const = const.__html__()
1266*635a8641SAndroid Build Coastguard Worker                    else:
1267*635a8641SAndroid Build Coastguard Worker                        const = escape(const)
1268*635a8641SAndroid Build Coastguard Worker                const = finalize(const)
1269*635a8641SAndroid Build Coastguard Worker            except Exception:
1270*635a8641SAndroid Build Coastguard Worker                # if something goes wrong here we evaluate the node
1271*635a8641SAndroid Build Coastguard Worker                # at runtime for easier debugging
1272*635a8641SAndroid Build Coastguard Worker                body.append(child)
1273*635a8641SAndroid Build Coastguard Worker                continue
1274*635a8641SAndroid Build Coastguard Worker            if body and isinstance(body[-1], list):
1275*635a8641SAndroid Build Coastguard Worker                body[-1].append(const)
1276*635a8641SAndroid Build Coastguard Worker            else:
1277*635a8641SAndroid Build Coastguard Worker                body.append([const])
1278*635a8641SAndroid Build Coastguard Worker
1279*635a8641SAndroid Build Coastguard Worker        # if we have less than 3 nodes or a buffer we yield or extend/append
1280*635a8641SAndroid Build Coastguard Worker        if len(body) < 3 or frame.buffer is not None:
1281*635a8641SAndroid Build Coastguard Worker            if frame.buffer is not None:
1282*635a8641SAndroid Build Coastguard Worker                # for one item we append, for more we extend
1283*635a8641SAndroid Build Coastguard Worker                if len(body) == 1:
1284*635a8641SAndroid Build Coastguard Worker                    self.writeline('%s.append(' % frame.buffer)
1285*635a8641SAndroid Build Coastguard Worker                else:
1286*635a8641SAndroid Build Coastguard Worker                    self.writeline('%s.extend((' % frame.buffer)
1287*635a8641SAndroid Build Coastguard Worker                self.indent()
1288*635a8641SAndroid Build Coastguard Worker            for item in body:
1289*635a8641SAndroid Build Coastguard Worker                if isinstance(item, list):
1290*635a8641SAndroid Build Coastguard Worker                    val = repr(concat(item))
1291*635a8641SAndroid Build Coastguard Worker                    if frame.buffer is None:
1292*635a8641SAndroid Build Coastguard Worker                        self.writeline('yield ' + val)
1293*635a8641SAndroid Build Coastguard Worker                    else:
1294*635a8641SAndroid Build Coastguard Worker                        self.writeline(val + ',')
1295*635a8641SAndroid Build Coastguard Worker                else:
1296*635a8641SAndroid Build Coastguard Worker                    if frame.buffer is None:
1297*635a8641SAndroid Build Coastguard Worker                        self.writeline('yield ', item)
1298*635a8641SAndroid Build Coastguard Worker                    else:
1299*635a8641SAndroid Build Coastguard Worker                        self.newline(item)
1300*635a8641SAndroid Build Coastguard Worker                    close = 1
1301*635a8641SAndroid Build Coastguard Worker                    if frame.eval_ctx.volatile:
1302*635a8641SAndroid Build Coastguard Worker                        self.write('(escape if context.eval_ctx.autoescape'
1303*635a8641SAndroid Build Coastguard Worker                                   ' else to_string)(')
1304*635a8641SAndroid Build Coastguard Worker                    elif frame.eval_ctx.autoescape:
1305*635a8641SAndroid Build Coastguard Worker                        self.write('escape(')
1306*635a8641SAndroid Build Coastguard Worker                    else:
1307*635a8641SAndroid Build Coastguard Worker                        self.write('to_string(')
1308*635a8641SAndroid Build Coastguard Worker                    if self.environment.finalize is not None:
1309*635a8641SAndroid Build Coastguard Worker                        self.write('environment.finalize(')
1310*635a8641SAndroid Build Coastguard Worker                        if getattr(self.environment.finalize,
1311*635a8641SAndroid Build Coastguard Worker                                   "contextfunction", False):
1312*635a8641SAndroid Build Coastguard Worker                            self.write('context, ')
1313*635a8641SAndroid Build Coastguard Worker                        close += 1
1314*635a8641SAndroid Build Coastguard Worker                    self.visit(item, frame)
1315*635a8641SAndroid Build Coastguard Worker                    self.write(')' * close)
1316*635a8641SAndroid Build Coastguard Worker                    if frame.buffer is not None:
1317*635a8641SAndroid Build Coastguard Worker                        self.write(',')
1318*635a8641SAndroid Build Coastguard Worker            if frame.buffer is not None:
1319*635a8641SAndroid Build Coastguard Worker                # close the open parentheses
1320*635a8641SAndroid Build Coastguard Worker                self.outdent()
1321*635a8641SAndroid Build Coastguard Worker                self.writeline(len(body) == 1 and ')' or '))')
1322*635a8641SAndroid Build Coastguard Worker
1323*635a8641SAndroid Build Coastguard Worker        # otherwise we create a format string as this is faster in that case
1324*635a8641SAndroid Build Coastguard Worker        else:
1325*635a8641SAndroid Build Coastguard Worker            format = []
1326*635a8641SAndroid Build Coastguard Worker            arguments = []
1327*635a8641SAndroid Build Coastguard Worker            for item in body:
1328*635a8641SAndroid Build Coastguard Worker                if isinstance(item, list):
1329*635a8641SAndroid Build Coastguard Worker                    format.append(concat(item).replace('%', '%%'))
1330*635a8641SAndroid Build Coastguard Worker                else:
1331*635a8641SAndroid Build Coastguard Worker                    format.append('%s')
1332*635a8641SAndroid Build Coastguard Worker                    arguments.append(item)
1333*635a8641SAndroid Build Coastguard Worker            self.writeline('yield ')
1334*635a8641SAndroid Build Coastguard Worker            self.write(repr(concat(format)) + ' % (')
1335*635a8641SAndroid Build Coastguard Worker            self.indent()
1336*635a8641SAndroid Build Coastguard Worker            for argument in arguments:
1337*635a8641SAndroid Build Coastguard Worker                self.newline(argument)
1338*635a8641SAndroid Build Coastguard Worker                close = 0
1339*635a8641SAndroid Build Coastguard Worker                if frame.eval_ctx.volatile:
1340*635a8641SAndroid Build Coastguard Worker                    self.write('(escape if context.eval_ctx.autoescape else'
1341*635a8641SAndroid Build Coastguard Worker                               ' to_string)(')
1342*635a8641SAndroid Build Coastguard Worker                    close += 1
1343*635a8641SAndroid Build Coastguard Worker                elif frame.eval_ctx.autoescape:
1344*635a8641SAndroid Build Coastguard Worker                    self.write('escape(')
1345*635a8641SAndroid Build Coastguard Worker                    close += 1
1346*635a8641SAndroid Build Coastguard Worker                if self.environment.finalize is not None:
1347*635a8641SAndroid Build Coastguard Worker                    self.write('environment.finalize(')
1348*635a8641SAndroid Build Coastguard Worker                    if getattr(self.environment.finalize,
1349*635a8641SAndroid Build Coastguard Worker                               'contextfunction', False):
1350*635a8641SAndroid Build Coastguard Worker                        self.write('context, ')
1351*635a8641SAndroid Build Coastguard Worker                    elif getattr(self.environment.finalize,
1352*635a8641SAndroid Build Coastguard Worker                               'evalcontextfunction', False):
1353*635a8641SAndroid Build Coastguard Worker                        self.write('context.eval_ctx, ')
1354*635a8641SAndroid Build Coastguard Worker                    elif getattr(self.environment.finalize,
1355*635a8641SAndroid Build Coastguard Worker                               'environmentfunction', False):
1356*635a8641SAndroid Build Coastguard Worker                        self.write('environment, ')
1357*635a8641SAndroid Build Coastguard Worker                    close += 1
1358*635a8641SAndroid Build Coastguard Worker                self.visit(argument, frame)
1359*635a8641SAndroid Build Coastguard Worker                self.write(')' * close + ', ')
1360*635a8641SAndroid Build Coastguard Worker            self.outdent()
1361*635a8641SAndroid Build Coastguard Worker            self.writeline(')')
1362*635a8641SAndroid Build Coastguard Worker
1363*635a8641SAndroid Build Coastguard Worker        if outdent_later:
1364*635a8641SAndroid Build Coastguard Worker            self.outdent()
1365*635a8641SAndroid Build Coastguard Worker
1366*635a8641SAndroid Build Coastguard Worker    def visit_Assign(self, node, frame):
1367*635a8641SAndroid Build Coastguard Worker        self.push_assign_tracking()
1368*635a8641SAndroid Build Coastguard Worker        self.newline(node)
1369*635a8641SAndroid Build Coastguard Worker        self.visit(node.target, frame)
1370*635a8641SAndroid Build Coastguard Worker        self.write(' = ')
1371*635a8641SAndroid Build Coastguard Worker        self.visit(node.node, frame)
1372*635a8641SAndroid Build Coastguard Worker        self.pop_assign_tracking(frame)
1373*635a8641SAndroid Build Coastguard Worker
1374*635a8641SAndroid Build Coastguard Worker    def visit_AssignBlock(self, node, frame):
1375*635a8641SAndroid Build Coastguard Worker        self.push_assign_tracking()
1376*635a8641SAndroid Build Coastguard Worker        block_frame = frame.inner()
1377*635a8641SAndroid Build Coastguard Worker        # This is a special case.  Since a set block always captures we
1378*635a8641SAndroid Build Coastguard Worker        # will disable output checks.  This way one can use set blocks
1379*635a8641SAndroid Build Coastguard Worker        # toplevel even in extended templates.
1380*635a8641SAndroid Build Coastguard Worker        block_frame.require_output_check = False
1381*635a8641SAndroid Build Coastguard Worker        block_frame.symbols.analyze_node(node)
1382*635a8641SAndroid Build Coastguard Worker        self.enter_frame(block_frame)
1383*635a8641SAndroid Build Coastguard Worker        self.buffer(block_frame)
1384*635a8641SAndroid Build Coastguard Worker        self.blockvisit(node.body, block_frame)
1385*635a8641SAndroid Build Coastguard Worker        self.newline(node)
1386*635a8641SAndroid Build Coastguard Worker        self.visit(node.target, frame)
1387*635a8641SAndroid Build Coastguard Worker        self.write(' = (Markup if context.eval_ctx.autoescape '
1388*635a8641SAndroid Build Coastguard Worker                   'else identity)(')
1389*635a8641SAndroid Build Coastguard Worker        if node.filter is not None:
1390*635a8641SAndroid Build Coastguard Worker            self.visit_Filter(node.filter, block_frame)
1391*635a8641SAndroid Build Coastguard Worker        else:
1392*635a8641SAndroid Build Coastguard Worker            self.write('concat(%s)' % block_frame.buffer)
1393*635a8641SAndroid Build Coastguard Worker        self.write(')')
1394*635a8641SAndroid Build Coastguard Worker        self.pop_assign_tracking(frame)
1395*635a8641SAndroid Build Coastguard Worker        self.leave_frame(block_frame)
1396*635a8641SAndroid Build Coastguard Worker
1397*635a8641SAndroid Build Coastguard Worker    # -- Expression Visitors
1398*635a8641SAndroid Build Coastguard Worker
1399*635a8641SAndroid Build Coastguard Worker    def visit_Name(self, node, frame):
1400*635a8641SAndroid Build Coastguard Worker        if node.ctx == 'store' and frame.toplevel:
1401*635a8641SAndroid Build Coastguard Worker            if self._assign_stack:
1402*635a8641SAndroid Build Coastguard Worker                self._assign_stack[-1].add(node.name)
1403*635a8641SAndroid Build Coastguard Worker        ref = frame.symbols.ref(node.name)
1404*635a8641SAndroid Build Coastguard Worker
1405*635a8641SAndroid Build Coastguard Worker        # If we are looking up a variable we might have to deal with the
1406*635a8641SAndroid Build Coastguard Worker        # case where it's undefined.  We can skip that case if the load
1407*635a8641SAndroid Build Coastguard Worker        # instruction indicates a parameter which are always defined.
1408*635a8641SAndroid Build Coastguard Worker        if node.ctx == 'load':
1409*635a8641SAndroid Build Coastguard Worker            load = frame.symbols.find_load(ref)
1410*635a8641SAndroid Build Coastguard Worker            if not (load is not None and load[0] == VAR_LOAD_PARAMETER and \
1411*635a8641SAndroid Build Coastguard Worker                    not self.parameter_is_undeclared(ref)):
1412*635a8641SAndroid Build Coastguard Worker                self.write('(undefined(name=%r) if %s is missing else %s)' %
1413*635a8641SAndroid Build Coastguard Worker                           (node.name, ref, ref))
1414*635a8641SAndroid Build Coastguard Worker                return
1415*635a8641SAndroid Build Coastguard Worker
1416*635a8641SAndroid Build Coastguard Worker        self.write(ref)
1417*635a8641SAndroid Build Coastguard Worker
1418*635a8641SAndroid Build Coastguard Worker    def visit_NSRef(self, node, frame):
1419*635a8641SAndroid Build Coastguard Worker        # NSRefs can only be used to store values; since they use the normal
1420*635a8641SAndroid Build Coastguard Worker        # `foo.bar` notation they will be parsed as a normal attribute access
1421*635a8641SAndroid Build Coastguard Worker        # when used anywhere but in a `set` context
1422*635a8641SAndroid Build Coastguard Worker        ref = frame.symbols.ref(node.name)
1423*635a8641SAndroid Build Coastguard Worker        self.writeline('if not isinstance(%s, Namespace):' % ref)
1424*635a8641SAndroid Build Coastguard Worker        self.indent()
1425*635a8641SAndroid Build Coastguard Worker        self.writeline('raise TemplateRuntimeError(%r)' %
1426*635a8641SAndroid Build Coastguard Worker                       'cannot assign attribute on non-namespace object')
1427*635a8641SAndroid Build Coastguard Worker        self.outdent()
1428*635a8641SAndroid Build Coastguard Worker        self.writeline('%s[%r]' % (ref, node.attr))
1429*635a8641SAndroid Build Coastguard Worker
1430*635a8641SAndroid Build Coastguard Worker    def visit_Const(self, node, frame):
1431*635a8641SAndroid Build Coastguard Worker        val = node.as_const(frame.eval_ctx)
1432*635a8641SAndroid Build Coastguard Worker        if isinstance(val, float):
1433*635a8641SAndroid Build Coastguard Worker            self.write(str(val))
1434*635a8641SAndroid Build Coastguard Worker        else:
1435*635a8641SAndroid Build Coastguard Worker            self.write(repr(val))
1436*635a8641SAndroid Build Coastguard Worker
1437*635a8641SAndroid Build Coastguard Worker    def visit_TemplateData(self, node, frame):
1438*635a8641SAndroid Build Coastguard Worker        try:
1439*635a8641SAndroid Build Coastguard Worker            self.write(repr(node.as_const(frame.eval_ctx)))
1440*635a8641SAndroid Build Coastguard Worker        except nodes.Impossible:
1441*635a8641SAndroid Build Coastguard Worker            self.write('(Markup if context.eval_ctx.autoescape else identity)(%r)'
1442*635a8641SAndroid Build Coastguard Worker                       % node.data)
1443*635a8641SAndroid Build Coastguard Worker
1444*635a8641SAndroid Build Coastguard Worker    def visit_Tuple(self, node, frame):
1445*635a8641SAndroid Build Coastguard Worker        self.write('(')
1446*635a8641SAndroid Build Coastguard Worker        idx = -1
1447*635a8641SAndroid Build Coastguard Worker        for idx, item in enumerate(node.items):
1448*635a8641SAndroid Build Coastguard Worker            if idx:
1449*635a8641SAndroid Build Coastguard Worker                self.write(', ')
1450*635a8641SAndroid Build Coastguard Worker            self.visit(item, frame)
1451*635a8641SAndroid Build Coastguard Worker        self.write(idx == 0 and ',)' or ')')
1452*635a8641SAndroid Build Coastguard Worker
1453*635a8641SAndroid Build Coastguard Worker    def visit_List(self, node, frame):
1454*635a8641SAndroid Build Coastguard Worker        self.write('[')
1455*635a8641SAndroid Build Coastguard Worker        for idx, item in enumerate(node.items):
1456*635a8641SAndroid Build Coastguard Worker            if idx:
1457*635a8641SAndroid Build Coastguard Worker                self.write(', ')
1458*635a8641SAndroid Build Coastguard Worker            self.visit(item, frame)
1459*635a8641SAndroid Build Coastguard Worker        self.write(']')
1460*635a8641SAndroid Build Coastguard Worker
1461*635a8641SAndroid Build Coastguard Worker    def visit_Dict(self, node, frame):
1462*635a8641SAndroid Build Coastguard Worker        self.write('{')
1463*635a8641SAndroid Build Coastguard Worker        for idx, item in enumerate(node.items):
1464*635a8641SAndroid Build Coastguard Worker            if idx:
1465*635a8641SAndroid Build Coastguard Worker                self.write(', ')
1466*635a8641SAndroid Build Coastguard Worker            self.visit(item.key, frame)
1467*635a8641SAndroid Build Coastguard Worker            self.write(': ')
1468*635a8641SAndroid Build Coastguard Worker            self.visit(item.value, frame)
1469*635a8641SAndroid Build Coastguard Worker        self.write('}')
1470*635a8641SAndroid Build Coastguard Worker
1471*635a8641SAndroid Build Coastguard Worker    def binop(operator, interceptable=True):
1472*635a8641SAndroid Build Coastguard Worker        @optimizeconst
1473*635a8641SAndroid Build Coastguard Worker        def visitor(self, node, frame):
1474*635a8641SAndroid Build Coastguard Worker            if self.environment.sandboxed and \
1475*635a8641SAndroid Build Coastguard Worker               operator in self.environment.intercepted_binops:
1476*635a8641SAndroid Build Coastguard Worker                self.write('environment.call_binop(context, %r, ' % operator)
1477*635a8641SAndroid Build Coastguard Worker                self.visit(node.left, frame)
1478*635a8641SAndroid Build Coastguard Worker                self.write(', ')
1479*635a8641SAndroid Build Coastguard Worker                self.visit(node.right, frame)
1480*635a8641SAndroid Build Coastguard Worker            else:
1481*635a8641SAndroid Build Coastguard Worker                self.write('(')
1482*635a8641SAndroid Build Coastguard Worker                self.visit(node.left, frame)
1483*635a8641SAndroid Build Coastguard Worker                self.write(' %s ' % operator)
1484*635a8641SAndroid Build Coastguard Worker                self.visit(node.right, frame)
1485*635a8641SAndroid Build Coastguard Worker            self.write(')')
1486*635a8641SAndroid Build Coastguard Worker        return visitor
1487*635a8641SAndroid Build Coastguard Worker
1488*635a8641SAndroid Build Coastguard Worker    def uaop(operator, interceptable=True):
1489*635a8641SAndroid Build Coastguard Worker        @optimizeconst
1490*635a8641SAndroid Build Coastguard Worker        def visitor(self, node, frame):
1491*635a8641SAndroid Build Coastguard Worker            if self.environment.sandboxed and \
1492*635a8641SAndroid Build Coastguard Worker               operator in self.environment.intercepted_unops:
1493*635a8641SAndroid Build Coastguard Worker                self.write('environment.call_unop(context, %r, ' % operator)
1494*635a8641SAndroid Build Coastguard Worker                self.visit(node.node, frame)
1495*635a8641SAndroid Build Coastguard Worker            else:
1496*635a8641SAndroid Build Coastguard Worker                self.write('(' + operator)
1497*635a8641SAndroid Build Coastguard Worker                self.visit(node.node, frame)
1498*635a8641SAndroid Build Coastguard Worker            self.write(')')
1499*635a8641SAndroid Build Coastguard Worker        return visitor
1500*635a8641SAndroid Build Coastguard Worker
1501*635a8641SAndroid Build Coastguard Worker    visit_Add = binop('+')
1502*635a8641SAndroid Build Coastguard Worker    visit_Sub = binop('-')
1503*635a8641SAndroid Build Coastguard Worker    visit_Mul = binop('*')
1504*635a8641SAndroid Build Coastguard Worker    visit_Div = binop('/')
1505*635a8641SAndroid Build Coastguard Worker    visit_FloorDiv = binop('//')
1506*635a8641SAndroid Build Coastguard Worker    visit_Pow = binop('**')
1507*635a8641SAndroid Build Coastguard Worker    visit_Mod = binop('%')
1508*635a8641SAndroid Build Coastguard Worker    visit_And = binop('and', interceptable=False)
1509*635a8641SAndroid Build Coastguard Worker    visit_Or = binop('or', interceptable=False)
1510*635a8641SAndroid Build Coastguard Worker    visit_Pos = uaop('+')
1511*635a8641SAndroid Build Coastguard Worker    visit_Neg = uaop('-')
1512*635a8641SAndroid Build Coastguard Worker    visit_Not = uaop('not ', interceptable=False)
1513*635a8641SAndroid Build Coastguard Worker    del binop, uaop
1514*635a8641SAndroid Build Coastguard Worker
1515*635a8641SAndroid Build Coastguard Worker    @optimizeconst
1516*635a8641SAndroid Build Coastguard Worker    def visit_Concat(self, node, frame):
1517*635a8641SAndroid Build Coastguard Worker        if frame.eval_ctx.volatile:
1518*635a8641SAndroid Build Coastguard Worker            func_name = '(context.eval_ctx.volatile and' \
1519*635a8641SAndroid Build Coastguard Worker                        ' markup_join or unicode_join)'
1520*635a8641SAndroid Build Coastguard Worker        elif frame.eval_ctx.autoescape:
1521*635a8641SAndroid Build Coastguard Worker            func_name = 'markup_join'
1522*635a8641SAndroid Build Coastguard Worker        else:
1523*635a8641SAndroid Build Coastguard Worker            func_name = 'unicode_join'
1524*635a8641SAndroid Build Coastguard Worker        self.write('%s((' % func_name)
1525*635a8641SAndroid Build Coastguard Worker        for arg in node.nodes:
1526*635a8641SAndroid Build Coastguard Worker            self.visit(arg, frame)
1527*635a8641SAndroid Build Coastguard Worker            self.write(', ')
1528*635a8641SAndroid Build Coastguard Worker        self.write('))')
1529*635a8641SAndroid Build Coastguard Worker
1530*635a8641SAndroid Build Coastguard Worker    @optimizeconst
1531*635a8641SAndroid Build Coastguard Worker    def visit_Compare(self, node, frame):
1532*635a8641SAndroid Build Coastguard Worker        self.visit(node.expr, frame)
1533*635a8641SAndroid Build Coastguard Worker        for op in node.ops:
1534*635a8641SAndroid Build Coastguard Worker            self.visit(op, frame)
1535*635a8641SAndroid Build Coastguard Worker
1536*635a8641SAndroid Build Coastguard Worker    def visit_Operand(self, node, frame):
1537*635a8641SAndroid Build Coastguard Worker        self.write(' %s ' % operators[node.op])
1538*635a8641SAndroid Build Coastguard Worker        self.visit(node.expr, frame)
1539*635a8641SAndroid Build Coastguard Worker
1540*635a8641SAndroid Build Coastguard Worker    @optimizeconst
1541*635a8641SAndroid Build Coastguard Worker    def visit_Getattr(self, node, frame):
1542*635a8641SAndroid Build Coastguard Worker        self.write('environment.getattr(')
1543*635a8641SAndroid Build Coastguard Worker        self.visit(node.node, frame)
1544*635a8641SAndroid Build Coastguard Worker        self.write(', %r)' % node.attr)
1545*635a8641SAndroid Build Coastguard Worker
1546*635a8641SAndroid Build Coastguard Worker    @optimizeconst
1547*635a8641SAndroid Build Coastguard Worker    def visit_Getitem(self, node, frame):
1548*635a8641SAndroid Build Coastguard Worker        # slices bypass the environment getitem method.
1549*635a8641SAndroid Build Coastguard Worker        if isinstance(node.arg, nodes.Slice):
1550*635a8641SAndroid Build Coastguard Worker            self.visit(node.node, frame)
1551*635a8641SAndroid Build Coastguard Worker            self.write('[')
1552*635a8641SAndroid Build Coastguard Worker            self.visit(node.arg, frame)
1553*635a8641SAndroid Build Coastguard Worker            self.write(']')
1554*635a8641SAndroid Build Coastguard Worker        else:
1555*635a8641SAndroid Build Coastguard Worker            self.write('environment.getitem(')
1556*635a8641SAndroid Build Coastguard Worker            self.visit(node.node, frame)
1557*635a8641SAndroid Build Coastguard Worker            self.write(', ')
1558*635a8641SAndroid Build Coastguard Worker            self.visit(node.arg, frame)
1559*635a8641SAndroid Build Coastguard Worker            self.write(')')
1560*635a8641SAndroid Build Coastguard Worker
1561*635a8641SAndroid Build Coastguard Worker    def visit_Slice(self, node, frame):
1562*635a8641SAndroid Build Coastguard Worker        if node.start is not None:
1563*635a8641SAndroid Build Coastguard Worker            self.visit(node.start, frame)
1564*635a8641SAndroid Build Coastguard Worker        self.write(':')
1565*635a8641SAndroid Build Coastguard Worker        if node.stop is not None:
1566*635a8641SAndroid Build Coastguard Worker            self.visit(node.stop, frame)
1567*635a8641SAndroid Build Coastguard Worker        if node.step is not None:
1568*635a8641SAndroid Build Coastguard Worker            self.write(':')
1569*635a8641SAndroid Build Coastguard Worker            self.visit(node.step, frame)
1570*635a8641SAndroid Build Coastguard Worker
1571*635a8641SAndroid Build Coastguard Worker    @optimizeconst
1572*635a8641SAndroid Build Coastguard Worker    def visit_Filter(self, node, frame):
1573*635a8641SAndroid Build Coastguard Worker        if self.environment.is_async:
1574*635a8641SAndroid Build Coastguard Worker            self.write('await auto_await(')
1575*635a8641SAndroid Build Coastguard Worker        self.write(self.filters[node.name] + '(')
1576*635a8641SAndroid Build Coastguard Worker        func = self.environment.filters.get(node.name)
1577*635a8641SAndroid Build Coastguard Worker        if func is None:
1578*635a8641SAndroid Build Coastguard Worker            self.fail('no filter named %r' % node.name, node.lineno)
1579*635a8641SAndroid Build Coastguard Worker        if getattr(func, 'contextfilter', False):
1580*635a8641SAndroid Build Coastguard Worker            self.write('context, ')
1581*635a8641SAndroid Build Coastguard Worker        elif getattr(func, 'evalcontextfilter', False):
1582*635a8641SAndroid Build Coastguard Worker            self.write('context.eval_ctx, ')
1583*635a8641SAndroid Build Coastguard Worker        elif getattr(func, 'environmentfilter', False):
1584*635a8641SAndroid Build Coastguard Worker            self.write('environment, ')
1585*635a8641SAndroid Build Coastguard Worker
1586*635a8641SAndroid Build Coastguard Worker        # if the filter node is None we are inside a filter block
1587*635a8641SAndroid Build Coastguard Worker        # and want to write to the current buffer
1588*635a8641SAndroid Build Coastguard Worker        if node.node is not None:
1589*635a8641SAndroid Build Coastguard Worker            self.visit(node.node, frame)
1590*635a8641SAndroid Build Coastguard Worker        elif frame.eval_ctx.volatile:
1591*635a8641SAndroid Build Coastguard Worker            self.write('(context.eval_ctx.autoescape and'
1592*635a8641SAndroid Build Coastguard Worker                       ' Markup(concat(%s)) or concat(%s))' %
1593*635a8641SAndroid Build Coastguard Worker                       (frame.buffer, frame.buffer))
1594*635a8641SAndroid Build Coastguard Worker        elif frame.eval_ctx.autoescape:
1595*635a8641SAndroid Build Coastguard Worker            self.write('Markup(concat(%s))' % frame.buffer)
1596*635a8641SAndroid Build Coastguard Worker        else:
1597*635a8641SAndroid Build Coastguard Worker            self.write('concat(%s)' % frame.buffer)
1598*635a8641SAndroid Build Coastguard Worker        self.signature(node, frame)
1599*635a8641SAndroid Build Coastguard Worker        self.write(')')
1600*635a8641SAndroid Build Coastguard Worker        if self.environment.is_async:
1601*635a8641SAndroid Build Coastguard Worker            self.write(')')
1602*635a8641SAndroid Build Coastguard Worker
1603*635a8641SAndroid Build Coastguard Worker    @optimizeconst
1604*635a8641SAndroid Build Coastguard Worker    def visit_Test(self, node, frame):
1605*635a8641SAndroid Build Coastguard Worker        self.write(self.tests[node.name] + '(')
1606*635a8641SAndroid Build Coastguard Worker        if node.name not in self.environment.tests:
1607*635a8641SAndroid Build Coastguard Worker            self.fail('no test named %r' % node.name, node.lineno)
1608*635a8641SAndroid Build Coastguard Worker        self.visit(node.node, frame)
1609*635a8641SAndroid Build Coastguard Worker        self.signature(node, frame)
1610*635a8641SAndroid Build Coastguard Worker        self.write(')')
1611*635a8641SAndroid Build Coastguard Worker
1612*635a8641SAndroid Build Coastguard Worker    @optimizeconst
1613*635a8641SAndroid Build Coastguard Worker    def visit_CondExpr(self, node, frame):
1614*635a8641SAndroid Build Coastguard Worker        def write_expr2():
1615*635a8641SAndroid Build Coastguard Worker            if node.expr2 is not None:
1616*635a8641SAndroid Build Coastguard Worker                return self.visit(node.expr2, frame)
1617*635a8641SAndroid Build Coastguard Worker            self.write('undefined(%r)' % ('the inline if-'
1618*635a8641SAndroid Build Coastguard Worker                       'expression on %s evaluated to false and '
1619*635a8641SAndroid Build Coastguard Worker                       'no else section was defined.' % self.position(node)))
1620*635a8641SAndroid Build Coastguard Worker
1621*635a8641SAndroid Build Coastguard Worker        self.write('(')
1622*635a8641SAndroid Build Coastguard Worker        self.visit(node.expr1, frame)
1623*635a8641SAndroid Build Coastguard Worker        self.write(' if ')
1624*635a8641SAndroid Build Coastguard Worker        self.visit(node.test, frame)
1625*635a8641SAndroid Build Coastguard Worker        self.write(' else ')
1626*635a8641SAndroid Build Coastguard Worker        write_expr2()
1627*635a8641SAndroid Build Coastguard Worker        self.write(')')
1628*635a8641SAndroid Build Coastguard Worker
1629*635a8641SAndroid Build Coastguard Worker    @optimizeconst
1630*635a8641SAndroid Build Coastguard Worker    def visit_Call(self, node, frame, forward_caller=False):
1631*635a8641SAndroid Build Coastguard Worker        if self.environment.is_async:
1632*635a8641SAndroid Build Coastguard Worker            self.write('await auto_await(')
1633*635a8641SAndroid Build Coastguard Worker        if self.environment.sandboxed:
1634*635a8641SAndroid Build Coastguard Worker            self.write('environment.call(context, ')
1635*635a8641SAndroid Build Coastguard Worker        else:
1636*635a8641SAndroid Build Coastguard Worker            self.write('context.call(')
1637*635a8641SAndroid Build Coastguard Worker        self.visit(node.node, frame)
1638*635a8641SAndroid Build Coastguard Worker        extra_kwargs = forward_caller and {'caller': 'caller'} or None
1639*635a8641SAndroid Build Coastguard Worker        self.signature(node, frame, extra_kwargs)
1640*635a8641SAndroid Build Coastguard Worker        self.write(')')
1641*635a8641SAndroid Build Coastguard Worker        if self.environment.is_async:
1642*635a8641SAndroid Build Coastguard Worker            self.write(')')
1643*635a8641SAndroid Build Coastguard Worker
1644*635a8641SAndroid Build Coastguard Worker    def visit_Keyword(self, node, frame):
1645*635a8641SAndroid Build Coastguard Worker        self.write(node.key + '=')
1646*635a8641SAndroid Build Coastguard Worker        self.visit(node.value, frame)
1647*635a8641SAndroid Build Coastguard Worker
1648*635a8641SAndroid Build Coastguard Worker    # -- Unused nodes for extensions
1649*635a8641SAndroid Build Coastguard Worker
1650*635a8641SAndroid Build Coastguard Worker    def visit_MarkSafe(self, node, frame):
1651*635a8641SAndroid Build Coastguard Worker        self.write('Markup(')
1652*635a8641SAndroid Build Coastguard Worker        self.visit(node.expr, frame)
1653*635a8641SAndroid Build Coastguard Worker        self.write(')')
1654*635a8641SAndroid Build Coastguard Worker
1655*635a8641SAndroid Build Coastguard Worker    def visit_MarkSafeIfAutoescape(self, node, frame):
1656*635a8641SAndroid Build Coastguard Worker        self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1657*635a8641SAndroid Build Coastguard Worker        self.visit(node.expr, frame)
1658*635a8641SAndroid Build Coastguard Worker        self.write(')')
1659*635a8641SAndroid Build Coastguard Worker
1660*635a8641SAndroid Build Coastguard Worker    def visit_EnvironmentAttribute(self, node, frame):
1661*635a8641SAndroid Build Coastguard Worker        self.write('environment.' + node.name)
1662*635a8641SAndroid Build Coastguard Worker
1663*635a8641SAndroid Build Coastguard Worker    def visit_ExtensionAttribute(self, node, frame):
1664*635a8641SAndroid Build Coastguard Worker        self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
1665*635a8641SAndroid Build Coastguard Worker
1666*635a8641SAndroid Build Coastguard Worker    def visit_ImportedName(self, node, frame):
1667*635a8641SAndroid Build Coastguard Worker        self.write(self.import_aliases[node.importname])
1668*635a8641SAndroid Build Coastguard Worker
1669*635a8641SAndroid Build Coastguard Worker    def visit_InternalName(self, node, frame):
1670*635a8641SAndroid Build Coastguard Worker        self.write(node.name)
1671*635a8641SAndroid Build Coastguard Worker
1672*635a8641SAndroid Build Coastguard Worker    def visit_ContextReference(self, node, frame):
1673*635a8641SAndroid Build Coastguard Worker        self.write('context')
1674*635a8641SAndroid Build Coastguard Worker
1675*635a8641SAndroid Build Coastguard Worker    def visit_Continue(self, node, frame):
1676*635a8641SAndroid Build Coastguard Worker        self.writeline('continue', node)
1677*635a8641SAndroid Build Coastguard Worker
1678*635a8641SAndroid Build Coastguard Worker    def visit_Break(self, node, frame):
1679*635a8641SAndroid Build Coastguard Worker        self.writeline('break', node)
1680*635a8641SAndroid Build Coastguard Worker
1681*635a8641SAndroid Build Coastguard Worker    def visit_Scope(self, node, frame):
1682*635a8641SAndroid Build Coastguard Worker        scope_frame = frame.inner()
1683*635a8641SAndroid Build Coastguard Worker        scope_frame.symbols.analyze_node(node)
1684*635a8641SAndroid Build Coastguard Worker        self.enter_frame(scope_frame)
1685*635a8641SAndroid Build Coastguard Worker        self.blockvisit(node.body, scope_frame)
1686*635a8641SAndroid Build Coastguard Worker        self.leave_frame(scope_frame)
1687*635a8641SAndroid Build Coastguard Worker
1688*635a8641SAndroid Build Coastguard Worker    def visit_OverlayScope(self, node, frame):
1689*635a8641SAndroid Build Coastguard Worker        ctx = self.temporary_identifier()
1690*635a8641SAndroid Build Coastguard Worker        self.writeline('%s = %s' % (ctx, self.derive_context(frame)))
1691*635a8641SAndroid Build Coastguard Worker        self.writeline('%s.vars = ' % ctx)
1692*635a8641SAndroid Build Coastguard Worker        self.visit(node.context, frame)
1693*635a8641SAndroid Build Coastguard Worker        self.push_context_reference(ctx)
1694*635a8641SAndroid Build Coastguard Worker
1695*635a8641SAndroid Build Coastguard Worker        scope_frame = frame.inner(isolated=True)
1696*635a8641SAndroid Build Coastguard Worker        scope_frame.symbols.analyze_node(node)
1697*635a8641SAndroid Build Coastguard Worker        self.enter_frame(scope_frame)
1698*635a8641SAndroid Build Coastguard Worker        self.blockvisit(node.body, scope_frame)
1699*635a8641SAndroid Build Coastguard Worker        self.leave_frame(scope_frame)
1700*635a8641SAndroid Build Coastguard Worker        self.pop_context_reference()
1701*635a8641SAndroid Build Coastguard Worker
1702*635a8641SAndroid Build Coastguard Worker    def visit_EvalContextModifier(self, node, frame):
1703*635a8641SAndroid Build Coastguard Worker        for keyword in node.options:
1704*635a8641SAndroid Build Coastguard Worker            self.writeline('context.eval_ctx.%s = ' % keyword.key)
1705*635a8641SAndroid Build Coastguard Worker            self.visit(keyword.value, frame)
1706*635a8641SAndroid Build Coastguard Worker            try:
1707*635a8641SAndroid Build Coastguard Worker                val = keyword.value.as_const(frame.eval_ctx)
1708*635a8641SAndroid Build Coastguard Worker            except nodes.Impossible:
1709*635a8641SAndroid Build Coastguard Worker                frame.eval_ctx.volatile = True
1710*635a8641SAndroid Build Coastguard Worker            else:
1711*635a8641SAndroid Build Coastguard Worker                setattr(frame.eval_ctx, keyword.key, val)
1712*635a8641SAndroid Build Coastguard Worker
1713*635a8641SAndroid Build Coastguard Worker    def visit_ScopedEvalContextModifier(self, node, frame):
1714*635a8641SAndroid Build Coastguard Worker        old_ctx_name = self.temporary_identifier()
1715*635a8641SAndroid Build Coastguard Worker        saved_ctx = frame.eval_ctx.save()
1716*635a8641SAndroid Build Coastguard Worker        self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1717*635a8641SAndroid Build Coastguard Worker        self.visit_EvalContextModifier(node, frame)
1718*635a8641SAndroid Build Coastguard Worker        for child in node.body:
1719*635a8641SAndroid Build Coastguard Worker            self.visit(child, frame)
1720*635a8641SAndroid Build Coastguard Worker        frame.eval_ctx.revert(saved_ctx)
1721*635a8641SAndroid Build Coastguard Worker        self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)
1722