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