NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

compiler.py (46530B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\jinja2\compiler.py
      2 from cStringIO import StringIO
      3 from itertools import chain
      4 from copy import deepcopy
      5 from jinja2 import nodes
      6 from jinja2.nodes import EvalContext
      7 from jinja2.visitor import NodeVisitor
      8 from jinja2.exceptions import TemplateAssertionError
      9 from jinja2.utils import Markup, concat, escape, is_python_keyword, next
     10 operators = {'eq': '==',
     11  'ne': '!=',
     12  'gt': '>',
     13  'gteq': '>=',
     14  'lt': '<',
     15  'lteq': '<=',
     16  'in': 'in',
     17  'notin': 'not in'}
     18 try:
     19     exec '(0 if 0 else 0)'
     20 except SyntaxError:
     21     have_condexpr = False
     22 else:
     23     have_condexpr = True
     24 
     25 if hasattr(dict, 'iteritems'):
     26     dict_item_iter = 'iteritems'
     27 else:
     28     dict_item_iter = 'items'
     29 
     30 def unoptimize_before_dead_code():
     31     x = 42
     32 
     33     def f():
     34         pass
     35 
     36     return f
     37 
     38 
     39 unoptimize_before_dead_code = bool(unoptimize_before_dead_code().func_closure)
     40 
     41 def generate(node, environment, name, filename, stream = None, defer_init = False):
     42     if not isinstance(node, nodes.Template):
     43         raise TypeError("Can't compile non template nodes")
     44     generator = CodeGenerator(environment, name, filename, stream, defer_init)
     45     generator.visit(node)
     46     if stream is None:
     47         return generator.stream.getvalue()
     48 
     49 
     50 def has_safe_repr(value):
     51     if value is None or value is NotImplemented or value is Ellipsis:
     52         return True
     53     if isinstance(value, (bool,
     54      int,
     55      long,
     56      float,
     57      complex,
     58      basestring,
     59      xrange,
     60      Markup)):
     61         return True
     62     if isinstance(value, (tuple,
     63      list,
     64      set,
     65      frozenset)):
     66         for item in value:
     67             if not has_safe_repr(item):
     68                 return False
     69 
     70         return True
     71     if isinstance(value, dict):
     72         for key, value in value.iteritems():
     73             if not has_safe_repr(key):
     74                 return False
     75             if not has_safe_repr(value):
     76                 return False
     77 
     78         return True
     79     return False
     80 
     81 
     82 def find_undeclared(nodes, names):
     83     visitor = UndeclaredNameVisitor(names)
     84     try:
     85         for node in nodes:
     86             visitor.visit(node)
     87 
     88     except VisitorExit:
     89         pass
     90 
     91     return visitor.undeclared
     92 
     93 
     94 class Identifiers(object):
     95 
     96     def __init__(self):
     97         self.declared = set()
     98         self.outer_undeclared = set()
     99         self.undeclared = set()
    100         self.declared_locally = set()
    101         self.declared_parameter = set()
    102 
    103     def add_special(self, name):
    104         self.undeclared.discard(name)
    105         self.declared.add(name)
    106 
    107     def is_declared(self, name):
    108         if name in self.declared_locally or name in self.declared_parameter:
    109             return True
    110         return name in self.declared
    111 
    112     def copy(self):
    113         return deepcopy(self)
    114 
    115 
    116 class Frame(object):
    117 
    118     def __init__(self, eval_ctx, parent = None):
    119         self.eval_ctx = eval_ctx
    120         self.identifiers = Identifiers()
    121         self.toplevel = False
    122         self.rootlevel = False
    123         self.require_output_check = parent and parent.require_output_check
    124         self.buffer = None
    125         self.block = parent and parent.block or None
    126         self.assigned_names = set()
    127         self.parent = parent
    128         if parent is not None:
    129             self.identifiers.declared.update(parent.identifiers.declared | parent.identifiers.declared_parameter | parent.assigned_names)
    130             self.identifiers.outer_undeclared.update(parent.identifiers.undeclared - self.identifiers.declared)
    131             self.buffer = parent.buffer
    132 
    133     def copy(self):
    134         rv = object.__new__(self.__class__)
    135         rv.__dict__.update(self.__dict__)
    136         rv.identifiers = object.__new__(self.identifiers.__class__)
    137         rv.identifiers.__dict__.update(self.identifiers.__dict__)
    138         return rv
    139 
    140     def inspect(self, nodes):
    141         visitor = FrameIdentifierVisitor(self.identifiers)
    142         for node in nodes:
    143             visitor.visit(node)
    144 
    145     def find_shadowed(self, extra = ()):
    146         i = self.identifiers
    147         return (i.declared | i.outer_undeclared) & (i.declared_locally | i.declared_parameter) | set((x for x in extra if i.is_declared(x)))
    148 
    149     def inner(self):
    150         return Frame(self.eval_ctx, self)
    151 
    152     def soft(self):
    153         rv = self.copy()
    154         rv.rootlevel = False
    155         return rv
    156 
    157     __copy__ = copy
    158 
    159 
    160 class VisitorExit(RuntimeError):
    161     pass
    162 
    163 
    164 class DependencyFinderVisitor(NodeVisitor):
    165 
    166     def __init__(self):
    167         self.filters = set()
    168         self.tests = set()
    169 
    170     def visit_Filter(self, node):
    171         self.generic_visit(node)
    172         self.filters.add(node.name)
    173 
    174     def visit_Test(self, node):
    175         self.generic_visit(node)
    176         self.tests.add(node.name)
    177 
    178     def visit_Block(self, node):
    179         pass
    180 
    181 
    182 class UndeclaredNameVisitor(NodeVisitor):
    183 
    184     def __init__(self, names):
    185         self.names = set(names)
    186         self.undeclared = set()
    187 
    188     def visit_Name(self, node):
    189         if node.ctx == 'load' and node.name in self.names:
    190             self.undeclared.add(node.name)
    191             if self.undeclared == self.names:
    192                 raise VisitorExit()
    193         else:
    194             self.names.discard(node.name)
    195 
    196     def visit_Block(self, node):
    197         pass
    198 
    199 
    200 class FrameIdentifierVisitor(NodeVisitor):
    201 
    202     def __init__(self, identifiers):
    203         self.identifiers = identifiers
    204 
    205     def visit_Name(self, node):
    206         if node.ctx == 'store':
    207             self.identifiers.declared_locally.add(node.name)
    208         elif node.ctx == 'param':
    209             self.identifiers.declared_parameter.add(node.name)
    210         elif node.ctx == 'load' and not self.identifiers.is_declared(node.name):
    211             self.identifiers.undeclared.add(node.name)
    212 
    213     def visit_If(self, node):
    214         self.visit(node.test)
    215         real_identifiers = self.identifiers
    216         old_names = real_identifiers.declared_locally | real_identifiers.declared_parameter
    217 
    218         def inner_visit(nodes):
    219             if not nodes:
    220                 return set()
    221             self.identifiers = real_identifiers.copy()
    222             for subnode in nodes:
    223                 self.visit(subnode)
    224 
    225             rv = self.identifiers.declared_locally - old_names
    226             real_identifiers.undeclared.update(self.identifiers.undeclared)
    227             self.identifiers = real_identifiers
    228             return rv
    229 
    230         body = inner_visit(node.body)
    231         else_ = inner_visit(node.else_ or ())
    232         real_identifiers.undeclared.update(body.symmetric_difference(else_) - real_identifiers.declared)
    233         real_identifiers.declared_locally.update(body | else_)
    234 
    235     def visit_Macro(self, node):
    236         self.identifiers.declared_locally.add(node.name)
    237 
    238     def visit_Import(self, node):
    239         self.generic_visit(node)
    240         self.identifiers.declared_locally.add(node.target)
    241 
    242     def visit_FromImport(self, node):
    243         self.generic_visit(node)
    244         for name in node.names:
    245             if isinstance(name, tuple):
    246                 self.identifiers.declared_locally.add(name[1])
    247             else:
    248                 self.identifiers.declared_locally.add(name)
    249 
    250     def visit_Assign(self, node):
    251         self.visit(node.node)
    252         self.visit(node.target)
    253 
    254     def visit_For(self, node):
    255         self.visit(node.iter)
    256 
    257     def visit_CallBlock(self, node):
    258         self.visit(node.call)
    259 
    260     def visit_FilterBlock(self, node):
    261         self.visit(node.filter)
    262 
    263     def visit_Scope(self, node):
    264         pass
    265 
    266     def visit_Block(self, node):
    267         pass
    268 
    269 
    270 class CompilerExit(Exception):
    271     pass
    272 
    273 
    274 class CodeGenerator(NodeVisitor):
    275 
    276     def __init__(self, environment, name, filename, stream = None, defer_init = False):
    277         if stream is None:
    278             stream = StringIO()
    279         self.environment = environment
    280         self.name = name
    281         self.filename = filename
    282         self.stream = stream
    283         self.created_block_context = False
    284         self.defer_init = defer_init
    285         self.import_aliases = {}
    286         self.blocks = {}
    287         self.extends_so_far = 0
    288         self.has_known_extends = False
    289         self.code_lineno = 1
    290         self.tests = {}
    291         self.filters = {}
    292         self.debug_info = []
    293         self._write_debug_info = None
    294         self._new_lines = 0
    295         self._last_line = 0
    296         self._first_write = True
    297         self._last_identifier = 0
    298         self._indentation = 0
    299 
    300     def fail(self, msg, lineno):
    301         raise TemplateAssertionError(msg, lineno, self.name, self.filename)
    302 
    303     def temporary_identifier(self):
    304         self._last_identifier += 1
    305         return 't_%d' % self._last_identifier
    306 
    307     def buffer(self, frame):
    308         frame.buffer = self.temporary_identifier()
    309         self.writeline('%s = []' % frame.buffer)
    310 
    311     def return_buffer_contents(self, frame):
    312         if frame.eval_ctx.volatile:
    313             self.writeline('if context.eval_ctx.autoescape:')
    314             self.indent()
    315             self.writeline('return Markup(concat(%s))' % frame.buffer)
    316             self.outdent()
    317             self.writeline('else:')
    318             self.indent()
    319             self.writeline('return concat(%s)' % frame.buffer)
    320             self.outdent()
    321         elif frame.eval_ctx.autoescape:
    322             self.writeline('return Markup(concat(%s))' % frame.buffer)
    323         else:
    324             self.writeline('return concat(%s)' % frame.buffer)
    325 
    326     def indent(self):
    327         self._indentation += 1
    328 
    329     def outdent(self, step = 1):
    330         self._indentation -= step
    331 
    332     def start_write(self, frame, node = None):
    333         if frame.buffer is None:
    334             self.writeline('yield ', node)
    335         else:
    336             self.writeline('%s.append(' % frame.buffer, node)
    337 
    338     def end_write(self, frame):
    339         if frame.buffer is not None:
    340             self.write(')')
    341 
    342     def simple_write(self, s, frame, node = None):
    343         self.start_write(frame, node)
    344         self.write(s)
    345         self.end_write(frame)
    346 
    347     def blockvisit(self, nodes, frame):
    348         if frame.buffer is None:
    349             self.writeline('if 0: yield None')
    350         else:
    351             self.writeline('pass')
    352         try:
    353             for node in nodes:
    354                 self.visit(node, frame)
    355 
    356         except CompilerExit:
    357             pass
    358 
    359     def write(self, x):
    360         if self._new_lines:
    361             if not self._first_write:
    362                 self.stream.write('\n' * self._new_lines)
    363                 self.code_lineno += self._new_lines
    364                 if self._write_debug_info is not None:
    365                     self.debug_info.append((self._write_debug_info, self.code_lineno))
    366                     self._write_debug_info = None
    367             self._first_write = False
    368             self.stream.write('    ' * self._indentation)
    369             self._new_lines = 0
    370         self.stream.write(x)
    371 
    372     def writeline(self, x, node = None, extra = 0):
    373         self.newline(node, extra)
    374         self.write(x)
    375 
    376     def newline(self, node = None, extra = 0):
    377         self._new_lines = max(self._new_lines, 1 + extra)
    378         if node is not None and node.lineno != self._last_line:
    379             self._write_debug_info = node.lineno
    380             self._last_line = node.lineno
    381 
    382     def signature(self, node, frame, extra_kwargs = None):
    383         kwarg_workaround = False
    384         for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
    385             if is_python_keyword(kwarg):
    386                 kwarg_workaround = True
    387                 break
    388 
    389         for arg in node.args:
    390             self.write(', ')
    391             self.visit(arg, frame)
    392 
    393         if not kwarg_workaround:
    394             for kwarg in node.kwargs:
    395                 self.write(', ')
    396                 self.visit(kwarg, frame)
    397 
    398             if extra_kwargs is not None:
    399                 for key, value in extra_kwargs.iteritems():
    400                     self.write(', %s=%s' % (key, value))
    401 
    402         if node.dyn_args:
    403             self.write(', *')
    404             self.visit(node.dyn_args, frame)
    405         if kwarg_workaround:
    406             if node.dyn_kwargs is not None:
    407                 self.write(', **dict({')
    408             else:
    409                 self.write(', **{')
    410             for kwarg in node.kwargs:
    411                 self.write('%r: ' % kwarg.key)
    412                 self.visit(kwarg.value, frame)
    413                 self.write(', ')
    414 
    415             if extra_kwargs is not None:
    416                 for key, value in extra_kwargs.iteritems():
    417                     self.write('%r: %s, ' % (key, value))
    418 
    419             if node.dyn_kwargs is not None:
    420                 self.write('}, **')
    421                 self.visit(node.dyn_kwargs, frame)
    422                 self.write(')')
    423             else:
    424                 self.write('}')
    425         elif node.dyn_kwargs is not None:
    426             self.write(', **')
    427             self.visit(node.dyn_kwargs, frame)
    428 
    429     def pull_locals(self, frame):
    430         for name in frame.identifiers.undeclared:
    431             self.writeline('l_%s = context.resolve(%r)' % (name, name))
    432 
    433     def pull_dependencies(self, nodes):
    434         visitor = DependencyFinderVisitor()
    435         for node in nodes:
    436             visitor.visit(node)
    437 
    438         for dependency in ('filters', 'tests'):
    439             mapping = getattr(self, dependency)
    440             for name in getattr(visitor, dependency):
    441                 if name not in mapping:
    442                     mapping[name] = self.temporary_identifier()
    443                 self.writeline('%s = environment.%s[%r]' % (mapping[name], dependency, name))
    444 
    445     def unoptimize_scope(self, frame):
    446         if frame.identifiers.declared:
    447             self.writeline('%sdummy(%s)' % (unoptimize_before_dead_code and 'if 0: ' or '', ', '.join(('l_' + name for name in frame.identifiers.declared))))
    448 
    449     def push_scope(self, frame, extra_vars = ()):
    450         aliases = {}
    451         for name in frame.find_shadowed(extra_vars):
    452             aliases[name] = ident = self.temporary_identifier()
    453             self.writeline('%s = l_%s' % (ident, name))
    454 
    455         to_declare = set()
    456         for name in frame.identifiers.declared_locally:
    457             if name not in aliases:
    458                 to_declare.add('l_' + name)
    459 
    460         if to_declare:
    461             self.writeline(' = '.join(to_declare) + ' = missing')
    462         return aliases
    463 
    464     def pop_scope(self, aliases, frame):
    465         for name, alias in aliases.iteritems():
    466             self.writeline('l_%s = %s' % (name, alias))
    467 
    468         to_delete = set()
    469         for name in frame.identifiers.declared_locally:
    470             if name not in aliases:
    471                 to_delete.add('l_' + name)
    472 
    473         if to_delete:
    474             self.writeline(' = '.join(to_delete) + ' = missing')
    475 
    476     def function_scoping(self, node, frame, children = None, find_special = True):
    477         if children is None:
    478             children = node.iter_child_nodes()
    479         children = list(children)
    480         func_frame = frame.inner()
    481         func_frame.inspect(children)
    482         overriden_closure_vars = func_frame.identifiers.undeclared & func_frame.identifiers.declared & (func_frame.identifiers.declared_locally | func_frame.identifiers.declared_parameter)
    483         if overriden_closure_vars:
    484             self.fail("It's not possible to set and access variables derived from an outer scope! (affects: %s)" % ', '.join(sorted(overriden_closure_vars)), node.lineno)
    485         func_frame.identifiers.undeclared -= func_frame.identifiers.undeclared & func_frame.identifiers.declared
    486         if not find_special:
    487             return func_frame
    488         func_frame.accesses_kwargs = False
    489         func_frame.accesses_varargs = False
    490         func_frame.accesses_caller = False
    491         func_frame.arguments = args = [ 'l_' + x.name for x in node.args ]
    492         undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
    493         if 'caller' in undeclared:
    494             func_frame.accesses_caller = True
    495             func_frame.identifiers.add_special('caller')
    496             args.append('l_caller')
    497         if 'kwargs' in undeclared:
    498             func_frame.accesses_kwargs = True
    499             func_frame.identifiers.add_special('kwargs')
    500             args.append('l_kwargs')
    501         if 'varargs' in undeclared:
    502             func_frame.accesses_varargs = True
    503             func_frame.identifiers.add_special('varargs')
    504             args.append('l_varargs')
    505         return func_frame
    506 
    507     def macro_body(self, node, frame, children = None):
    508         frame = self.function_scoping(node, frame, children)
    509         frame.require_output_check = False
    510         args = frame.arguments
    511         if 'loop' in frame.identifiers.declared:
    512             args = args + ['l_loop=l_loop']
    513         self.writeline('def macro(%s):' % ', '.join(args), node)
    514         self.indent()
    515         self.buffer(frame)
    516         self.pull_locals(frame)
    517         self.blockvisit(node.body, frame)
    518         self.return_buffer_contents(frame)
    519         self.outdent()
    520         return frame
    521 
    522     def macro_def(self, node, frame):
    523         arg_tuple = ', '.join((repr(x.name) for x in node.args))
    524         name = getattr(node, 'name', None)
    525         if len(node.args) == 1:
    526             arg_tuple += ','
    527         self.write('Macro(environment, macro, %r, (%s), (' % (name, arg_tuple))
    528         for arg in node.defaults:
    529             self.visit(arg, frame)
    530             self.write(', ')
    531 
    532         self.write('), %r, %r, %r)' % (bool(frame.accesses_kwargs), bool(frame.accesses_varargs), bool(frame.accesses_caller)))
    533 
    534     def position(self, node):
    535         rv = 'line %d' % node.lineno
    536         if self.name is not None:
    537             rv += ' in ' + repr(self.name)
    538         return rv
    539 
    540     def visit_Template(self, node, frame = None):
    541         eval_ctx = EvalContext(self.environment, self.name)
    542         from jinja2.runtime import __all__ as exported
    543         self.writeline('from __future__ import division')
    544         self.writeline('from jinja2.runtime import ' + ', '.join(exported))
    545         if not unoptimize_before_dead_code:
    546             self.writeline('dummy = lambda *x: None')
    547         envenv = not self.defer_init and ', environment=environment' or ''
    548         have_extends = node.find(nodes.Extends) is not None
    549         for block in node.find_all(nodes.Block):
    550             if block.name in self.blocks:
    551                 self.fail('block %r defined twice' % block.name, block.lineno)
    552             self.blocks[block.name] = block
    553 
    554         for import_ in node.find_all(nodes.ImportedName):
    555             if import_.importname not in self.import_aliases:
    556                 imp = import_.importname
    557                 self.import_aliases[imp] = alias = self.temporary_identifier()
    558                 if '.' in imp:
    559                     module, obj = imp.rsplit('.', 1)
    560                     self.writeline('from %s import %s as %s' % (module, obj, alias))
    561                 else:
    562                     self.writeline('import %s as %s' % (imp, alias))
    563 
    564         self.writeline('name = %r' % self.name)
    565         self.writeline('def root(context%s):' % envenv, extra=1)
    566         frame = Frame(eval_ctx)
    567         frame.inspect(node.body)
    568         frame.toplevel = frame.rootlevel = True
    569         frame.require_output_check = have_extends and not self.has_known_extends
    570         self.indent()
    571         if have_extends:
    572             self.writeline('parent_template = None')
    573         if 'self' in find_undeclared(node.body, ('self',)):
    574             frame.identifiers.add_special('self')
    575             self.writeline('l_self = TemplateReference(context)')
    576         self.pull_locals(frame)
    577         self.pull_dependencies(node.body)
    578         self.blockvisit(node.body, frame)
    579         self.outdent()
    580         if have_extends:
    581             if not self.has_known_extends:
    582                 self.indent()
    583                 self.writeline('if parent_template is not None:')
    584             self.indent()
    585             self.writeline('for event in parent_template.root_render_func(context):')
    586             self.indent()
    587             self.writeline('yield event')
    588             self.outdent(2 + (not self.has_known_extends))
    589         for name, block in self.blocks.iteritems():
    590             block_frame = Frame(eval_ctx)
    591             block_frame.inspect(block.body)
    592             block_frame.block = name
    593             self.writeline('def block_%s(context%s):' % (name, envenv), block, 1)
    594             self.indent()
    595             undeclared = find_undeclared(block.body, ('self', 'super'))
    596             if 'self' in undeclared:
    597                 block_frame.identifiers.add_special('self')
    598                 self.writeline('l_self = TemplateReference(context)')
    599             if 'super' in undeclared:
    600                 block_frame.identifiers.add_special('super')
    601                 self.writeline('l_super = context.super(%r, block_%s)' % (name, name))
    602             self.pull_locals(block_frame)
    603             self.pull_dependencies(block.body)
    604             self.blockvisit(block.body, block_frame)
    605             self.outdent()
    606 
    607         self.writeline('blocks = {%s}' % ', '.join(('%r: block_%s' % (x, x) for x in self.blocks)), extra=1)
    608         self.writeline('debug_info = %r' % '&'.join(('%s=%s' % x for x in self.debug_info)))
    609 
    610     def visit_Block(self, node, frame):
    611         level = 1
    612         if frame.toplevel:
    613             if self.has_known_extends:
    614                 return
    615             if self.extends_so_far > 0:
    616                 self.writeline('if parent_template is None:')
    617                 self.indent()
    618                 level += 1
    619         context = node.scoped and 'context.derived(locals())' or 'context'
    620         self.writeline('for event in context.blocks[%r][0](%s):' % (node.name, context), node)
    621         self.indent()
    622         self.simple_write('event', frame)
    623         self.outdent(level)
    624 
    625     def visit_Extends(self, node, frame):
    626         if not frame.toplevel:
    627             self.fail('cannot use extend from a non top-level scope', node.lineno)
    628         if self.extends_so_far > 0:
    629             if not self.has_known_extends:
    630                 self.writeline('if parent_template is not None:')
    631                 self.indent()
    632             self.writeline('raise TemplateRuntimeError(%r)' % 'extended multiple times')
    633             self.outdent()
    634             if self.has_known_extends:
    635                 raise CompilerExit()
    636         self.writeline('parent_template = environment.get_template(', node)
    637         self.visit(node.template, frame)
    638         self.write(', %r)' % self.name)
    639         self.writeline('for name, parent_block in parent_template.blocks.%s():' % dict_item_iter)
    640         self.indent()
    641         self.writeline('context.blocks.setdefault(name, []).append(parent_block)')
    642         self.outdent()
    643         if frame.rootlevel:
    644             self.has_known_extends = True
    645         self.extends_so_far += 1
    646 
    647     def visit_Include(self, node, frame):
    648         if node.with_context:
    649             self.unoptimize_scope(frame)
    650         if node.ignore_missing:
    651             self.writeline('try:')
    652             self.indent()
    653         func_name = 'get_or_select_template'
    654         if isinstance(node.template, nodes.Const):
    655             if isinstance(node.template.value, basestring):
    656                 func_name = 'get_template'
    657             elif isinstance(node.template.value, (tuple, list)):
    658                 func_name = 'select_template'
    659         elif isinstance(node.template, (nodes.Tuple, nodes.List)):
    660             func_name = 'select_template'
    661         self.writeline('template = environment.%s(' % func_name, node)
    662         self.visit(node.template, frame)
    663         self.write(', %r)' % self.name)
    664         if node.ignore_missing:
    665             self.outdent()
    666             self.writeline('except TemplateNotFound:')
    667             self.indent()
    668             self.writeline('pass')
    669             self.outdent()
    670             self.writeline('else:')
    671             self.indent()
    672         if node.with_context:
    673             self.writeline('for event in template.root_render_func(template.new_context(context.parent, True, locals())):')
    674         else:
    675             self.writeline('for event in template.module._body_stream:')
    676         self.indent()
    677         self.simple_write('event', frame)
    678         self.outdent()
    679         if node.ignore_missing:
    680             self.outdent()
    681 
    682     def visit_Import(self, node, frame):
    683         if node.with_context:
    684             self.unoptimize_scope(frame)
    685         self.writeline('l_%s = ' % node.target, node)
    686         if frame.toplevel:
    687             self.write('context.vars[%r] = ' % node.target)
    688         self.write('environment.get_template(')
    689         self.visit(node.template, frame)
    690         self.write(', %r).' % self.name)
    691         if node.with_context:
    692             self.write('make_module(context.parent, True, locals())')
    693         else:
    694             self.write('module')
    695         if frame.toplevel and not node.target.startswith('_'):
    696             self.writeline('context.exported_vars.discard(%r)' % node.target)
    697         frame.assigned_names.add(node.target)
    698 
    699     def visit_FromImport(self, node, frame):
    700         self.newline(node)
    701         self.write('included_template = environment.get_template(')
    702         self.visit(node.template, frame)
    703         self.write(', %r).' % self.name)
    704         if node.with_context:
    705             self.write('make_module(context.parent, True)')
    706         else:
    707             self.write('module')
    708         var_names = []
    709         discarded_names = []
    710         for name in node.names:
    711             if isinstance(name, tuple):
    712                 name, alias = name
    713             else:
    714                 alias = name
    715             self.writeline('l_%s = getattr(included_template, %r, missing)' % (alias, name))
    716             self.writeline('if l_%s is missing:' % alias)
    717             self.indent()
    718             self.writeline('l_%s = environment.undefined(%r %% included_template.__name__, name=%r)' % (alias, 'the template %%r (imported on %s) does not export the requested name %s' % (self.position(node), repr(name)), name))
    719             self.outdent()
    720             if frame.toplevel:
    721                 var_names.append(alias)
    722                 if not alias.startswith('_'):
    723                     discarded_names.append(alias)
    724             frame.assigned_names.add(alias)
    725 
    726         if var_names:
    727             if len(var_names) == 1:
    728                 name = var_names[0]
    729                 self.writeline('context.vars[%r] = l_%s' % (name, name))
    730             else:
    731                 self.writeline('context.vars.update({%s})' % ', '.join(('%r: l_%s' % (name, name) for name in var_names)))
    732         if discarded_names:
    733             if len(discarded_names) == 1:
    734                 self.writeline('context.exported_vars.discard(%r)' % discarded_names[0])
    735             else:
    736                 self.writeline('context.exported_vars.difference_update((%s))' % ', '.join(map(repr, discarded_names)))
    737 
    738     def visit_For(self, node, frame):
    739         children = node.iter_child_nodes(exclude=('iter',))
    740         if node.recursive:
    741             loop_frame = self.function_scoping(node, frame, children, find_special=False)
    742         else:
    743             loop_frame = frame.inner()
    744             loop_frame.inspect(children)
    745         extended_loop = node.recursive or 'loop' in find_undeclared(node.iter_child_nodes(only=('body',)), ('loop',))
    746         if not node.recursive:
    747             aliases = self.push_scope(loop_frame, ('loop',))
    748         else:
    749             self.writeline('def loop(reciter, loop_render_func):', node)
    750             self.indent()
    751             self.buffer(loop_frame)
    752             aliases = {}
    753         if extended_loop:
    754             loop_frame.identifiers.add_special('loop')
    755         for name in node.find_all(nodes.Name):
    756             if name.ctx == 'store' and name.name == 'loop':
    757                 self.fail("Can't assign to special loop variable in for-loop target", name.lineno)
    758 
    759         self.pull_locals(loop_frame)
    760         if node.else_:
    761             iteration_indicator = self.temporary_identifier()
    762             self.writeline('%s = 1' % iteration_indicator)
    763         if 'loop' not in aliases and 'loop' in find_undeclared(node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
    764             self.writeline("l_loop = environment.undefined(%r, name='loop')" % ("'loop' is undefined. the filter section of a loop as well as the else block don't have access to the special 'loop' variable of the current loop.  Because there is no parent loop it's undefined.  Happened in loop on %s" % self.position(node)))
    765         self.writeline('for ', node)
    766         self.visit(node.target, loop_frame)
    767         self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
    768         if extended_loop and node.test is not None:
    769             self.write('(')
    770             self.visit(node.target, loop_frame)
    771             self.write(' for ')
    772             self.visit(node.target, loop_frame)
    773             self.write(' in ')
    774             if node.recursive:
    775                 self.write('reciter')
    776             else:
    777                 self.visit(node.iter, loop_frame)
    778             self.write(' if (')
    779             test_frame = loop_frame.copy()
    780             self.visit(node.test, test_frame)
    781             self.write('))')
    782         elif node.recursive:
    783             self.write('reciter')
    784         else:
    785             self.visit(node.iter, loop_frame)
    786         if node.recursive:
    787             self.write(', recurse=loop_render_func):')
    788         else:
    789             self.write(extended_loop and '):' or ':')
    790         if not extended_loop and node.test is not None:
    791             self.indent()
    792             self.writeline('if not ')
    793             self.visit(node.test, loop_frame)
    794             self.write(':')
    795             self.indent()
    796             self.writeline('continue')
    797             self.outdent(2)
    798         self.indent()
    799         self.blockvisit(node.body, loop_frame)
    800         if node.else_:
    801             self.writeline('%s = 0' % iteration_indicator)
    802         self.outdent()
    803         if node.else_:
    804             self.writeline('if %s:' % iteration_indicator)
    805             self.indent()
    806             self.blockvisit(node.else_, loop_frame)
    807             self.outdent()
    808         if not node.recursive:
    809             self.pop_scope(aliases, loop_frame)
    810         if node.recursive:
    811             self.return_buffer_contents(loop_frame)
    812             self.outdent()
    813             self.start_write(frame, node)
    814             self.write('loop(')
    815             self.visit(node.iter, frame)
    816             self.write(', loop)')
    817             self.end_write(frame)
    818 
    819     def visit_If(self, node, frame):
    820         if_frame = frame.soft()
    821         self.writeline('if ', node)
    822         self.visit(node.test, if_frame)
    823         self.write(':')
    824         self.indent()
    825         self.blockvisit(node.body, if_frame)
    826         self.outdent()
    827         if node.else_:
    828             self.writeline('else:')
    829             self.indent()
    830             self.blockvisit(node.else_, if_frame)
    831             self.outdent()
    832 
    833     def visit_Macro(self, node, frame):
    834         macro_frame = self.macro_body(node, frame)
    835         self.newline()
    836         if frame.toplevel:
    837             if not node.name.startswith('_'):
    838                 self.write('context.exported_vars.add(%r)' % node.name)
    839             self.writeline('context.vars[%r] = ' % node.name)
    840         self.write('l_%s = ' % node.name)
    841         self.macro_def(node, macro_frame)
    842         frame.assigned_names.add(node.name)
    843 
    844     def visit_CallBlock(self, node, frame):
    845         children = node.iter_child_nodes(exclude=('call',))
    846         call_frame = self.macro_body(node, frame, children)
    847         self.writeline('caller = ')
    848         self.macro_def(node, call_frame)
    849         self.start_write(frame, node)
    850         self.visit_Call(node.call, call_frame, forward_caller=True)
    851         self.end_write(frame)
    852 
    853     def visit_FilterBlock(self, node, frame):
    854         filter_frame = frame.inner()
    855         filter_frame.inspect(node.iter_child_nodes())
    856         aliases = self.push_scope(filter_frame)
    857         self.pull_locals(filter_frame)
    858         self.buffer(filter_frame)
    859         self.blockvisit(node.body, filter_frame)
    860         self.start_write(frame, node)
    861         self.visit_Filter(node.filter, filter_frame)
    862         self.end_write(frame)
    863         self.pop_scope(aliases, filter_frame)
    864 
    865     def visit_ExprStmt(self, node, frame):
    866         self.newline(node)
    867         self.visit(node.node, frame)
    868 
    869     def visit_Output(self, node, frame):
    870         if self.has_known_extends and frame.require_output_check:
    871             return
    872         if self.environment.finalize:
    873             finalize = lambda x: unicode(self.environment.finalize(x))
    874         else:
    875             finalize = unicode
    876         outdent_later = False
    877         if frame.require_output_check:
    878             self.writeline('if parent_template is None:')
    879             self.indent()
    880             outdent_later = True
    881         body = []
    882         for child in node.nodes:
    883             try:
    884                 const = child.as_const(frame.eval_ctx)
    885             except nodes.Impossible:
    886                 body.append(child)
    887                 continue
    888 
    889             try:
    890                 if frame.eval_ctx.autoescape:
    891                     if hasattr(const, '__html__'):
    892                         const = const.__html__()
    893                     else:
    894                         const = escape(const)
    895                 const = finalize(const)
    896             except Exception:
    897                 body.append(child)
    898                 continue
    899 
    900             if body and isinstance(body[-1], list):
    901                 body[-1].append(const)
    902             else:
    903                 body.append([const])
    904 
    905         if len(body) < 3 or frame.buffer is not None:
    906             if frame.buffer is not None:
    907                 if len(body) == 1:
    908                     self.writeline('%s.append(' % frame.buffer)
    909                 else:
    910                     self.writeline('%s.extend((' % frame.buffer)
    911                 self.indent()
    912             for item in body:
    913                 if isinstance(item, list):
    914                     val = repr(concat(item))
    915                     if frame.buffer is None:
    916                         self.writeline('yield ' + val)
    917                     else:
    918                         self.writeline(val + ', ')
    919                 else:
    920                     if frame.buffer is None:
    921                         self.writeline('yield ', item)
    922                     else:
    923                         self.newline(item)
    924                     close = 1
    925                     if frame.eval_ctx.volatile:
    926                         self.write('(context.eval_ctx.autoescape and escape or to_string)(')
    927                     elif frame.eval_ctx.autoescape:
    928                         self.write('escape(')
    929                     else:
    930                         self.write('to_string(')
    931                     if self.environment.finalize is not None:
    932                         self.write('environment.finalize(')
    933                         close += 1
    934                     self.visit(item, frame)
    935                     self.write(')' * close)
    936                     if frame.buffer is not None:
    937                         self.write(', ')
    938 
    939             if frame.buffer is not None:
    940                 self.outdent()
    941                 self.writeline(len(body) == 1 and ')' or '))')
    942         else:
    943             format = []
    944             arguments = []
    945             for item in body:
    946                 if isinstance(item, list):
    947                     format.append(concat(item).replace('%', '%%'))
    948                 else:
    949                     format.append('%s')
    950                     arguments.append(item)
    951 
    952             self.writeline('yield ')
    953             self.write(repr(concat(format)) + ' % (')
    954             idx = -1
    955             self.indent()
    956             for argument in arguments:
    957                 self.newline(argument)
    958                 close = 0
    959                 if frame.eval_ctx.volatile:
    960                     self.write('(context.eval_ctx.autoescape and escape or to_string)(')
    961                     close += 1
    962                 elif frame.eval_ctx.autoescape:
    963                     self.write('escape(')
    964                     close += 1
    965                 if self.environment.finalize is not None:
    966                     self.write('environment.finalize(')
    967                     close += 1
    968                 self.visit(argument, frame)
    969                 self.write(')' * close + ', ')
    970 
    971             self.outdent()
    972             self.writeline(')')
    973         if outdent_later:
    974             self.outdent()
    975 
    976     def visit_Assign(self, node, frame):
    977         self.newline(node)
    978         if frame.toplevel:
    979             assignment_frame = frame.copy()
    980             assignment_frame.toplevel_assignments = set()
    981         else:
    982             assignment_frame = frame
    983         self.visit(node.target, assignment_frame)
    984         self.write(' = ')
    985         self.visit(node.node, frame)
    986         if frame.toplevel:
    987             public_names = [ x for x in assignment_frame.toplevel_assignments if not x.startswith('_') ]
    988             if len(assignment_frame.toplevel_assignments) == 1:
    989                 name = next(iter(assignment_frame.toplevel_assignments))
    990                 self.writeline('context.vars[%r] = l_%s' % (name, name))
    991             else:
    992                 self.writeline('context.vars.update({')
    993                 for idx, name in enumerate(assignment_frame.toplevel_assignments):
    994                     if idx:
    995                         self.write(', ')
    996                     self.write('%r: l_%s' % (name, name))
    997 
    998                 self.write('})')
    999             if public_names:
   1000                 if len(public_names) == 1:
   1001                     self.writeline('context.exported_vars.add(%r)' % public_names[0])
   1002                 else:
   1003                     self.writeline('context.exported_vars.update((%s))' % ', '.join(map(repr, public_names)))
   1004 
   1005     def visit_Name(self, node, frame):
   1006         if node.ctx == 'store' and frame.toplevel:
   1007             frame.toplevel_assignments.add(node.name)
   1008         self.write('l_' + node.name)
   1009         frame.assigned_names.add(node.name)
   1010 
   1011     def visit_Const(self, node, frame):
   1012         val = node.value
   1013         if isinstance(val, float):
   1014             self.write(str(val))
   1015         else:
   1016             self.write(repr(val))
   1017 
   1018     def visit_TemplateData(self, node, frame):
   1019         try:
   1020             self.write(repr(node.as_const(frame.eval_ctx)))
   1021         except nodes.Impossible:
   1022             self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)' % node.data)
   1023 
   1024     def visit_Tuple(self, node, frame):
   1025         self.write('(')
   1026         idx = -1
   1027         for idx, item in enumerate(node.items):
   1028             if idx:
   1029                 self.write(', ')
   1030             self.visit(item, frame)
   1031 
   1032         self.write(idx == 0 and ',)' or ')')
   1033 
   1034     def visit_List(self, node, frame):
   1035         self.write('[')
   1036         for idx, item in enumerate(node.items):
   1037             if idx:
   1038                 self.write(', ')
   1039             self.visit(item, frame)
   1040 
   1041         self.write(']')
   1042 
   1043     def visit_Dict(self, node, frame):
   1044         self.write('{')
   1045         for idx, item in enumerate(node.items):
   1046             if idx:
   1047                 self.write(', ')
   1048             self.visit(item.key, frame)
   1049             self.write(': ')
   1050             self.visit(item.value, frame)
   1051 
   1052         self.write('}')
   1053 
   1054     def binop(operator, interceptable = True):
   1055 
   1056         def visitor(self, node, frame):
   1057             if self.environment.sandboxed and operator in self.environment.intercepted_binops:
   1058                 self.write('environment.call_binop(context, %r, ' % operator)
   1059                 self.visit(node.left, frame)
   1060                 self.write(', ')
   1061                 self.visit(node.right, frame)
   1062             else:
   1063                 self.write('(')
   1064                 self.visit(node.left, frame)
   1065                 self.write(' %s ' % operator)
   1066                 self.visit(node.right, frame)
   1067             self.write(')')
   1068 
   1069         return visitor
   1070 
   1071     def uaop(operator, interceptable = True):
   1072 
   1073         def visitor(self, node, frame):
   1074             if self.environment.sandboxed and operator in self.environment.intercepted_unops:
   1075                 self.write('environment.call_unop(context, %r, ' % operator)
   1076                 self.visit(node.node, frame)
   1077             else:
   1078                 self.write('(' + operator)
   1079                 self.visit(node.node, frame)
   1080             self.write(')')
   1081 
   1082         return visitor
   1083 
   1084     visit_Add = binop('+')
   1085     visit_Sub = binop('-')
   1086     visit_Mul = binop('*')
   1087     visit_Div = binop('/')
   1088     visit_FloorDiv = binop('//')
   1089     visit_Pow = binop('**')
   1090     visit_Mod = binop('%')
   1091     visit_And = binop('and', interceptable=False)
   1092     visit_Or = binop('or', interceptable=False)
   1093     visit_Pos = uaop('+')
   1094     visit_Neg = uaop('-')
   1095     visit_Not = uaop('not ', interceptable=False)
   1096     del binop
   1097     del uaop
   1098 
   1099     def visit_Concat(self, node, frame):
   1100         if frame.eval_ctx.volatile:
   1101             func_name = '(context.eval_ctx.volatile and markup_join or unicode_join)'
   1102         elif frame.eval_ctx.autoescape:
   1103             func_name = 'markup_join'
   1104         else:
   1105             func_name = 'unicode_join'
   1106         self.write('%s((' % func_name)
   1107         for arg in node.nodes:
   1108             self.visit(arg, frame)
   1109             self.write(', ')
   1110 
   1111         self.write('))')
   1112 
   1113     def visit_Compare(self, node, frame):
   1114         self.visit(node.expr, frame)
   1115         for op in node.ops:
   1116             self.visit(op, frame)
   1117 
   1118     def visit_Operand(self, node, frame):
   1119         self.write(' %s ' % operators[node.op])
   1120         self.visit(node.expr, frame)
   1121 
   1122     def visit_Getattr(self, node, frame):
   1123         self.write('environment.getattr(')
   1124         self.visit(node.node, frame)
   1125         self.write(', %r)' % node.attr)
   1126 
   1127     def visit_Getitem(self, node, frame):
   1128         if isinstance(node.arg, nodes.Slice):
   1129             self.visit(node.node, frame)
   1130             self.write('[')
   1131             self.visit(node.arg, frame)
   1132             self.write(']')
   1133         else:
   1134             self.write('environment.getitem(')
   1135             self.visit(node.node, frame)
   1136             self.write(', ')
   1137             self.visit(node.arg, frame)
   1138             self.write(')')
   1139 
   1140     def visit_Slice(self, node, frame):
   1141         if node.start is not None:
   1142             self.visit(node.start, frame)
   1143         self.write(':')
   1144         if node.stop is not None:
   1145             self.visit(node.stop, frame)
   1146         if node.step is not None:
   1147             self.write(':')
   1148             self.visit(node.step, frame)
   1149 
   1150     def visit_Filter(self, node, frame):
   1151         self.write(self.filters[node.name] + '(')
   1152         func = self.environment.filters.get(node.name)
   1153         if func is None:
   1154             self.fail('no filter named %r' % node.name, node.lineno)
   1155         if getattr(func, 'contextfilter', False):
   1156             self.write('context, ')
   1157         elif getattr(func, 'evalcontextfilter', False):
   1158             self.write('context.eval_ctx, ')
   1159         elif getattr(func, 'environmentfilter', False):
   1160             self.write('environment, ')
   1161         if node.node is not None:
   1162             self.visit(node.node, frame)
   1163         elif frame.eval_ctx.volatile:
   1164             self.write('(context.eval_ctx.autoescape and Markup(concat(%s)) or concat(%s))' % (frame.buffer, frame.buffer))
   1165         elif frame.eval_ctx.autoescape:
   1166             self.write('Markup(concat(%s))' % frame.buffer)
   1167         else:
   1168             self.write('concat(%s)' % frame.buffer)
   1169         self.signature(node, frame)
   1170         self.write(')')
   1171 
   1172     def visit_Test(self, node, frame):
   1173         self.write(self.tests[node.name] + '(')
   1174         if node.name not in self.environment.tests:
   1175             self.fail('no test named %r' % node.name, node.lineno)
   1176         self.visit(node.node, frame)
   1177         self.signature(node, frame)
   1178         self.write(')')
   1179 
   1180     def visit_CondExpr(self, node, frame):
   1181 
   1182         def write_expr2():
   1183             if node.expr2 is not None:
   1184                 return self.visit(node.expr2, frame)
   1185             self.write('environment.undefined(%r)' % ('the inline if-expression on %s evaluated to false and no else section was defined.' % self.position(node)))
   1186 
   1187         if not have_condexpr:
   1188             self.write('((')
   1189             self.visit(node.test, frame)
   1190             self.write(') and (')
   1191             self.visit(node.expr1, frame)
   1192             self.write(',) or (')
   1193             write_expr2()
   1194             self.write(',))[0]')
   1195         else:
   1196             self.write('(')
   1197             self.visit(node.expr1, frame)
   1198             self.write(' if ')
   1199             self.visit(node.test, frame)
   1200             self.write(' else ')
   1201             write_expr2()
   1202             self.write(')')
   1203 
   1204     def visit_Call(self, node, frame, forward_caller = False):
   1205         if self.environment.sandboxed:
   1206             self.write('environment.call(context, ')
   1207         else:
   1208             self.write('context.call(')
   1209         self.visit(node.node, frame)
   1210         extra_kwargs = forward_caller and {'caller': 'caller'} or None
   1211         self.signature(node, frame, extra_kwargs)
   1212         self.write(')')
   1213 
   1214     def visit_Keyword(self, node, frame):
   1215         self.write(node.key + '=')
   1216         self.visit(node.value, frame)
   1217 
   1218     def visit_MarkSafe(self, node, frame):
   1219         self.write('Markup(')
   1220         self.visit(node.expr, frame)
   1221         self.write(')')
   1222 
   1223     def visit_MarkSafeIfAutoescape(self, node, frame):
   1224         self.write('(context.eval_ctx.autoescape and Markup or identity)(')
   1225         self.visit(node.expr, frame)
   1226         self.write(')')
   1227 
   1228     def visit_EnvironmentAttribute(self, node, frame):
   1229         self.write('environment.' + node.name)
   1230 
   1231     def visit_ExtensionAttribute(self, node, frame):
   1232         self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
   1233 
   1234     def visit_ImportedName(self, node, frame):
   1235         self.write(self.import_aliases[node.importname])
   1236 
   1237     def visit_InternalName(self, node, frame):
   1238         self.write(node.name)
   1239 
   1240     def visit_ContextReference(self, node, frame):
   1241         self.write('context')
   1242 
   1243     def visit_Continue(self, node, frame):
   1244         self.writeline('continue', node)
   1245 
   1246     def visit_Break(self, node, frame):
   1247         self.writeline('break', node)
   1248 
   1249     def visit_Scope(self, node, frame):
   1250         scope_frame = frame.inner()
   1251         scope_frame.inspect(node.iter_child_nodes())
   1252         aliases = self.push_scope(scope_frame)
   1253         self.pull_locals(scope_frame)
   1254         self.blockvisit(node.body, scope_frame)
   1255         self.pop_scope(aliases, scope_frame)
   1256 
   1257     def visit_EvalContextModifier(self, node, frame):
   1258         for keyword in node.options:
   1259             self.writeline('context.eval_ctx.%s = ' % keyword.key)
   1260             self.visit(keyword.value, frame)
   1261             try:
   1262                 val = keyword.value.as_const(frame.eval_ctx)
   1263             except nodes.Impossible:
   1264                 frame.eval_ctx.volatile = True
   1265             else:
   1266                 setattr(frame.eval_ctx, keyword.key, val)
   1267 
   1268     def visit_ScopedEvalContextModifier(self, node, frame):
   1269         old_ctx_name = self.temporary_identifier()
   1270         safed_ctx = frame.eval_ctx.save()
   1271         self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
   1272         self.visit_EvalContextModifier(node, frame)
   1273         for child in node.body:
   1274             self.visit(child, frame)
   1275 
   1276         frame.eval_ctx.revert(safed_ctx)
   1277         self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)