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"""
11from itertools import chain
12from copy import deepcopy
13from keyword import iskeyword as is_python_keyword
14from jinja2 import nodes
15from jinja2.nodes import EvalContext
16from jinja2.visitor import NodeVisitor
17from jinja2.exceptions import TemplateAssertionError
18from jinja2.utils import Markup, concat, escape
19from jinja2._compat import range_type, next, text_type, string_types, \
20     iteritems, NativeStringIO, imap
21
22
23operators = {
24    'eq':       '==',
25    'ne':       '!=',
26    'gt':       '>',
27    'gteq':     '>=',
28    'lt':       '<',
29    'lteq':     '<=',
30    'in':       'in',
31    'notin':    'not in'
32}
33
34# what method to iterate over items do we want to use for dict iteration
35# in generated code?  on 2.x let's go with iteritems, on 3.x with items
36if hasattr(dict, 'iteritems'):
37    dict_item_iter = 'iteritems'
38else:
39    dict_item_iter = 'items'
40
41
42# does if 0: dummy(x) get us x into the scope?
43def unoptimize_before_dead_code():
44    x = 42
45    def f():
46        if 0: dummy(x)
47    return f
48
49# The getattr is necessary for pypy which does not set this attribute if
50# no closure is on the function
51unoptimize_before_dead_code = bool(
52    getattr(unoptimize_before_dead_code(), '__closure__', None))
53
54
55def generate(node, environment, name, filename, stream=None,
56             defer_init=False):
57    """Generate the python source for a node tree."""
58    if not isinstance(node, nodes.Template):
59        raise TypeError('Can\'t compile non template nodes')
60    generator = CodeGenerator(environment, name, filename, stream, defer_init)
61    generator.visit(node)
62    if stream is None:
63        return generator.stream.getvalue()
64
65
66def has_safe_repr(value):
67    """Does the node have a safe representation?"""
68    if value is None or value is NotImplemented or value is Ellipsis:
69        return True
70    if isinstance(value, (bool, int, float, complex, range_type,
71            Markup) + string_types):
72        return True
73    if isinstance(value, (tuple, list, set, frozenset)):
74        for item in value:
75            if not has_safe_repr(item):
76                return False
77        return True
78    elif isinstance(value, dict):
79        for key, value in iteritems(value):
80            if not has_safe_repr(key):
81                return False
82            if not has_safe_repr(value):
83                return False
84        return True
85    return False
86
87
88def find_undeclared(nodes, names):
89    """Check if the names passed are accessed undeclared.  The return value
90    is a set of all the undeclared names from the sequence of names found.
91    """
92    visitor = UndeclaredNameVisitor(names)
93    try:
94        for node in nodes:
95            visitor.visit(node)
96    except VisitorExit:
97        pass
98    return visitor.undeclared
99
100
101class Identifiers(object):
102    """Tracks the status of identifiers in frames."""
103
104    def __init__(self):
105        # variables that are known to be declared (probably from outer
106        # frames or because they are special for the frame)
107        self.declared = set()
108
109        # undeclared variables from outer scopes
110        self.outer_undeclared = set()
111
112        # names that are accessed without being explicitly declared by
113        # this one or any of the outer scopes.  Names can appear both in
114        # declared and undeclared.
115        self.undeclared = set()
116
117        # names that are declared locally
118        self.declared_locally = set()
119
120        # names that are declared by parameters
121        self.declared_parameter = set()
122
123    def add_special(self, name):
124        """Register a special name like `loop`."""
125        self.undeclared.discard(name)
126        self.declared.add(name)
127
128    def is_declared(self, name):
129        """Check if a name is declared in this or an outer scope."""
130        if name in self.declared_locally or name in self.declared_parameter:
131            return True
132        return name in self.declared
133
134    def copy(self):
135        return deepcopy(self)
136
137
138class Frame(object):
139    """Holds compile time information for us."""
140
141    def __init__(self, eval_ctx, parent=None):
142        self.eval_ctx = eval_ctx
143        self.identifiers = Identifiers()
144
145        # a toplevel frame is the root + soft frames such as if conditions.
146        self.toplevel = False
147
148        # the root frame is basically just the outermost frame, so no if
149        # conditions.  This information is used to optimize inheritance
150        # situations.
151        self.rootlevel = False
152
153        # in some dynamic inheritance situations the compiler needs to add
154        # write tests around output statements.
155        self.require_output_check = parent and parent.require_output_check
156
157        # inside some tags we are using a buffer rather than yield statements.
158        # this for example affects {% filter %} or {% macro %}.  If a frame
159        # is buffered this variable points to the name of the list used as
160        # buffer.
161        self.buffer = None
162
163        # the name of the block we're in, otherwise None.
164        self.block = parent and parent.block or None
165
166        # a set of actually assigned names
167        self.assigned_names = set()
168
169        # the parent of this frame
170        self.parent = parent
171
172        if parent is not None:
173            self.identifiers.declared.update(
174                parent.identifiers.declared |
175                parent.identifiers.declared_parameter |
176                parent.assigned_names
177            )
178            self.identifiers.outer_undeclared.update(
179                parent.identifiers.undeclared -
180                self.identifiers.declared
181            )
182            self.buffer = parent.buffer
183
184    def copy(self):
185        """Create a copy of the current one."""
186        rv = object.__new__(self.__class__)
187        rv.__dict__.update(self.__dict__)
188        rv.identifiers = object.__new__(self.identifiers.__class__)
189        rv.identifiers.__dict__.update(self.identifiers.__dict__)
190        return rv
191
192    def inspect(self, nodes):
193        """Walk the node and check for identifiers.  If the scope is hard (eg:
194        enforce on a python level) overrides from outer scopes are tracked
195        differently.
196        """
197        visitor = FrameIdentifierVisitor(self.identifiers)
198        for node in nodes:
199            visitor.visit(node)
200
201    def find_shadowed(self, extra=()):
202        """Find all the shadowed names.  extra is an iterable of variables
203        that may be defined with `add_special` which may occour scoped.
204        """
205        i = self.identifiers
206        return (i.declared | i.outer_undeclared) & \
207               (i.declared_locally | i.declared_parameter) | \
208               set(x for x in extra if i.is_declared(x))
209
210    def inner(self):
211        """Return an inner frame."""
212        return Frame(self.eval_ctx, self)
213
214    def soft(self):
215        """Return a soft frame.  A soft frame may not be modified as
216        standalone thing as it shares the resources with the frame it
217        was created of, but it's not a rootlevel frame any longer.
218        """
219        rv = self.copy()
220        rv.rootlevel = False
221        return rv
222
223    __copy__ = copy
224
225
226class VisitorExit(RuntimeError):
227    """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
228
229
230class DependencyFinderVisitor(NodeVisitor):
231    """A visitor that collects filter and test calls."""
232
233    def __init__(self):
234        self.filters = set()
235        self.tests = set()
236
237    def visit_Filter(self, node):
238        self.generic_visit(node)
239        self.filters.add(node.name)
240
241    def visit_Test(self, node):
242        self.generic_visit(node)
243        self.tests.add(node.name)
244
245    def visit_Block(self, node):
246        """Stop visiting at blocks."""
247
248
249class UndeclaredNameVisitor(NodeVisitor):
250    """A visitor that checks if a name is accessed without being
251    declared.  This is different from the frame visitor as it will
252    not stop at closure frames.
253    """
254
255    def __init__(self, names):
256        self.names = set(names)
257        self.undeclared = set()
258
259    def visit_Name(self, node):
260        if node.ctx == 'load' and node.name in self.names:
261            self.undeclared.add(node.name)
262            if self.undeclared == self.names:
263                raise VisitorExit()
264        else:
265            self.names.discard(node.name)
266
267    def visit_Block(self, node):
268        """Stop visiting a blocks."""
269
270
271class FrameIdentifierVisitor(NodeVisitor):
272    """A visitor for `Frame.inspect`."""
273
274    def __init__(self, identifiers):
275        self.identifiers = identifiers
276
277    def visit_Name(self, node):
278        """All assignments to names go through this function."""
279        if node.ctx == 'store':
280            self.identifiers.declared_locally.add(node.name)
281        elif node.ctx == 'param':
282            self.identifiers.declared_parameter.add(node.name)
283        elif node.ctx == 'load' and not \
284             self.identifiers.is_declared(node.name):
285            self.identifiers.undeclared.add(node.name)
286
287    def visit_If(self, node):
288        self.visit(node.test)
289        real_identifiers = self.identifiers
290
291        old_names = real_identifiers.declared_locally | \
292                    real_identifiers.declared_parameter
293
294        def inner_visit(nodes):
295            if not nodes:
296                return set()
297            self.identifiers = real_identifiers.copy()
298            for subnode in nodes:
299                self.visit(subnode)
300            rv = self.identifiers.declared_locally - old_names
301            # we have to remember the undeclared variables of this branch
302            # because we will have to pull them.
303            real_identifiers.undeclared.update(self.identifiers.undeclared)
304            self.identifiers = real_identifiers
305            return rv
306
307        body = inner_visit(node.body)
308        else_ = inner_visit(node.else_ or ())
309
310        # the differences between the two branches are also pulled as
311        # undeclared variables
312        real_identifiers.undeclared.update(body.symmetric_difference(else_) -
313                                           real_identifiers.declared)
314
315        # remember those that are declared.
316        real_identifiers.declared_locally.update(body | else_)
317
318    def visit_Macro(self, node):
319        self.identifiers.declared_locally.add(node.name)
320
321    def visit_Import(self, node):
322        self.generic_visit(node)
323        self.identifiers.declared_locally.add(node.target)
324
325    def visit_FromImport(self, node):
326        self.generic_visit(node)
327        for name in node.names:
328            if isinstance(name, tuple):
329                self.identifiers.declared_locally.add(name[1])
330            else:
331                self.identifiers.declared_locally.add(name)
332
333    def visit_Assign(self, node):
334        """Visit assignments in the correct order."""
335        self.visit(node.node)
336        self.visit(node.target)
337
338    def visit_For(self, node):
339        """Visiting stops at for blocks.  However the block sequence
340        is visited as part of the outer scope.
341        """
342        self.visit(node.iter)
343
344    def visit_CallBlock(self, node):
345        self.visit(node.call)
346
347    def visit_FilterBlock(self, node):
348        self.visit(node.filter)
349
350    def visit_Scope(self, node):
351        """Stop visiting at scopes."""
352
353    def visit_Block(self, node):
354        """Stop visiting at blocks."""
355
356
357class CompilerExit(Exception):
358    """Raised if the compiler encountered a situation where it just
359    doesn't make sense to further process the code.  Any block that
360    raises such an exception is not further processed.
361    """
362
363
364class CodeGenerator(NodeVisitor):
365
366    def __init__(self, environment, name, filename, stream=None,
367                 defer_init=False):
368        if stream is None:
369            stream = NativeStringIO()
370        self.environment = environment
371        self.name = name
372        self.filename = filename
373        self.stream = stream
374        self.created_block_context = False
375        self.defer_init = defer_init
376
377        # aliases for imports
378        self.import_aliases = {}
379
380        # a registry for all blocks.  Because blocks are moved out
381        # into the global python scope they are registered here
382        self.blocks = {}
383
384        # the number of extends statements so far
385        self.extends_so_far = 0
386
387        # some templates have a rootlevel extends.  In this case we
388        # can safely assume that we're a child template and do some
389        # more optimizations.
390        self.has_known_extends = False
391
392        # the current line number
393        self.code_lineno = 1
394
395        # registry of all filters and tests (global, not block local)
396        self.tests = {}
397        self.filters = {}
398
399        # the debug information
400        self.debug_info = []
401        self._write_debug_info = None
402
403        # the number of new lines before the next write()
404        self._new_lines = 0
405
406        # the line number of the last written statement
407        self._last_line = 0
408
409        # true if nothing was written so far.
410        self._first_write = True
411
412        # used by the `temporary_identifier` method to get new
413        # unique, temporary identifier
414        self._last_identifier = 0
415
416        # the current indentation
417        self._indentation = 0
418
419    # -- Various compilation helpers
420
421    def fail(self, msg, lineno):
422        """Fail with a :exc:`TemplateAssertionError`."""
423        raise TemplateAssertionError(msg, lineno, self.name, self.filename)
424
425    def temporary_identifier(self):
426        """Get a new unique identifier."""
427        self._last_identifier += 1
428        return 't_%d' % self._last_identifier
429
430    def buffer(self, frame):
431        """Enable buffering for the frame from that point onwards."""
432        frame.buffer = self.temporary_identifier()
433        self.writeline('%s = []' % frame.buffer)
434
435    def return_buffer_contents(self, frame):
436        """Return the buffer contents of the frame."""
437        if frame.eval_ctx.volatile:
438            self.writeline('if context.eval_ctx.autoescape:')
439            self.indent()
440            self.writeline('return Markup(concat(%s))' % frame.buffer)
441            self.outdent()
442            self.writeline('else:')
443            self.indent()
444            self.writeline('return concat(%s)' % frame.buffer)
445            self.outdent()
446        elif frame.eval_ctx.autoescape:
447            self.writeline('return Markup(concat(%s))' % frame.buffer)
448        else:
449            self.writeline('return concat(%s)' % frame.buffer)
450
451    def indent(self):
452        """Indent by one."""
453        self._indentation += 1
454
455    def outdent(self, step=1):
456        """Outdent by step."""
457        self._indentation -= step
458
459    def start_write(self, frame, node=None):
460        """Yield or write into the frame buffer."""
461        if frame.buffer is None:
462            self.writeline('yield ', node)
463        else:
464            self.writeline('%s.append(' % frame.buffer, node)
465
466    def end_write(self, frame):
467        """End the writing process started by `start_write`."""
468        if frame.buffer is not None:
469            self.write(')')
470
471    def simple_write(self, s, frame, node=None):
472        """Simple shortcut for start_write + write + end_write."""
473        self.start_write(frame, node)
474        self.write(s)
475        self.end_write(frame)
476
477    def blockvisit(self, nodes, frame):
478        """Visit a list of nodes as block in a frame.  If the current frame
479        is no buffer a dummy ``if 0: yield None`` is written automatically
480        unless the force_generator parameter is set to False.
481        """
482        if frame.buffer is None:
483            self.writeline('if 0: yield None')
484        else:
485            self.writeline('pass')
486        try:
487            for node in nodes:
488                self.visit(node, frame)
489        except CompilerExit:
490            pass
491
492    def write(self, x):
493        """Write a string into the output stream."""
494        if self._new_lines:
495            if not self._first_write:
496                self.stream.write('\n' * self._new_lines)
497                self.code_lineno += self._new_lines
498                if self._write_debug_info is not None:
499                    self.debug_info.append((self._write_debug_info,
500                                            self.code_lineno))
501                    self._write_debug_info = None
502            self._first_write = False
503            self.stream.write('    ' * self._indentation)
504            self._new_lines = 0
505        self.stream.write(x)
506
507    def writeline(self, x, node=None, extra=0):
508        """Combination of newline and write."""
509        self.newline(node, extra)
510        self.write(x)
511
512    def newline(self, node=None, extra=0):
513        """Add one or more newlines before the next write."""
514        self._new_lines = max(self._new_lines, 1 + extra)
515        if node is not None and node.lineno != self._last_line:
516            self._write_debug_info = node.lineno
517            self._last_line = node.lineno
518
519    def signature(self, node, frame, extra_kwargs=None):
520        """Writes a function call to the stream for the current node.
521        A leading comma is added automatically.  The extra keyword
522        arguments may not include python keywords otherwise a syntax
523        error could occour.  The extra keyword arguments should be given
524        as python dict.
525        """
526        # if any of the given keyword arguments is a python keyword
527        # we have to make sure that no invalid call is created.
528        kwarg_workaround = False
529        for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
530            if is_python_keyword(kwarg):
531                kwarg_workaround = True
532                break
533
534        for arg in node.args:
535            self.write(', ')
536            self.visit(arg, frame)
537
538        if not kwarg_workaround:
539            for kwarg in node.kwargs:
540                self.write(', ')
541                self.visit(kwarg, frame)
542            if extra_kwargs is not None:
543                for key, value in iteritems(extra_kwargs):
544                    self.write(', %s=%s' % (key, value))
545        if node.dyn_args:
546            self.write(', *')
547            self.visit(node.dyn_args, frame)
548
549        if kwarg_workaround:
550            if node.dyn_kwargs is not None:
551                self.write(', **dict({')
552            else:
553                self.write(', **{')
554            for kwarg in node.kwargs:
555                self.write('%r: ' % kwarg.key)
556                self.visit(kwarg.value, frame)
557                self.write(', ')
558            if extra_kwargs is not None:
559                for key, value in iteritems(extra_kwargs):
560                    self.write('%r: %s, ' % (key, value))
561            if node.dyn_kwargs is not None:
562                self.write('}, **')
563                self.visit(node.dyn_kwargs, frame)
564                self.write(')')
565            else:
566                self.write('}')
567
568        elif node.dyn_kwargs is not None:
569            self.write(', **')
570            self.visit(node.dyn_kwargs, frame)
571
572    def pull_locals(self, frame):
573        """Pull all the references identifiers into the local scope."""
574        for name in frame.identifiers.undeclared:
575            self.writeline('l_%s = context.resolve(%r)' % (name, name))
576
577    def pull_dependencies(self, nodes):
578        """Pull all the dependencies."""
579        visitor = DependencyFinderVisitor()
580        for node in nodes:
581            visitor.visit(node)
582        for dependency in 'filters', 'tests':
583            mapping = getattr(self, dependency)
584            for name in getattr(visitor, dependency):
585                if name not in mapping:
586                    mapping[name] = self.temporary_identifier()
587                self.writeline('%s = environment.%s[%r]' %
588                               (mapping[name], dependency, name))
589
590    def unoptimize_scope(self, frame):
591        """Disable Python optimizations for the frame."""
592        # XXX: this is not that nice but it has no real overhead.  It
593        # mainly works because python finds the locals before dead code
594        # is removed.  If that breaks we have to add a dummy function
595        # that just accepts the arguments and does nothing.
596        if frame.identifiers.declared:
597            self.writeline('%sdummy(%s)' % (
598                unoptimize_before_dead_code and 'if 0: ' or '',
599                ', '.join('l_' + name for name in frame.identifiers.declared)
600            ))
601
602    def push_scope(self, frame, extra_vars=()):
603        """This function returns all the shadowed variables in a dict
604        in the form name: alias and will write the required assignments
605        into the current scope.  No indentation takes place.
606
607        This also predefines locally declared variables from the loop
608        body because under some circumstances it may be the case that
609
610        `extra_vars` is passed to `Frame.find_shadowed`.
611        """
612        aliases = {}
613        for name in frame.find_shadowed(extra_vars):
614            aliases[name] = ident = self.temporary_identifier()
615            self.writeline('%s = l_%s' % (ident, name))
616        to_declare = set()
617        for name in frame.identifiers.declared_locally:
618            if name not in aliases:
619                to_declare.add('l_' + name)
620        if to_declare:
621            self.writeline(' = '.join(to_declare) + ' = missing')
622        return aliases
623
624    def pop_scope(self, aliases, frame):
625        """Restore all aliases and delete unused variables."""
626        for name, alias in iteritems(aliases):
627            self.writeline('l_%s = %s' % (name, alias))
628        to_delete = set()
629        for name in frame.identifiers.declared_locally:
630            if name not in aliases:
631                to_delete.add('l_' + name)
632        if to_delete:
633            # we cannot use the del statement here because enclosed
634            # scopes can trigger a SyntaxError:
635            #   a = 42; b = lambda: a; del a
636            self.writeline(' = '.join(to_delete) + ' = missing')
637
638    def function_scoping(self, node, frame, children=None,
639                         find_special=True):
640        """In Jinja a few statements require the help of anonymous
641        functions.  Those are currently macros and call blocks and in
642        the future also recursive loops.  As there is currently
643        technical limitation that doesn't allow reading and writing a
644        variable in a scope where the initial value is coming from an
645        outer scope, this function tries to fall back with a common
646        error message.  Additionally the frame passed is modified so
647        that the argumetns are collected and callers are looked up.
648
649        This will return the modified frame.
650        """
651        # we have to iterate twice over it, make sure that works
652        if children is None:
653            children = node.iter_child_nodes()
654        children = list(children)
655        func_frame = frame.inner()
656        func_frame.inspect(children)
657
658        # variables that are undeclared (accessed before declaration) and
659        # declared locally *and* part of an outside scope raise a template
660        # assertion error. Reason: we can't generate reasonable code from
661        # it without aliasing all the variables.
662        # this could be fixed in Python 3 where we have the nonlocal
663        # keyword or if we switch to bytecode generation
664        overridden_closure_vars = (
665            func_frame.identifiers.undeclared &
666            func_frame.identifiers.declared &
667            (func_frame.identifiers.declared_locally |
668             func_frame.identifiers.declared_parameter)
669        )
670        if overridden_closure_vars:
671            self.fail('It\'s not possible to set and access variables '
672                      'derived from an outer scope! (affects: %s)' %
673                      ', '.join(sorted(overridden_closure_vars)), node.lineno)
674
675        # remove variables from a closure from the frame's undeclared
676        # identifiers.
677        func_frame.identifiers.undeclared -= (
678            func_frame.identifiers.undeclared &
679            func_frame.identifiers.declared
680        )
681
682        # no special variables for this scope, abort early
683        if not find_special:
684            return func_frame
685
686        func_frame.accesses_kwargs = False
687        func_frame.accesses_varargs = False
688        func_frame.accesses_caller = False
689        func_frame.arguments = args = ['l_' + x.name for x in node.args]
690
691        undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
692
693        if 'caller' in undeclared:
694            func_frame.accesses_caller = True
695            func_frame.identifiers.add_special('caller')
696            args.append('l_caller')
697        if 'kwargs' in undeclared:
698            func_frame.accesses_kwargs = True
699            func_frame.identifiers.add_special('kwargs')
700            args.append('l_kwargs')
701        if 'varargs' in undeclared:
702            func_frame.accesses_varargs = True
703            func_frame.identifiers.add_special('varargs')
704            args.append('l_varargs')
705        return func_frame
706
707    def macro_body(self, node, frame, children=None):
708        """Dump the function def of a macro or call block."""
709        frame = self.function_scoping(node, frame, children)
710        # macros are delayed, they never require output checks
711        frame.require_output_check = False
712        args = frame.arguments
713        # XXX: this is an ugly fix for the loop nesting bug
714        # (tests.test_old_bugs.test_loop_call_bug).  This works around
715        # a identifier nesting problem we have in general.  It's just more
716        # likely to happen in loops which is why we work around it.  The
717        # real solution would be "nonlocal" all the identifiers that are
718        # leaking into a new python frame and might be used both unassigned
719        # and assigned.
720        if 'loop' in frame.identifiers.declared:
721            args = args + ['l_loop=l_loop']
722        self.writeline('def macro(%s):' % ', '.join(args), node)
723        self.indent()
724        self.buffer(frame)
725        self.pull_locals(frame)
726        self.blockvisit(node.body, frame)
727        self.return_buffer_contents(frame)
728        self.outdent()
729        return frame
730
731    def macro_def(self, node, frame):
732        """Dump the macro definition for the def created by macro_body."""
733        arg_tuple = ', '.join(repr(x.name) for x in node.args)
734        name = getattr(node, 'name', None)
735        if len(node.args) == 1:
736            arg_tuple += ','
737        self.write('Macro(environment, macro, %r, (%s), (' %
738                   (name, arg_tuple))
739        for arg in node.defaults:
740            self.visit(arg, frame)
741            self.write(', ')
742        self.write('), %r, %r, %r)' % (
743            bool(frame.accesses_kwargs),
744            bool(frame.accesses_varargs),
745            bool(frame.accesses_caller)
746        ))
747
748    def position(self, node):
749        """Return a human readable position for the node."""
750        rv = 'line %d' % node.lineno
751        if self.name is not None:
752            rv += ' in ' + repr(self.name)
753        return rv
754
755    # -- Statement Visitors
756
757    def visit_Template(self, node, frame=None):
758        assert frame is None, 'no root frame allowed'
759        eval_ctx = EvalContext(self.environment, self.name)
760
761        from jinja2.runtime import __all__ as exported
762        self.writeline('from __future__ import division')
763        self.writeline('from jinja2.runtime import ' + ', '.join(exported))
764        if not unoptimize_before_dead_code:
765            self.writeline('dummy = lambda *x: None')
766
767        # if we want a deferred initialization we cannot move the
768        # environment into a local name
769        envenv = not self.defer_init and ', environment=environment' or ''
770
771        # do we have an extends tag at all?  If not, we can save some
772        # overhead by just not processing any inheritance code.
773        have_extends = node.find(nodes.Extends) is not None
774
775        # find all blocks
776        for block in node.find_all(nodes.Block):
777            if block.name in self.blocks:
778                self.fail('block %r defined twice' % block.name, block.lineno)
779            self.blocks[block.name] = block
780
781        # find all imports and import them
782        for import_ in node.find_all(nodes.ImportedName):
783            if import_.importname not in self.import_aliases:
784                imp = import_.importname
785                self.import_aliases[imp] = alias = self.temporary_identifier()
786                if '.' in imp:
787                    module, obj = imp.rsplit('.', 1)
788                    self.writeline('from %s import %s as %s' %
789                                   (module, obj, alias))
790                else:
791                    self.writeline('import %s as %s' % (imp, alias))
792
793        # add the load name
794        self.writeline('name = %r' % self.name)
795
796        # generate the root render function.
797        self.writeline('def root(context%s):' % envenv, extra=1)
798
799        # process the root
800        frame = Frame(eval_ctx)
801        frame.inspect(node.body)
802        frame.toplevel = frame.rootlevel = True
803        frame.require_output_check = have_extends and not self.has_known_extends
804        self.indent()
805        if have_extends:
806            self.writeline('parent_template = None')
807        if 'self' in find_undeclared(node.body, ('self',)):
808            frame.identifiers.add_special('self')
809            self.writeline('l_self = TemplateReference(context)')
810        self.pull_locals(frame)
811        self.pull_dependencies(node.body)
812        self.blockvisit(node.body, frame)
813        self.outdent()
814
815        # make sure that the parent root is called.
816        if have_extends:
817            if not self.has_known_extends:
818                self.indent()
819                self.writeline('if parent_template is not None:')
820            self.indent()
821            self.writeline('for event in parent_template.'
822                           'root_render_func(context):')
823            self.indent()
824            self.writeline('yield event')
825            self.outdent(2 + (not self.has_known_extends))
826
827        # at this point we now have the blocks collected and can visit them too.
828        for name, block in iteritems(self.blocks):
829            block_frame = Frame(eval_ctx)
830            block_frame.inspect(block.body)
831            block_frame.block = name
832            self.writeline('def block_%s(context%s):' % (name, envenv),
833                           block, 1)
834            self.indent()
835            undeclared = find_undeclared(block.body, ('self', 'super'))
836            if 'self' in undeclared:
837                block_frame.identifiers.add_special('self')
838                self.writeline('l_self = TemplateReference(context)')
839            if 'super' in undeclared:
840                block_frame.identifiers.add_special('super')
841                self.writeline('l_super = context.super(%r, '
842                               'block_%s)' % (name, name))
843            self.pull_locals(block_frame)
844            self.pull_dependencies(block.body)
845            self.blockvisit(block.body, block_frame)
846            self.outdent()
847
848        self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
849                                                   for x in self.blocks),
850                       extra=1)
851
852        # add a function that returns the debug info
853        self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
854                                                    in self.debug_info))
855
856    def visit_Block(self, node, frame):
857        """Call a block and register it for the template."""
858        level = 1
859        if frame.toplevel:
860            # if we know that we are a child template, there is no need to
861            # check if we are one
862            if self.has_known_extends:
863                return
864            if self.extends_so_far > 0:
865                self.writeline('if parent_template is None:')
866                self.indent()
867                level += 1
868        context = node.scoped and 'context.derived(locals())' or 'context'
869        self.writeline('for event in context.blocks[%r][0](%s):' % (
870                       node.name, context), node)
871        self.indent()
872        self.simple_write('event', frame)
873        self.outdent(level)
874
875    def visit_Extends(self, node, frame):
876        """Calls the extender."""
877        if not frame.toplevel:
878            self.fail('cannot use extend from a non top-level scope',
879                      node.lineno)
880
881        # if the number of extends statements in general is zero so
882        # far, we don't have to add a check if something extended
883        # the template before this one.
884        if self.extends_so_far > 0:
885
886            # if we have a known extends we just add a template runtime
887            # error into the generated code.  We could catch that at compile
888            # time too, but i welcome it not to confuse users by throwing the
889            # same error at different times just "because we can".
890            if not self.has_known_extends:
891                self.writeline('if parent_template is not None:')
892                self.indent()
893            self.writeline('raise TemplateRuntimeError(%r)' %
894                           'extended multiple times')
895
896            # if we have a known extends already we don't need that code here
897            # as we know that the template execution will end here.
898            if self.has_known_extends:
899                raise CompilerExit()
900            else:
901                self.outdent()
902
903        self.writeline('parent_template = environment.get_template(', node)
904        self.visit(node.template, frame)
905        self.write(', %r)' % self.name)
906        self.writeline('for name, parent_block in parent_template.'
907                       'blocks.%s():' % dict_item_iter)
908        self.indent()
909        self.writeline('context.blocks.setdefault(name, []).'
910                       'append(parent_block)')
911        self.outdent()
912
913        # if this extends statement was in the root level we can take
914        # advantage of that information and simplify the generated code
915        # in the top level from this point onwards
916        if frame.rootlevel:
917            self.has_known_extends = True
918
919        # and now we have one more
920        self.extends_so_far += 1
921
922    def visit_Include(self, node, frame):
923        """Handles includes."""
924        if node.with_context:
925            self.unoptimize_scope(frame)
926        if node.ignore_missing:
927            self.writeline('try:')
928            self.indent()
929
930        func_name = 'get_or_select_template'
931        if isinstance(node.template, nodes.Const):
932            if isinstance(node.template.value, string_types):
933                func_name = 'get_template'
934            elif isinstance(node.template.value, (tuple, list)):
935                func_name = 'select_template'
936        elif isinstance(node.template, (nodes.Tuple, nodes.List)):
937            func_name = 'select_template'
938
939        self.writeline('template = environment.%s(' % func_name, node)
940        self.visit(node.template, frame)
941        self.write(', %r)' % self.name)
942        if node.ignore_missing:
943            self.outdent()
944            self.writeline('except TemplateNotFound:')
945            self.indent()
946            self.writeline('pass')
947            self.outdent()
948            self.writeline('else:')
949            self.indent()
950
951        if node.with_context:
952            self.writeline('for event in template.root_render_func('
953                           'template.new_context(context.parent, True, '
954                           'locals())):')
955        else:
956            self.writeline('for event in template.module._body_stream:')
957
958        self.indent()
959        self.simple_write('event', frame)
960        self.outdent()
961
962        if node.ignore_missing:
963            self.outdent()
964
965    def visit_Import(self, node, frame):
966        """Visit regular imports."""
967        if node.with_context:
968            self.unoptimize_scope(frame)
969        self.writeline('l_%s = ' % node.target, node)
970        if frame.toplevel:
971            self.write('context.vars[%r] = ' % node.target)
972        self.write('environment.get_template(')
973        self.visit(node.template, frame)
974        self.write(', %r).' % self.name)
975        if node.with_context:
976            self.write('make_module(context.parent, True, locals())')
977        else:
978            self.write('module')
979        if frame.toplevel and not node.target.startswith('_'):
980            self.writeline('context.exported_vars.discard(%r)' % node.target)
981        frame.assigned_names.add(node.target)
982
983    def visit_FromImport(self, node, frame):
984        """Visit named imports."""
985        self.newline(node)
986        self.write('included_template = environment.get_template(')
987        self.visit(node.template, frame)
988        self.write(', %r).' % self.name)
989        if node.with_context:
990            self.write('make_module(context.parent, True)')
991        else:
992            self.write('module')
993
994        var_names = []
995        discarded_names = []
996        for name in node.names:
997            if isinstance(name, tuple):
998                name, alias = name
999            else:
1000                alias = name
1001            self.writeline('l_%s = getattr(included_template, '
1002                           '%r, missing)' % (alias, name))
1003            self.writeline('if l_%s is missing:' % alias)
1004            self.indent()
1005            self.writeline('l_%s = environment.undefined(%r %% '
1006                           'included_template.__name__, '
1007                           'name=%r)' %
1008                           (alias, 'the template %%r (imported on %s) does '
1009                           'not export the requested name %s' % (
1010                                self.position(node),
1011                                repr(name)
1012                           ), name))
1013            self.outdent()
1014            if frame.toplevel:
1015                var_names.append(alias)
1016                if not alias.startswith('_'):
1017                    discarded_names.append(alias)
1018            frame.assigned_names.add(alias)
1019
1020        if var_names:
1021            if len(var_names) == 1:
1022                name = var_names[0]
1023                self.writeline('context.vars[%r] = l_%s' % (name, name))
1024            else:
1025                self.writeline('context.vars.update({%s})' % ', '.join(
1026                    '%r: l_%s' % (name, name) for name in var_names
1027                ))
1028        if discarded_names:
1029            if len(discarded_names) == 1:
1030                self.writeline('context.exported_vars.discard(%r)' %
1031                               discarded_names[0])
1032            else:
1033                self.writeline('context.exported_vars.difference_'
1034                               'update((%s))' % ', '.join(imap(repr, discarded_names)))
1035
1036    def visit_For(self, node, frame):
1037        # when calculating the nodes for the inner frame we have to exclude
1038        # the iterator contents from it
1039        children = node.iter_child_nodes(exclude=('iter',))
1040        if node.recursive:
1041            loop_frame = self.function_scoping(node, frame, children,
1042                                               find_special=False)
1043        else:
1044            loop_frame = frame.inner()
1045            loop_frame.inspect(children)
1046
1047        # try to figure out if we have an extended loop.  An extended loop
1048        # is necessary if the loop is in recursive mode if the special loop
1049        # variable is accessed in the body.
1050        extended_loop = node.recursive or 'loop' in \
1051                        find_undeclared(node.iter_child_nodes(
1052                            only=('body',)), ('loop',))
1053
1054        # if we don't have an recursive loop we have to find the shadowed
1055        # variables at that point.  Because loops can be nested but the loop
1056        # variable is a special one we have to enforce aliasing for it.
1057        if not node.recursive:
1058            aliases = self.push_scope(loop_frame, ('loop',))
1059
1060        # otherwise we set up a buffer and add a function def
1061        else:
1062            self.writeline('def loop(reciter, loop_render_func, depth=0):', node)
1063            self.indent()
1064            self.buffer(loop_frame)
1065            aliases = {}
1066
1067        # make sure the loop variable is a special one and raise a template
1068        # assertion error if a loop tries to write to loop
1069        if extended_loop:
1070            self.writeline('l_loop = missing')
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(', loop_render_func, depth):')
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: text_type(self.environment.finalize(x))
1220        else:
1221            finalize = text_type
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(imap(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        self.write('(')
1559        self.visit(node.expr1, frame)
1560        self.write(' if ')
1561        self.visit(node.test, frame)
1562        self.write(' else ')
1563        write_expr2()
1564        self.write(')')
1565
1566    def visit_Call(self, node, frame, forward_caller=False):
1567        if self.environment.sandboxed:
1568            self.write('environment.call(context, ')
1569        else:
1570            self.write('context.call(')
1571        self.visit(node.node, frame)
1572        extra_kwargs = forward_caller and {'caller': 'caller'} or None
1573        self.signature(node, frame, extra_kwargs)
1574        self.write(')')
1575
1576    def visit_Keyword(self, node, frame):
1577        self.write(node.key + '=')
1578        self.visit(node.value, frame)
1579
1580    # -- Unused nodes for extensions
1581
1582    def visit_MarkSafe(self, node, frame):
1583        self.write('Markup(')
1584        self.visit(node.expr, frame)
1585        self.write(')')
1586
1587    def visit_MarkSafeIfAutoescape(self, node, frame):
1588        self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1589        self.visit(node.expr, frame)
1590        self.write(')')
1591
1592    def visit_EnvironmentAttribute(self, node, frame):
1593        self.write('environment.' + node.name)
1594
1595    def visit_ExtensionAttribute(self, node, frame):
1596        self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
1597
1598    def visit_ImportedName(self, node, frame):
1599        self.write(self.import_aliases[node.importname])
1600
1601    def visit_InternalName(self, node, frame):
1602        self.write(node.name)
1603
1604    def visit_ContextReference(self, node, frame):
1605        self.write('context')
1606
1607    def visit_Continue(self, node, frame):
1608        self.writeline('continue', node)
1609
1610    def visit_Break(self, node, frame):
1611        self.writeline('break', node)
1612
1613    def visit_Scope(self, node, frame):
1614        scope_frame = frame.inner()
1615        scope_frame.inspect(node.iter_child_nodes())
1616        aliases = self.push_scope(scope_frame)
1617        self.pull_locals(scope_frame)
1618        self.blockvisit(node.body, scope_frame)
1619        self.pop_scope(aliases, scope_frame)
1620
1621    def visit_EvalContextModifier(self, node, frame):
1622        for keyword in node.options:
1623            self.writeline('context.eval_ctx.%s = ' % keyword.key)
1624            self.visit(keyword.value, frame)
1625            try:
1626                val = keyword.value.as_const(frame.eval_ctx)
1627            except nodes.Impossible:
1628                frame.eval_ctx.volatile = True
1629            else:
1630                setattr(frame.eval_ctx, keyword.key, val)
1631
1632    def visit_ScopedEvalContextModifier(self, node, frame):
1633        old_ctx_name = self.temporary_identifier()
1634        safed_ctx = frame.eval_ctx.save()
1635        self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1636        self.visit_EvalContextModifier(node, frame)
1637        for child in node.body:
1638            self.visit(child, frame)
1639        frame.eval_ctx.revert(safed_ctx)
1640        self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)
1641