1 # -*- coding: utf-8 -*-
6 Compiles nodes into python code.
8 :copyright: (c) 2010 by the Jinja Team.
9 :license: BSD, see LICENSE for more details.
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
33 exec '(0 if 0 else 0)'
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'
45 dict_item_iter = 'items'
48 # does if 0: dummy(x) get us x into the scope?
49 def unoptimize_before_dead_code():
54 unoptimize_before_dead_code = bool(unoptimize_before_dead_code().func_closure)
57 def generate(node, environment, name, filename, stream=None,
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)
65 return generator.stream.getvalue()
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:
72 if isinstance(value, (bool, int, long, float, complex, basestring,
75 if isinstance(value, (tuple, list, set, frozenset)):
77 if not has_safe_repr(item):
80 elif isinstance(value, dict):
81 for key, value in value.iteritems():
82 if not has_safe_repr(key):
84 if not has_safe_repr(value):
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.
94 visitor = UndeclaredNameVisitor(names)
100 return visitor.undeclared
103 class Identifiers(object):
104 """Tracks the status of identifiers in frames."""
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()
111 # undeclared variables from outer scopes
112 self.outer_undeclared = set()
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()
119 # names that are declared locally
120 self.declared_locally = set()
122 # names that are declared by parameters
123 self.declared_parameter = set()
125 def add_special(self, name):
126 """Register a special name like `loop`."""
127 self.undeclared.discard(name)
128 self.declared.add(name)
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:
136 return name in self.declared
139 return deepcopy(self)
143 """Holds compile time information for us."""
145 def __init__(self, eval_ctx, parent=None):
146 self.eval_ctx = eval_ctx
147 self.identifiers = Identifiers()
149 # a toplevel frame is the root + soft frames such as if conditions.
150 self.toplevel = False
152 # the root frame is basically just the outermost frame, so no if
153 # conditions. This information is used to optimize inheritance
155 self.rootlevel = False
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
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
167 # the name of the block we're in, otherwise None.
168 self.block = parent and parent.block or None
170 # a set of actually assigned names
171 self.assigned_names = set()
173 # the parent of this frame
176 if parent is not None:
177 self.identifiers.declared.update(
178 parent.identifiers.declared |
179 parent.identifiers.declared_parameter |
180 parent.assigned_names
182 self.identifiers.outer_undeclared.update(
183 parent.identifiers.undeclared -
184 self.identifiers.declared
186 self.buffer = parent.buffer
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__)
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
201 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
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.
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))
215 """Return an inner frame."""
216 return Frame(self.eval_ctx, 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.
230 class VisitorExit(RuntimeError):
231 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
234 class DependencyFinderVisitor(NodeVisitor):
235 """A visitor that collects filter and test calls."""
241 def visit_Filter(self, node):
242 self.generic_visit(node)
243 self.filters.add(node.name)
245 def visit_Test(self, node):
246 self.generic_visit(node)
247 self.tests.add(node.name)
249 def visit_Block(self, node):
250 """Stop visiting at blocks."""
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.
259 def __init__(self, names):
260 self.names = set(names)
261 self.undeclared = set()
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:
269 self.names.discard(node.name)
271 def visit_Block(self, node):
272 """Stop visiting a blocks."""
275 class FrameIdentifierVisitor(NodeVisitor):
276 """A visitor for `Frame.inspect`."""
278 def __init__(self, identifiers, hard_scope):
279 self.identifiers = identifiers
280 self.hard_scope = hard_scope
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)
292 def visit_If(self, node):
293 self.visit(node.test)
294 real_identifiers = self.identifiers
296 old_names = real_identifiers.declared_locally | \
297 real_identifiers.declared_parameter
299 def inner_visit(nodes):
302 self.identifiers = real_identifiers.copy()
303 for subnode in nodes:
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
312 body = inner_visit(node.body)
313 else_ = inner_visit(node.else_ or ())
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)
320 # remember those that are declared.
321 real_identifiers.declared_locally.update(body | else_)
323 def visit_Macro(self, node):
324 self.identifiers.declared_locally.add(node.name)
326 def visit_Import(self, node):
327 self.generic_visit(node)
328 self.identifiers.declared_locally.add(node.target)
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])
336 self.identifiers.declared_locally.add(name)
338 def visit_Assign(self, node):
339 """Visit assignments in the correct order."""
340 self.visit(node.node)
341 self.visit(node.target)
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.
347 self.visit(node.iter)
349 def visit_CallBlock(self, node):
350 self.visit(node.call)
352 def visit_FilterBlock(self, node):
353 self.visit(node.filter)
355 def visit_Scope(self, node):
356 """Stop visiting at scopes."""
358 def visit_Block(self, node):
359 """Stop visiting at blocks."""
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.
369 class CodeGenerator(NodeVisitor):
371 def __init__(self, environment, name, filename, stream=None,
375 self.environment = environment
377 self.filename = filename
379 self.created_block_context = False
380 self.defer_init = defer_init
382 # aliases for imports
383 self.import_aliases = {}
385 # a registry for all blocks. Because blocks are moved out
386 # into the global python scope they are registered here
389 # the number of extends statements so far
390 self.extends_so_far = 0
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
397 # the current line number
400 # registry of all filters and tests (global, not block local)
404 # the debug information
406 self._write_debug_info = None
408 # the number of new lines before the next write()
411 # the line number of the last written statement
414 # true if nothing was written so far.
415 self._first_write = True
417 # used by the `temporary_identifier` method to get new
418 # unique, temporary identifier
419 self._last_identifier = 0
421 # the current indentation
422 self._indentation = 0
424 # -- Various compilation helpers
426 def fail(self, msg, lineno):
427 """Fail with a :exc:`TemplateAssertionError`."""
428 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
430 def temporary_identifier(self):
431 """Get a new unique identifier."""
432 self._last_identifier += 1
433 return 't_%d' % self._last_identifier
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)
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:')
445 self.writeline('return Markup(concat(%s))' % frame.buffer)
447 self.writeline('else:')
449 self.writeline('return concat(%s)' % frame.buffer)
451 elif frame.eval_ctx.autoescape:
452 self.writeline('return Markup(concat(%s))' % frame.buffer)
454 self.writeline('return concat(%s)' % frame.buffer)
458 self._indentation += 1
460 def outdent(self, step=1):
461 """Outdent by step."""
462 self._indentation -= step
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)
469 self.writeline('%s.append(' % frame.buffer, node)
471 def end_write(self, frame):
472 """End the writing process started by `start_write`."""
473 if frame.buffer is not None:
476 def simple_write(self, s, frame, node=None):
477 """Simple shortcut for start_write + write + end_write."""
478 self.start_write(frame, node)
480 self.end_write(frame)
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.
487 if frame.buffer is None:
488 self.writeline('if 0: yield None')
490 self.writeline('pass')
493 self.visit(node, frame)
498 """Write a string into the output stream."""
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,
506 self._write_debug_info = None
507 self._first_write = False
508 self.stream.write(' ' * self._indentation)
512 def writeline(self, x, node=None, extra=0):
513 """Combination of newline and write."""
514 self.newline(node, extra)
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
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
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
539 for arg in node.args:
541 self.visit(arg, frame)
543 if not kwarg_workaround:
544 for kwarg in node.kwargs:
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))
552 self.visit(node.dyn_args, frame)
555 if node.dyn_kwargs is not None:
556 self.write(', **dict({')
559 for kwarg in node.kwargs:
560 self.write('%r: ' % kwarg.key)
561 self.visit(kwarg.value, frame)
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:
568 self.visit(node.dyn_kwargs, frame)
573 elif node.dyn_kwargs is not None:
575 self.visit(node.dyn_kwargs, frame)
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))
582 def pull_dependencies(self, nodes):
583 """Pull all the dependencies."""
584 visitor = DependencyFinderVisitor()
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))
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)
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.
612 This also predefines locally declared variables from the loop
613 body because under some circumstances it may be the case that
615 `extra_vars` is passed to `Frame.find_shadowed`.
618 for name in frame.find_shadowed(extra_vars):
619 aliases[name] = ident = self.temporary_identifier()
620 self.writeline('%s = l_%s' % (ident, name))
622 for name in frame.identifiers.declared_locally:
623 if name not in aliases:
624 to_declare.add('l_' + name)
626 self.writeline(' = '.join(to_declare) + ' = missing')
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))
634 for name in frame.identifiers.declared_locally:
635 if name not in aliases:
636 to_delete.add('l_' + name)
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')
643 def function_scoping(self, node, frame, children=None,
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.
654 This will return the modified frame.
656 # we have to iterate twice over it, make sure that works
658 children = node.iter_child_nodes()
659 children = list(children)
660 func_frame = frame.inner()
661 func_frame.inspect(children, hard_scope=True)
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)
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)
680 # remove variables from a closure from the frame's undeclared
682 func_frame.identifiers.undeclared -= (
683 func_frame.identifiers.undeclared &
684 func_frame.identifiers.declared
687 # no special variables for this scope, abort early
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]
696 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
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')
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
725 if 'loop' in frame.identifiers.declared:
726 args = args + ['l_loop=l_loop']
727 self.writeline('def macro(%s):' % ', '.join(args), node)
730 self.pull_locals(frame)
731 self.blockvisit(node.body, frame)
732 self.return_buffer_contents(frame)
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:
742 self.write('Macro(environment, macro, %r, (%s), (' %
744 for arg in node.defaults:
745 self.visit(arg, frame)
747 self.write('), %r, %r, %r)' % (
748 bool(frame.accesses_kwargs),
749 bool(frame.accesses_varargs),
750 bool(frame.accesses_caller)
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)
760 # -- Statement Visitors
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)
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')
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 ''
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
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
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()
792 module, obj = imp.rsplit('.', 1)
793 self.writeline('from %s import %s as %s' %
794 (module, obj, alias))
796 self.writeline('import %s as %s' % (imp, alias))
799 self.writeline('name = %r' % self.name)
801 # generate the root render function.
802 self.writeline('def root(context%s):' % envenv, extra=1)
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
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)
820 # make sure that the parent root is called.
822 if not self.has_known_extends:
824 self.writeline('if parent_template is not None:')
826 self.writeline('for event in parent_template.'
827 'root_render_func(context):')
829 self.writeline('yield event')
830 self.outdent(2 + (not self.has_known_extends))
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),
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)
853 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
854 for x in self.blocks),
857 # add a function that returns the debug info
858 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
861 def visit_Block(self, node, frame):
862 """Call a block and register it for the template."""
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:
869 if self.extends_so_far > 0:
870 self.writeline('if parent_template is None:')
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)
877 self.simple_write('event', frame)
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',
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:
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:')
898 self.writeline('raise TemplateRuntimeError(%r)' %
899 'extended multiple times')
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:
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)
913 self.writeline('context.blocks.setdefault(name, []).'
914 'append(parent_block)')
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
921 self.has_known_extends = True
923 # and now we have one more
924 self.extends_so_far += 1
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:')
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'
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:
948 self.writeline('except TemplateNotFound:')
950 self.writeline('pass')
952 self.writeline('else:')
955 if node.with_context:
956 self.writeline('for event in template.root_render_func('
957 'template.new_context(context.parent, True, '
960 self.writeline('for event in template.module._body_stream:')
963 self.simple_write('event', frame)
966 if node.ignore_missing:
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)
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())')
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)
987 def visit_FromImport(self, node, frame):
988 """Visit named imports."""
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)')
1000 for name in node.names:
1001 if isinstance(name, tuple):
1005 self.writeline('l_%s = getattr(included_template, '
1006 '%r, missing)' % (alias, name))
1007 self.writeline('if l_%s is missing:' % alias)
1009 self.writeline('l_%s = environment.undefined(%r %% '
1010 'included_template.__name__, '
1012 (alias, 'the template %%r (imported on %s) does '
1013 'not export the requested name %s' % (
1014 self.position(node),
1019 var_names.append(alias)
1020 if not alias.startswith('_'):
1021 discarded_names.append(alias)
1022 frame.assigned_names.add(alias)
1025 if len(var_names) == 1:
1027 self.writeline('context.vars[%r] = l_%s' % (name, name))
1029 self.writeline('context.vars.update({%s})' % ', '.join(
1030 '%r: l_%s' % (name, name) for name in var_names
1033 if len(discarded_names) == 1:
1034 self.writeline('context.exported_vars.discard(%r)' %
1037 self.writeline('context.exported_vars.difference_'
1038 'update((%s))' % ', '.join(map(repr, discarded_names)))
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',))
1045 loop_frame = self.function_scoping(node, frame, children,
1048 loop_frame = frame.inner()
1049 loop_frame.inspect(children)
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',))
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',))
1064 # otherwise we set up a buffer and add a function def
1066 self.writeline('def loop(reciter, loop_render_func):', node)
1068 self.buffer(loop_frame)
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
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)
1080 self.pull_locals(loop_frame)
1082 iteration_indicator = self.temporary_identifier()
1083 self.writeline('%s = 1' % iteration_indicator)
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
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)))
1097 self.writeline('for ', node)
1098 self.visit(node.target, loop_frame)
1099 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
1101 # if we have an extened loop and a node test, we filter in the
1103 if extended_loop and node.test is not None:
1105 self.visit(node.target, loop_frame)
1107 self.visit(node.target, loop_frame)
1110 self.write('reciter')
1112 self.visit(node.iter, loop_frame)
1114 test_frame = loop_frame.copy()
1115 self.visit(node.test, test_frame)
1118 elif node.recursive:
1119 self.write('reciter')
1121 self.visit(node.iter, loop_frame)
1124 self.write(', recurse=loop_render_func):')
1126 self.write(extended_loop and '):' or ':')
1128 # tests in not extended loops become a continue
1129 if not extended_loop and node.test is not None:
1131 self.writeline('if not ')
1132 self.visit(node.test, loop_frame)
1135 self.writeline('continue')
1139 self.blockvisit(node.body, loop_frame)
1141 self.writeline('%s = 0' % iteration_indicator)
1145 self.writeline('if %s:' % iteration_indicator)
1147 self.blockvisit(node.else_, loop_frame)
1150 # reset the aliases if there are any.
1151 if not node.recursive:
1152 self.pop_scope(aliases, loop_frame)
1154 # if the node was recursive we have to return the buffer contents
1155 # and start the iteration code
1157 self.return_buffer_contents(loop_frame)
1159 self.start_write(frame, node)
1161 self.visit(node.iter, frame)
1162 self.write(', loop)')
1163 self.end_write(frame)
1165 def visit_If(self, node, frame):
1166 if_frame = frame.soft()
1167 self.writeline('if ', node)
1168 self.visit(node.test, if_frame)
1171 self.blockvisit(node.body, if_frame)
1174 self.writeline('else:')
1176 self.blockvisit(node.else_, if_frame)
1179 def visit_Macro(self, node, frame):
1180 macro_frame = self.macro_body(node, frame)
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)
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)
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)
1211 def visit_ExprStmt(self, node, frame):
1213 self.visit(node.node, frame)
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:
1221 if self.environment.finalize:
1222 finalize = lambda x: unicode(self.environment.finalize(x))
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:')
1231 outdent_later = True
1233 # try to evaluate as many chunks as possible into a static
1234 # string at compile time.
1236 for child in node.nodes:
1238 const = child.as_const(frame.eval_ctx)
1239 except nodes.Impossible:
1242 # the frame can't be volatile here, becaus otherwise the
1243 # as_const() function would raise an Impossible exception
1246 if frame.eval_ctx.autoescape:
1247 if hasattr(const, '__html__'):
1248 const = const.__html__()
1250 const = escape(const)
1251 const = finalize(const)
1253 # if something goes wrong here we evaluate the node
1254 # at runtime for easier debugging
1257 if body and isinstance(body[-1], list):
1258 body[-1].append(const)
1260 body.append([const])
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
1267 self.writeline('%s.append(' % frame.buffer)
1269 self.writeline('%s.extend((' % frame.buffer)
1272 if isinstance(item, list):
1273 val = repr(concat(item))
1274 if frame.buffer is None:
1275 self.writeline('yield ' + val)
1277 self.writeline(val + ', ')
1279 if frame.buffer is None:
1280 self.writeline('yield ', item)
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(')
1290 self.write('to_string(')
1291 if self.environment.finalize is not None:
1292 self.write('environment.finalize(')
1294 self.visit(item, frame)
1295 self.write(')' * close)
1296 if frame.buffer is not None:
1298 if frame.buffer is not None:
1299 # close the open parentheses
1301 self.writeline(len(body) == 1 and ')' or '))')
1303 # otherwise we create a format string as this is faster in that case
1308 if isinstance(item, list):
1309 format.append(concat(item).replace('%', '%%'))
1312 arguments.append(item)
1313 self.writeline('yield ')
1314 self.write(repr(concat(format)) + ' % (')
1317 for argument in arguments:
1318 self.newline(argument)
1320 if frame.eval_ctx.volatile:
1321 self.write('(context.eval_ctx.autoescape and'
1322 ' escape or to_string)(')
1324 elif frame.eval_ctx.autoescape:
1325 self.write('escape(')
1327 if self.environment.finalize is not None:
1328 self.write('environment.finalize(')
1330 self.visit(argument, frame)
1331 self.write(')' * close + ', ')
1338 def visit_Assign(self, node, frame):
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
1345 assignment_frame = frame.copy()
1346 assignment_frame.toplevel_assignments = set()
1348 assignment_frame = frame
1349 self.visit(node.target, assignment_frame)
1351 self.visit(node.node, frame)
1353 # make sure toplevel assignments are added to the context.
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))
1361 self.writeline('context.vars.update({')
1362 for idx, name in enumerate(assignment_frame.toplevel_assignments):
1365 self.write('%r: l_%s' % (name, name))
1368 if len(public_names) == 1:
1369 self.writeline('context.exported_vars.add(%r)' %
1372 self.writeline('context.exported_vars.update((%s))' %
1373 ', '.join(map(repr, public_names)))
1375 # -- Expression Visitors
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)
1383 def visit_Const(self, node, frame):
1385 if isinstance(val, float):
1386 self.write(str(val))
1388 self.write(repr(val))
1390 def visit_TemplateData(self, node, frame):
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)'
1397 def visit_Tuple(self, node, frame):
1400 for idx, item in enumerate(node.items):
1403 self.visit(item, frame)
1404 self.write(idx == 0 and ',)' or ')')
1406 def visit_List(self, node, frame):
1408 for idx, item in enumerate(node.items):
1411 self.visit(item, frame)
1414 def visit_Dict(self, node, frame):
1416 for idx, item in enumerate(node.items):
1419 self.visit(item.key, frame)
1421 self.visit(item.value, frame)
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)
1431 self.visit(node.right, frame)
1434 self.visit(node.left, frame)
1435 self.write(' %s ' % operator)
1436 self.visit(node.right, frame)
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)
1447 self.write('(' + operator)
1448 self.visit(node.node, frame)
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)
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'
1473 func_name = 'unicode_join'
1474 self.write('%s((' % func_name)
1475 for arg in node.nodes:
1476 self.visit(arg, frame)
1480 def visit_Compare(self, node, frame):
1481 self.visit(node.expr, frame)
1483 self.visit(op, frame)
1485 def visit_Operand(self, node, frame):
1486 self.write(' %s ' % operators[node.op])
1487 self.visit(node.expr, frame)
1489 def visit_Getattr(self, node, frame):
1490 self.write('environment.getattr(')
1491 self.visit(node.node, frame)
1492 self.write(', %r)' % node.attr)
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)
1499 self.visit(node.arg, frame)
1502 self.write('environment.getitem(')
1503 self.visit(node.node, frame)
1505 self.visit(node.arg, frame)
1508 def visit_Slice(self, node, frame):
1509 if node.start is not None:
1510 self.visit(node.start, frame)
1512 if node.stop is not None:
1513 self.visit(node.stop, frame)
1514 if node.step is not None:
1516 self.visit(node.step, frame)
1518 def visit_Filter(self, node, frame):
1519 self.write(self.filters[node.name] + '(')
1520 func = self.environment.filters.get(node.name)
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, ')
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)
1541 self.write('concat(%s)' % frame.buffer)
1542 self.signature(node, frame)
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)
1553 def visit_CondExpr(self, node, frame):
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)))
1561 if not have_condexpr:
1563 self.visit(node.test, frame)
1564 self.write(') and (')
1565 self.visit(node.expr1, frame)
1566 self.write(',) or (')
1568 self.write(',))[0]')
1571 self.visit(node.expr1, frame)
1573 self.visit(node.test, frame)
1574 self.write(' else ')
1578 def visit_Call(self, node, frame, forward_caller=False):
1579 if self.environment.sandboxed:
1580 self.write('environment.call(context, ')
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)
1588 def visit_Keyword(self, node, frame):
1589 self.write(node.key + '=')
1590 self.visit(node.value, frame)
1592 # -- Unused nodes for extensions
1594 def visit_MarkSafe(self, node, frame):
1595 self.write('Markup(')
1596 self.visit(node.expr, frame)
1599 def visit_MarkSafeIfAutoescape(self, node, frame):
1600 self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1601 self.visit(node.expr, frame)
1604 def visit_EnvironmentAttribute(self, node, frame):
1605 self.write('environment.' + node.name)
1607 def visit_ExtensionAttribute(self, node, frame):
1608 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
1610 def visit_ImportedName(self, node, frame):
1611 self.write(self.import_aliases[node.importname])
1613 def visit_InternalName(self, node, frame):
1614 self.write(node.name)
1616 def visit_ContextReference(self, node, frame):
1617 self.write('context')
1619 def visit_Continue(self, node, frame):
1620 self.writeline('continue', node)
1622 def visit_Break(self, node, frame):
1623 self.writeline('break', node)
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)
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)
1638 val = keyword.value.as_const(frame.eval_ctx)
1639 except nodes.Impossible:
1640 frame.eval_ctx.volatile = True
1642 setattr(frame.eval_ctx, keyword.key, val)
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)