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