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