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