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.visitor import NodeVisitor, NodeTransformer
16 from jinja2.exceptions import TemplateAssertionError
17 from jinja2.utils import Markup, concat, escape, is_python_keyword, next
32 exec '(0 if 0 else 0)'
39 # what method to iterate over items do we want to use for dict iteration
40 # in generated code? on 2.x let's go with iteritems, on 3.x with items
41 if hasattr(dict, 'iteritems'):
42 dict_item_iter = 'iteritems'
44 dict_item_iter = 'items'
47 # does if 0: dummy(x) get us x into the scope?
48 def unoptimize_before_dead_code():
53 unoptimize_before_dead_code = bool(unoptimize_before_dead_code().func_closure)
56 def generate(node, environment, name, filename, stream=None,
58 """Generate the python source for a node tree."""
59 if not isinstance(node, nodes.Template):
60 raise TypeError('Can\'t compile non template nodes')
61 generator = CodeGenerator(environment, name, filename, stream, defer_init)
64 return generator.stream.getvalue()
67 def has_safe_repr(value):
68 """Does the node have a safe representation?"""
69 if value is None or value is NotImplemented or value is Ellipsis:
71 if isinstance(value, (bool, int, long, float, complex, basestring,
74 if isinstance(value, (tuple, list, set, frozenset)):
76 if not has_safe_repr(item):
79 elif isinstance(value, dict):
80 for key, value in value.iteritems():
81 if not has_safe_repr(key):
83 if not has_safe_repr(value):
89 def find_undeclared(nodes, names):
90 """Check if the names passed are accessed undeclared. The return value
91 is a set of all the undeclared names from the sequence of names found.
93 visitor = UndeclaredNameVisitor(names)
99 return visitor.undeclared
102 class Identifiers(object):
103 """Tracks the status of identifiers in frames."""
106 # variables that are known to be declared (probably from outer
107 # frames or because they are special for the frame)
108 self.declared = set()
110 # undeclared variables from outer scopes
111 self.outer_undeclared = set()
113 # names that are accessed without being explicitly declared by
114 # this one or any of the outer scopes. Names can appear both in
115 # declared and undeclared.
116 self.undeclared = set()
118 # names that are declared locally
119 self.declared_locally = set()
121 # names that are declared by parameters
122 self.declared_parameter = set()
124 def add_special(self, name):
125 """Register a special name like `loop`."""
126 self.undeclared.discard(name)
127 self.declared.add(name)
129 def is_declared(self, name, local_only=False):
130 """Check if a name is declared in this or an outer scope."""
131 if name in self.declared_locally or name in self.declared_parameter:
135 return name in self.declared
138 return deepcopy(self)
142 """Holds compile time information for us."""
144 def __init__(self, parent=None):
145 self.identifiers = Identifiers()
147 # a toplevel frame is the root + soft frames such as if conditions.
148 self.toplevel = False
150 # the root frame is basically just the outermost frame, so no if
151 # conditions. This information is used to optimize inheritance
153 self.rootlevel = False
155 # in some dynamic inheritance situations the compiler needs to add
156 # write tests around output statements.
157 self.require_output_check = parent and parent.require_output_check
159 # inside some tags we are using a buffer rather than yield statements.
160 # this for example affects {% filter %} or {% macro %}. If a frame
161 # is buffered this variable points to the name of the list used as
165 # the name of the block we're in, otherwise None.
166 self.block = parent and parent.block or None
168 # a set of actually assigned names
169 self.assigned_names = set()
171 # the parent of this frame
174 if parent is not None:
175 self.identifiers.declared.update(
176 parent.identifiers.declared |
177 parent.identifiers.declared_parameter |
178 parent.assigned_names
180 self.identifiers.outer_undeclared.update(
181 parent.identifiers.undeclared -
182 self.identifiers.declared
184 self.buffer = parent.buffer
187 """Create a copy of the current one."""
188 rv = object.__new__(self.__class__)
189 rv.__dict__.update(self.__dict__)
190 rv.identifiers = object.__new__(self.identifiers.__class__)
191 rv.identifiers.__dict__.update(self.identifiers.__dict__)
194 def inspect(self, nodes, hard_scope=False):
195 """Walk the node and check for identifiers. If the scope is hard (eg:
196 enforce on a python level) overrides from outer scopes are tracked
199 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
203 def find_shadowed(self, extra=()):
204 """Find all the shadowed names. extra is an iterable of variables
205 that may be defined with `add_special` which may occour scoped.
208 return (i.declared | i.outer_undeclared) & \
209 (i.declared_locally | i.declared_parameter) | \
210 set(x for x in extra if i.is_declared(x))
213 """Return an inner frame."""
217 """Return a soft frame. A soft frame may not be modified as
218 standalone thing as it shares the resources with the frame it
219 was created of, but it's not a rootlevel frame any longer.
228 class VisitorExit(RuntimeError):
229 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
232 class DependencyFinderVisitor(NodeVisitor):
233 """A visitor that collects filter and test calls."""
239 def visit_Filter(self, node):
240 self.generic_visit(node)
241 self.filters.add(node.name)
243 def visit_Test(self, node):
244 self.generic_visit(node)
245 self.tests.add(node.name)
247 def visit_Block(self, node):
248 """Stop visiting at blocks."""
251 class UndeclaredNameVisitor(NodeVisitor):
252 """A visitor that checks if a name is accessed without being
253 declared. This is different from the frame visitor as it will
254 not stop at closure frames.
257 def __init__(self, names):
258 self.names = set(names)
259 self.undeclared = set()
261 def visit_Name(self, node):
262 if node.ctx == 'load' and node.name in self.names:
263 self.undeclared.add(node.name)
264 if self.undeclared == self.names:
267 self.names.discard(node.name)
269 def visit_Block(self, node):
270 """Stop visiting a blocks."""
273 class FrameIdentifierVisitor(NodeVisitor):
274 """A visitor for `Frame.inspect`."""
276 def __init__(self, identifiers, hard_scope):
277 self.identifiers = identifiers
278 self.hard_scope = hard_scope
280 def visit_Name(self, node):
281 """All assignments to names go through this function."""
282 if node.ctx == 'store':
283 self.identifiers.declared_locally.add(node.name)
284 elif node.ctx == 'param':
285 self.identifiers.declared_parameter.add(node.name)
286 elif node.ctx == 'load' and not \
287 self.identifiers.is_declared(node.name, self.hard_scope):
288 self.identifiers.undeclared.add(node.name)
290 def visit_If(self, node):
291 self.visit(node.test)
292 real_identifiers = self.identifiers
294 old_names = real_identifiers.declared | \
295 real_identifiers.declared_locally | \
296 real_identifiers.declared_parameter
298 def inner_visit(nodes):
301 self.identifiers = real_identifiers.copy()
302 for subnode in nodes:
304 rv = self.identifiers.declared_locally - old_names
305 # we have to remember the undeclared variables of this branch
306 # because we will have to pull them.
307 real_identifiers.undeclared.update(self.identifiers.undeclared)
308 self.identifiers = real_identifiers
311 body = inner_visit(node.body)
312 else_ = inner_visit(node.else_ or ())
314 # the differences between the two branches are also pulled as
315 # undeclared variables
316 real_identifiers.undeclared.update(body.symmetric_difference(else_))
318 # remember those that are declared.
319 real_identifiers.declared_locally.update(body | else_)
321 def visit_Macro(self, node):
322 self.identifiers.declared_locally.add(node.name)
324 def visit_Import(self, node):
325 self.generic_visit(node)
326 self.identifiers.declared_locally.add(node.target)
328 def visit_FromImport(self, node):
329 self.generic_visit(node)
330 for name in node.names:
331 if isinstance(name, tuple):
332 self.identifiers.declared_locally.add(name[1])
334 self.identifiers.declared_locally.add(name)
336 def visit_Assign(self, node):
337 """Visit assignments in the correct order."""
338 self.visit(node.node)
339 self.visit(node.target)
341 def visit_For(self, node):
342 """Visiting stops at for blocks. However the block sequence
343 is visited as part of the outer scope.
345 self.visit(node.iter)
347 def visit_CallBlock(self, node):
348 self.visit(node.call)
350 def visit_FilterBlock(self, node):
351 self.visit(node.filter)
353 def visit_Scope(self, node):
354 """Stop visiting at scopes."""
356 def visit_Block(self, node):
357 """Stop visiting at blocks."""
360 class CompilerExit(Exception):
361 """Raised if the compiler encountered a situation where it just
362 doesn't make sense to further process the code. Any block that
363 raises such an exception is not further processed.
367 class CodeGenerator(NodeVisitor):
369 def __init__(self, environment, name, filename, stream=None,
373 self.environment = environment
375 self.filename = filename
377 self.created_block_context = False
378 self.defer_init = defer_init
380 # aliases for imports
381 self.import_aliases = {}
383 # a registry for all blocks. Because blocks are moved out
384 # into the global python scope they are registered here
387 # the number of extends statements so far
388 self.extends_so_far = 0
390 # some templates have a rootlevel extends. In this case we
391 # can safely assume that we're a child template and do some
392 # more optimizations.
393 self.has_known_extends = False
395 # the current line number
398 # registry of all filters and tests (global, not block local)
402 # the debug information
404 self._write_debug_info = None
406 # the number of new lines before the next write()
409 # the line number of the last written statement
412 # true if nothing was written so far.
413 self._first_write = True
415 # used by the `temporary_identifier` method to get new
416 # unique, temporary identifier
417 self._last_identifier = 0
419 # the current indentation
420 self._indentation = 0
422 # -- Various compilation helpers
424 def fail(self, msg, lineno):
425 """Fail with a `TemplateAssertionError`."""
426 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
428 def temporary_identifier(self):
429 """Get a new unique identifier."""
430 self._last_identifier += 1
431 return 't_%d' % self._last_identifier
433 def buffer(self, frame):
434 """Enable buffering for the frame from that point onwards."""
435 frame.buffer = self.temporary_identifier()
436 self.writeline('%s = []' % frame.buffer)
438 def return_buffer_contents(self, frame):
439 """Return the buffer contents of the frame."""
440 if self.environment.autoescape:
441 self.writeline('return Markup(concat(%s))' % frame.buffer)
443 self.writeline('return concat(%s)' % frame.buffer)
447 self._indentation += 1
449 def outdent(self, step=1):
450 """Outdent by step."""
451 self._indentation -= step
453 def start_write(self, frame, node=None):
454 """Yield or write into the frame buffer."""
455 if frame.buffer is None:
456 self.writeline('yield ', node)
458 self.writeline('%s.append(' % frame.buffer, node)
460 def end_write(self, frame):
461 """End the writing process started by `start_write`."""
462 if frame.buffer is not None:
465 def simple_write(self, s, frame, node=None):
466 """Simple shortcut for start_write + write + end_write."""
467 self.start_write(frame, node)
469 self.end_write(frame)
471 def blockvisit(self, nodes, frame):
472 """Visit a list of nodes as block in a frame. If the current frame
473 is no buffer a dummy ``if 0: yield None`` is written automatically
474 unless the force_generator parameter is set to False.
476 if frame.buffer is None:
477 self.writeline('if 0: yield None')
479 self.writeline('pass')
482 self.visit(node, frame)
487 """Write a string into the output stream."""
489 if not self._first_write:
490 self.stream.write('\n' * self._new_lines)
491 self.code_lineno += self._new_lines
492 if self._write_debug_info is not None:
493 self.debug_info.append((self._write_debug_info,
495 self._write_debug_info = None
496 self._first_write = False
497 self.stream.write(' ' * self._indentation)
501 def writeline(self, x, node=None, extra=0):
502 """Combination of newline and write."""
503 self.newline(node, extra)
506 def newline(self, node=None, extra=0):
507 """Add one or more newlines before the next write."""
508 self._new_lines = max(self._new_lines, 1 + extra)
509 if node is not None and node.lineno != self._last_line:
510 self._write_debug_info = node.lineno
511 self._last_line = node.lineno
513 def signature(self, node, frame, extra_kwargs=None):
514 """Writes a function call to the stream for the current node.
515 A leading comma is added automatically. The extra keyword
516 arguments may not include python keywords otherwise a syntax
517 error could occour. The extra keyword arguments should be given
520 # if any of the given keyword arguments is a python keyword
521 # we have to make sure that no invalid call is created.
522 kwarg_workaround = False
523 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
524 if is_python_keyword(kwarg):
525 kwarg_workaround = True
528 for arg in node.args:
530 self.visit(arg, frame)
532 if not kwarg_workaround:
533 for kwarg in node.kwargs:
535 self.visit(kwarg, frame)
536 if extra_kwargs is not None:
537 for key, value in extra_kwargs.iteritems():
538 self.write(', %s=%s' % (key, value))
541 self.visit(node.dyn_args, frame)
544 if node.dyn_kwargs is not None:
545 self.write(', **dict({')
548 for kwarg in node.kwargs:
549 self.write('%r: ' % kwarg.key)
550 self.visit(kwarg.value, frame)
552 if extra_kwargs is not None:
553 for key, value in extra_kwargs.iteritems():
554 self.write('%r: %s, ' % (key, value))
555 if node.dyn_kwargs is not None:
557 self.visit(node.dyn_kwargs, frame)
562 elif node.dyn_kwargs is not None:
564 self.visit(node.dyn_kwargs, frame)
566 def pull_locals(self, frame):
567 """Pull all the references identifiers into the local scope."""
568 for name in frame.identifiers.undeclared:
569 self.writeline('l_%s = context.resolve(%r)' % (name, name))
571 def pull_dependencies(self, nodes):
572 """Pull all the dependencies."""
573 visitor = DependencyFinderVisitor()
576 for dependency in 'filters', 'tests':
577 mapping = getattr(self, dependency)
578 for name in getattr(visitor, dependency):
579 if name not in mapping:
580 mapping[name] = self.temporary_identifier()
581 self.writeline('%s = environment.%s[%r]' %
582 (mapping[name], dependency, name))
584 def unoptimize_scope(self, frame):
585 """Disable Python optimizations for the frame."""
586 # XXX: this is not that nice but it has no real overhead. It
587 # mainly works because python finds the locals before dead code
588 # is removed. If that breaks we have to add a dummy function
589 # that just accepts the arguments and does nothing.
590 if frame.identifiers.declared:
591 self.writeline('%sdummy(%s)' % (
592 unoptimize_before_dead_code and 'if 0: ' or '',
593 ', '.join('l_' + name for name in frame.identifiers.declared)
596 def push_scope(self, frame, extra_vars=()):
597 """This function returns all the shadowed variables in a dict
598 in the form name: alias and will write the required assignments
599 into the current scope. No indentation takes place.
601 This also predefines locally declared variables from the loop
602 body because under some circumstances it may be the case that
604 `extra_vars` is passed to `Frame.find_shadowed`.
607 for name in frame.find_shadowed(extra_vars):
608 aliases[name] = ident = self.temporary_identifier()
609 self.writeline('%s = l_%s' % (ident, name))
611 for name in frame.identifiers.declared_locally:
612 if name not in aliases:
613 to_declare.add('l_' + name)
615 self.writeline(' = '.join(to_declare) + ' = missing')
618 def pop_scope(self, aliases, frame):
619 """Restore all aliases and delete unused variables."""
620 for name, alias in aliases.iteritems():
621 self.writeline('l_%s = %s' % (name, alias))
623 for name in frame.identifiers.declared_locally:
624 if name not in aliases:
625 to_delete.add('l_' + name)
627 # we cannot use the del statement here because enclosed
628 # scopes can trigger a SyntaxError:
629 # a = 42; b = lambda: a; del a
630 self.writeline(' = '.join(to_delete) + ' = missing')
632 def function_scoping(self, node, frame, children=None,
634 """In Jinja a few statements require the help of anonymous
635 functions. Those are currently macros and call blocks and in
636 the future also recursive loops. As there is currently
637 technical limitation that doesn't allow reading and writing a
638 variable in a scope where the initial value is coming from an
639 outer scope, this function tries to fall back with a common
640 error message. Additionally the frame passed is modified so
641 that the argumetns are collected and callers are looked up.
643 This will return the modified frame.
645 # we have to iterate twice over it, make sure that works
647 children = node.iter_child_nodes()
648 children = list(children)
649 func_frame = frame.inner()
650 func_frame.inspect(children, hard_scope=True)
652 # variables that are undeclared (accessed before declaration) and
653 # declared locally *and* part of an outside scope raise a template
654 # assertion error. Reason: we can't generate reasonable code from
655 # it without aliasing all the variables.
656 # this could be fixed in Python 3 where we have the nonlocal
657 # keyword or if we switch to bytecode generation
658 overriden_closure_vars = (
659 func_frame.identifiers.undeclared &
660 func_frame.identifiers.declared &
661 (func_frame.identifiers.declared_locally |
662 func_frame.identifiers.declared_parameter)
664 if overriden_closure_vars:
665 self.fail('It\'s not possible to set and access variables '
666 'derived from an outer scope! (affects: %s)' %
667 ', '.join(sorted(overriden_closure_vars)), node.lineno)
669 # remove variables from a closure from the frame's undeclared
671 func_frame.identifiers.undeclared -= (
672 func_frame.identifiers.undeclared &
673 func_frame.identifiers.declared
676 # no special variables for this scope, abort early
680 func_frame.accesses_kwargs = False
681 func_frame.accesses_varargs = False
682 func_frame.accesses_caller = False
683 func_frame.arguments = args = ['l_' + x.name for x in node.args]
685 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
687 if 'caller' in undeclared:
688 func_frame.accesses_caller = True
689 func_frame.identifiers.add_special('caller')
690 args.append('l_caller')
691 if 'kwargs' in undeclared:
692 func_frame.accesses_kwargs = True
693 func_frame.identifiers.add_special('kwargs')
694 args.append('l_kwargs')
695 if 'varargs' in undeclared:
696 func_frame.accesses_varargs = True
697 func_frame.identifiers.add_special('varargs')
698 args.append('l_varargs')
701 def macro_body(self, node, frame, children=None):
702 """Dump the function def of a macro or call block."""
703 frame = self.function_scoping(node, frame, children)
704 # macros are delayed, they never require output checks
705 frame.require_output_check = False
706 args = frame.arguments
707 # XXX: this is an ugly fix for the loop nesting bug
708 # (tests.test_old_bugs.test_loop_call_bug). This works around
709 # a identifier nesting problem we have in general. It's just more
710 # likely to happen in loops which is why we work around it. The
711 # real solution would be "nonlocal" all the identifiers that are
712 # leaking into a new python frame and might be used both unassigned
714 if 'loop' in frame.identifiers.declared:
715 args = args + ['l_loop=l_loop']
716 self.writeline('def macro(%s):' % ', '.join(args), node)
719 self.pull_locals(frame)
720 self.blockvisit(node.body, frame)
721 self.return_buffer_contents(frame)
725 def macro_def(self, node, frame):
726 """Dump the macro definition for the def created by macro_body."""
727 arg_tuple = ', '.join(repr(x.name) for x in node.args)
728 name = getattr(node, 'name', None)
729 if len(node.args) == 1:
731 self.write('Macro(environment, macro, %r, (%s), (' %
733 for arg in node.defaults:
734 self.visit(arg, frame)
736 self.write('), %r, %r, %r)' % (
737 bool(frame.accesses_kwargs),
738 bool(frame.accesses_varargs),
739 bool(frame.accesses_caller)
742 def position(self, node):
743 """Return a human readable position for the node."""
744 rv = 'line %d' % node.lineno
745 if self.name is not None:
746 rv += ' in ' + repr(self.name)
749 # -- Statement Visitors
751 def visit_Template(self, node, frame=None):
752 assert frame is None, 'no root frame allowed'
753 from jinja2.runtime import __all__ as exported
754 self.writeline('from __future__ import division')
755 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
756 if not unoptimize_before_dead_code:
757 self.writeline('dummy = lambda *x: None')
759 # if we want a deferred initialization we cannot move the
760 # environment into a local name
761 envenv = not self.defer_init and ', environment=environment' or ''
763 # do we have an extends tag at all? If not, we can save some
764 # overhead by just not processing any inheritance code.
765 have_extends = node.find(nodes.Extends) is not None
768 for block in node.find_all(nodes.Block):
769 if block.name in self.blocks:
770 self.fail('block %r defined twice' % block.name, block.lineno)
771 self.blocks[block.name] = block
773 # find all imports and import them
774 for import_ in node.find_all(nodes.ImportedName):
775 if import_.importname not in self.import_aliases:
776 imp = import_.importname
777 self.import_aliases[imp] = alias = self.temporary_identifier()
779 module, obj = imp.rsplit('.', 1)
780 self.writeline('from %s import %s as %s' %
781 (module, obj, alias))
783 self.writeline('import %s as %s' % (imp, alias))
786 self.writeline('name = %r' % self.name)
788 # generate the root render function.
789 self.writeline('def root(context%s):' % envenv, extra=1)
793 frame.inspect(node.body)
794 frame.toplevel = frame.rootlevel = True
795 frame.require_output_check = have_extends and not self.has_known_extends
798 self.writeline('parent_template = None')
799 if 'self' in find_undeclared(node.body, ('self',)):
800 frame.identifiers.add_special('self')
801 self.writeline('l_self = TemplateReference(context)')
802 self.pull_locals(frame)
803 self.pull_dependencies(node.body)
804 self.blockvisit(node.body, frame)
807 # make sure that the parent root is called.
809 if not self.has_known_extends:
811 self.writeline('if parent_template is not None:')
813 self.writeline('for event in parent_template.'
814 'root_render_func(context):')
816 self.writeline('yield event')
817 self.outdent(2 + (not self.has_known_extends))
819 # at this point we now have the blocks collected and can visit them too.
820 for name, block in self.blocks.iteritems():
821 block_frame = Frame()
822 block_frame.inspect(block.body)
823 block_frame.block = name
824 self.writeline('def block_%s(context%s):' % (name, envenv),
827 undeclared = find_undeclared(block.body, ('self', 'super'))
828 if 'self' in undeclared:
829 block_frame.identifiers.add_special('self')
830 self.writeline('l_self = TemplateReference(context)')
831 if 'super' in undeclared:
832 block_frame.identifiers.add_special('super')
833 self.writeline('l_super = context.super(%r, '
834 'block_%s)' % (name, name))
835 self.pull_locals(block_frame)
836 self.pull_dependencies(block.body)
837 self.blockvisit(block.body, block_frame)
840 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
841 for x in self.blocks),
844 # add a function that returns the debug info
845 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
848 def visit_Block(self, node, frame):
849 """Call a block and register it for the template."""
852 # if we know that we are a child template, there is no need to
853 # check if we are one
854 if self.has_known_extends:
856 if self.extends_so_far > 0:
857 self.writeline('if parent_template is None:')
860 context = node.scoped and 'context.derived(locals())' or 'context'
861 self.writeline('for event in context.blocks[%r][0](%s):' % (
862 node.name, context), node)
864 self.simple_write('event', frame)
867 def visit_Extends(self, node, frame):
868 """Calls the extender."""
869 if not frame.toplevel:
870 self.fail('cannot use extend from a non top-level scope',
873 # if the number of extends statements in general is zero so
874 # far, we don't have to add a check if something extended
875 # the template before this one.
876 if self.extends_so_far > 0:
878 # if we have a known extends we just add a template runtime
879 # error into the generated code. We could catch that at compile
880 # time too, but i welcome it not to confuse users by throwing the
881 # same error at different times just "because we can".
882 if not self.has_known_extends:
883 self.writeline('if parent_template is not None:')
885 self.writeline('raise TemplateRuntimeError(%r)' %
886 'extended multiple times')
889 # if we have a known extends already we don't need that code here
890 # as we know that the template execution will end here.
891 if self.has_known_extends:
894 self.writeline('parent_template = environment.get_template(', node)
895 self.visit(node.template, frame)
896 self.write(', %r)' % self.name)
897 self.writeline('for name, parent_block in parent_template.'
898 'blocks.%s():' % dict_item_iter)
900 self.writeline('context.blocks.setdefault(name, []).'
901 'append(parent_block)')
904 # if this extends statement was in the root level we can take
905 # advantage of that information and simplify the generated code
906 # in the top level from this point onwards
908 self.has_known_extends = True
910 # and now we have one more
911 self.extends_so_far += 1
913 def visit_Include(self, node, frame):
914 """Handles includes."""
915 if node.with_context:
916 self.unoptimize_scope(frame)
917 if node.ignore_missing:
918 self.writeline('try:')
921 func_name = 'get_or_select_template'
922 if isinstance(node.template, nodes.Const):
923 if isinstance(node.template.value, basestring):
924 func_name = 'get_template'
925 elif isinstance(node.template.value, (tuple, list)):
926 func_name = 'select_template'
927 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
928 func_name = 'select_template'
930 self.writeline('template = environment.%s(' % func_name, node)
931 self.visit(node.template, frame)
932 self.write(', %r)' % self.name)
933 if node.ignore_missing:
935 self.writeline('except TemplateNotFound:')
937 self.writeline('pass')
939 self.writeline('else:')
942 if node.with_context:
943 self.writeline('for event in template.root_render_func('
944 'template.new_context(context.parent, True, '
947 self.writeline('for event in template.module._body_stream:')
950 self.simple_write('event', frame)
953 if node.ignore_missing:
956 def visit_Import(self, node, frame):
957 """Visit regular imports."""
958 if node.with_context:
959 self.unoptimize_scope(frame)
960 self.writeline('l_%s = ' % node.target, node)
962 self.write('context.vars[%r] = ' % node.target)
963 self.write('environment.get_template(')
964 self.visit(node.template, frame)
965 self.write(', %r).' % self.name)
966 if node.with_context:
967 self.write('make_module(context.parent, True, locals())')
970 if frame.toplevel and not node.target.startswith('_'):
971 self.writeline('context.exported_vars.discard(%r)' % node.target)
972 frame.assigned_names.add(node.target)
974 def visit_FromImport(self, node, frame):
975 """Visit named imports."""
977 self.write('included_template = environment.get_template(')
978 self.visit(node.template, frame)
979 self.write(', %r).' % self.name)
980 if node.with_context:
981 self.write('make_module(context.parent, True)')
987 for name in node.names:
988 if isinstance(name, tuple):
992 self.writeline('l_%s = getattr(included_template, '
993 '%r, missing)' % (alias, name))
994 self.writeline('if l_%s is missing:' % alias)
996 self.writeline('l_%s = environment.undefined(%r %% '
997 'included_template.__name__, '
999 (alias, 'the template %%r (imported on %s) does '
1000 'not export the requested name %s' % (
1001 self.position(node),
1006 var_names.append(alias)
1007 if not alias.startswith('_'):
1008 discarded_names.append(alias)
1009 frame.assigned_names.add(alias)
1012 if len(var_names) == 1:
1014 self.writeline('context.vars[%r] = l_%s' % (name, name))
1016 self.writeline('context.vars.update({%s})' % ', '.join(
1017 '%r: l_%s' % (name, name) for name in var_names
1020 if len(discarded_names) == 1:
1021 self.writeline('context.exported_vars.discard(%r)' %
1024 self.writeline('context.exported_vars.difference_'
1025 'update((%s))' % ', '.join(map(repr, discarded_names)))
1027 def visit_For(self, node, frame):
1028 # when calculating the nodes for the inner frame we have to exclude
1029 # the iterator contents from it
1030 children = node.iter_child_nodes(exclude=('iter',))
1032 loop_frame = self.function_scoping(node, frame, children,
1035 loop_frame = frame.inner()
1036 loop_frame.inspect(children)
1038 # try to figure out if we have an extended loop. An extended loop
1039 # is necessary if the loop is in recursive mode if the special loop
1040 # variable is accessed in the body.
1041 extended_loop = node.recursive or 'loop' in \
1042 find_undeclared(node.iter_child_nodes(
1043 only=('body',)), ('loop',))
1045 # if we don't have an recursive loop we have to find the shadowed
1046 # variables at that point. Because loops can be nested but the loop
1047 # variable is a special one we have to enforce aliasing for it.
1048 if not node.recursive:
1049 aliases = self.push_scope(loop_frame, ('loop',))
1051 # otherwise we set up a buffer and add a function def
1053 self.writeline('def loop(reciter, loop_render_func):', node)
1055 self.buffer(loop_frame)
1058 # make sure the loop variable is a special one and raise a template
1059 # assertion error if a loop tries to write to loop
1061 loop_frame.identifiers.add_special('loop')
1062 for name in node.find_all(nodes.Name):
1063 if name.ctx == 'store' and name.name == 'loop':
1064 self.fail('Can\'t assign to special loop variable '
1065 'in for-loop target', name.lineno)
1067 self.pull_locals(loop_frame)
1069 iteration_indicator = self.temporary_identifier()
1070 self.writeline('%s = 1' % iteration_indicator)
1072 # Create a fake parent loop if the else or test section of a
1073 # loop is accessing the special loop variable and no parent loop
1075 if 'loop' not in aliases and 'loop' in find_undeclared(
1076 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1077 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
1078 ("'loop' is undefined. the filter section of a loop as well "
1079 "as the else block doesn't have access to the special 'loop'"
1080 " variable of the current loop. Because there is no parent "
1081 "loop it's undefined. Happened in loop on %s" %
1082 self.position(node)))
1084 self.writeline('for ', node)
1085 self.visit(node.target, loop_frame)
1086 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
1088 # if we have an extened loop and a node test, we filter in the
1090 if extended_loop and node.test is not None:
1092 self.visit(node.target, loop_frame)
1094 self.visit(node.target, loop_frame)
1097 self.write('reciter')
1099 self.visit(node.iter, loop_frame)
1101 test_frame = loop_frame.copy()
1102 self.visit(node.test, test_frame)
1105 elif node.recursive:
1106 self.write('reciter')
1108 self.visit(node.iter, loop_frame)
1111 self.write(', recurse=loop_render_func):')
1113 self.write(extended_loop and '):' or ':')
1115 # tests in not extended loops become a continue
1116 if not extended_loop and node.test is not None:
1118 self.writeline('if not ')
1119 self.visit(node.test, loop_frame)
1122 self.writeline('continue')
1126 self.blockvisit(node.body, loop_frame)
1128 self.writeline('%s = 0' % iteration_indicator)
1132 self.writeline('if %s:' % iteration_indicator)
1134 self.blockvisit(node.else_, loop_frame)
1137 # reset the aliases if there are any.
1138 if not node.recursive:
1139 self.pop_scope(aliases, loop_frame)
1141 # if the node was recursive we have to return the buffer contents
1142 # and start the iteration code
1144 self.return_buffer_contents(loop_frame)
1146 self.start_write(frame, node)
1148 self.visit(node.iter, frame)
1149 self.write(', loop)')
1150 self.end_write(frame)
1152 def visit_If(self, node, frame):
1153 if_frame = frame.soft()
1154 self.writeline('if ', node)
1155 self.visit(node.test, if_frame)
1158 self.blockvisit(node.body, if_frame)
1161 self.writeline('else:')
1163 self.blockvisit(node.else_, if_frame)
1166 def visit_Macro(self, node, frame):
1167 macro_frame = self.macro_body(node, frame)
1170 if not node.name.startswith('_'):
1171 self.write('context.exported_vars.add(%r)' % node.name)
1172 self.writeline('context.vars[%r] = ' % node.name)
1173 self.write('l_%s = ' % node.name)
1174 self.macro_def(node, macro_frame)
1175 frame.assigned_names.add(node.name)
1177 def visit_CallBlock(self, node, frame):
1178 children = node.iter_child_nodes(exclude=('call',))
1179 call_frame = self.macro_body(node, frame, children)
1180 self.writeline('caller = ')
1181 self.macro_def(node, call_frame)
1182 self.start_write(frame, node)
1183 self.visit_Call(node.call, call_frame, forward_caller=True)
1184 self.end_write(frame)
1186 def visit_FilterBlock(self, node, frame):
1187 filter_frame = frame.inner()
1188 filter_frame.inspect(node.iter_child_nodes())
1189 aliases = self.push_scope(filter_frame)
1190 self.pull_locals(filter_frame)
1191 self.buffer(filter_frame)
1192 self.blockvisit(node.body, filter_frame)
1193 self.start_write(frame, node)
1194 self.visit_Filter(node.filter, filter_frame)
1195 self.end_write(frame)
1196 self.pop_scope(aliases, filter_frame)
1198 def visit_ExprStmt(self, node, frame):
1200 self.visit(node.node, frame)
1202 def visit_Output(self, node, frame):
1203 # if we have a known extends statement, we don't output anything
1204 # if we are in a require_output_check section
1205 if self.has_known_extends and frame.require_output_check:
1208 if self.environment.finalize:
1209 finalize = lambda x: unicode(self.environment.finalize(x))
1215 # if we are inside a frame that requires output checking, we do so
1216 outdent_later = False
1217 if frame.require_output_check:
1218 self.writeline('if parent_template is None:')
1220 outdent_later = True
1222 # try to evaluate as many chunks as possible into a static
1223 # string at compile time.
1225 for child in node.nodes:
1227 const = child.as_const()
1228 except nodes.Impossible:
1232 if self.environment.autoescape:
1233 if hasattr(const, '__html__'):
1234 const = const.__html__()
1236 const = escape(const)
1237 const = finalize(const)
1239 # if something goes wrong here we evaluate the node
1240 # at runtime for easier debugging
1243 if body and isinstance(body[-1], list):
1244 body[-1].append(const)
1246 body.append([const])
1248 # if we have less than 3 nodes or a buffer we yield or extend/append
1249 if len(body) < 3 or frame.buffer is not None:
1250 if frame.buffer is not None:
1251 # for one item we append, for more we extend
1253 self.writeline('%s.append(' % frame.buffer)
1255 self.writeline('%s.extend((' % frame.buffer)
1258 if isinstance(item, list):
1259 val = repr(concat(item))
1260 if frame.buffer is None:
1261 self.writeline('yield ' + val)
1263 self.writeline(val + ', ')
1265 if frame.buffer is None:
1266 self.writeline('yield ', item)
1270 if self.environment.autoescape:
1271 self.write('escape(')
1273 self.write('to_string(')
1274 if self.environment.finalize is not None:
1275 self.write('environment.finalize(')
1277 self.visit(item, frame)
1278 self.write(')' * close)
1279 if frame.buffer is not None:
1281 if frame.buffer is not None:
1282 # close the open parentheses
1284 self.writeline(len(body) == 1 and ')' or '))')
1286 # otherwise we create a format string as this is faster in that case
1291 if isinstance(item, list):
1292 format.append(concat(item).replace('%', '%%'))
1295 arguments.append(item)
1296 self.writeline('yield ')
1297 self.write(repr(concat(format)) + ' % (')
1300 for argument in arguments:
1301 self.newline(argument)
1303 if self.environment.autoescape:
1304 self.write('escape(')
1306 if self.environment.finalize is not None:
1307 self.write('environment.finalize(')
1309 self.visit(argument, frame)
1310 self.write(')' * close + ', ')
1317 def visit_Assign(self, node, frame):
1319 # toplevel assignments however go into the local namespace and
1320 # the current template's context. We create a copy of the frame
1321 # here and add a set so that the Name visitor can add the assigned
1324 assignment_frame = frame.copy()
1325 assignment_frame.toplevel_assignments = set()
1327 assignment_frame = frame
1328 self.visit(node.target, assignment_frame)
1330 self.visit(node.node, frame)
1332 # make sure toplevel assignments are added to the context.
1334 public_names = [x for x in assignment_frame.toplevel_assignments
1335 if not x.startswith('_')]
1336 if len(assignment_frame.toplevel_assignments) == 1:
1337 name = next(iter(assignment_frame.toplevel_assignments))
1338 self.writeline('context.vars[%r] = l_%s' % (name, name))
1340 self.writeline('context.vars.update({')
1341 for idx, name in enumerate(assignment_frame.toplevel_assignments):
1344 self.write('%r: l_%s' % (name, name))
1347 if len(public_names) == 1:
1348 self.writeline('context.exported_vars.add(%r)' %
1351 self.writeline('context.exported_vars.update((%s))' %
1352 ', '.join(map(repr, public_names)))
1354 # -- Expression Visitors
1356 def visit_Name(self, node, frame):
1357 if node.ctx == 'store' and frame.toplevel:
1358 frame.toplevel_assignments.add(node.name)
1359 self.write('l_' + node.name)
1360 frame.assigned_names.add(node.name)
1362 def visit_Const(self, node, frame):
1364 if isinstance(val, float):
1365 self.write(str(val))
1367 self.write(repr(val))
1369 def visit_TemplateData(self, node, frame):
1370 self.write(repr(node.as_const()))
1372 def visit_Tuple(self, node, frame):
1375 for idx, item in enumerate(node.items):
1378 self.visit(item, frame)
1379 self.write(idx == 0 and ',)' or ')')
1381 def visit_List(self, node, frame):
1383 for idx, item in enumerate(node.items):
1386 self.visit(item, frame)
1389 def visit_Dict(self, node, frame):
1391 for idx, item in enumerate(node.items):
1394 self.visit(item.key, frame)
1396 self.visit(item.value, frame)
1399 def binop(operator):
1400 def visitor(self, node, frame):
1402 self.visit(node.left, frame)
1403 self.write(' %s ' % operator)
1404 self.visit(node.right, frame)
1409 def visitor(self, node, frame):
1410 self.write('(' + operator)
1411 self.visit(node.node, frame)
1415 visit_Add = binop('+')
1416 visit_Sub = binop('-')
1417 visit_Mul = binop('*')
1418 visit_Div = binop('/')
1419 visit_FloorDiv = binop('//')
1420 visit_Pow = binop('**')
1421 visit_Mod = binop('%')
1422 visit_And = binop('and')
1423 visit_Or = binop('or')
1424 visit_Pos = uaop('+')
1425 visit_Neg = uaop('-')
1426 visit_Not = uaop('not ')
1429 def visit_Concat(self, node, frame):
1430 self.write('%s((' % (self.environment.autoescape and
1431 'markup_join' or 'unicode_join'))
1432 for arg in node.nodes:
1433 self.visit(arg, frame)
1437 def visit_Compare(self, node, frame):
1438 self.visit(node.expr, frame)
1440 self.visit(op, frame)
1442 def visit_Operand(self, node, frame):
1443 self.write(' %s ' % operators[node.op])
1444 self.visit(node.expr, frame)
1446 def visit_Getattr(self, node, frame):
1447 self.write('environment.getattr(')
1448 self.visit(node.node, frame)
1449 self.write(', %r)' % node.attr)
1451 def visit_Getitem(self, node, frame):
1452 # slices bypass the environment getitem method.
1453 if isinstance(node.arg, nodes.Slice):
1454 self.visit(node.node, frame)
1456 self.visit(node.arg, frame)
1459 self.write('environment.getitem(')
1460 self.visit(node.node, frame)
1462 self.visit(node.arg, frame)
1465 def visit_Slice(self, node, frame):
1466 if node.start is not None:
1467 self.visit(node.start, frame)
1469 if node.stop is not None:
1470 self.visit(node.stop, frame)
1471 if node.step is not None:
1473 self.visit(node.step, frame)
1475 def visit_Filter(self, node, frame):
1476 self.write(self.filters[node.name] + '(')
1477 func = self.environment.filters.get(node.name)
1479 self.fail('no filter named %r' % node.name, node.lineno)
1480 if getattr(func, 'contextfilter', False):
1481 self.write('context, ')
1482 elif getattr(func, 'environmentfilter', False):
1483 self.write('environment, ')
1485 # if the filter node is None we are inside a filter block
1486 # and want to write to the current buffer
1487 if node.node is not None:
1488 self.visit(node.node, frame)
1489 elif self.environment.autoescape:
1490 self.write('Markup(concat(%s))' % frame.buffer)
1492 self.write('concat(%s)' % frame.buffer)
1493 self.signature(node, frame)
1496 def visit_Test(self, node, frame):
1497 self.write(self.tests[node.name] + '(')
1498 if node.name not in self.environment.tests:
1499 self.fail('no test named %r' % node.name, node.lineno)
1500 self.visit(node.node, frame)
1501 self.signature(node, frame)
1504 def visit_CondExpr(self, node, frame):
1506 if node.expr2 is not None:
1507 return self.visit(node.expr2, frame)
1508 self.write('environment.undefined(%r)' % ('the inline if-'
1509 'expression on %s evaluated to false and '
1510 'no else section was defined.' % self.position(node)))
1512 if not have_condexpr:
1514 self.visit(node.test, frame)
1515 self.write(') and (')
1516 self.visit(node.expr1, frame)
1517 self.write(',) or (')
1519 self.write(',))[0]')
1522 self.visit(node.expr1, frame)
1524 self.visit(node.test, frame)
1525 self.write(' else ')
1529 def visit_Call(self, node, frame, forward_caller=False):
1530 if self.environment.sandboxed:
1531 self.write('environment.call(context, ')
1533 self.write('context.call(')
1534 self.visit(node.node, frame)
1535 extra_kwargs = forward_caller and {'caller': 'caller'} or None
1536 self.signature(node, frame, extra_kwargs)
1539 def visit_Keyword(self, node, frame):
1540 self.write(node.key + '=')
1541 self.visit(node.value, frame)
1543 # -- Unused nodes for extensions
1545 def visit_MarkSafe(self, node, frame):
1546 self.write('Markup(')
1547 self.visit(node.expr, frame)
1550 def visit_EnvironmentAttribute(self, node, frame):
1551 self.write('environment.' + node.name)
1553 def visit_ExtensionAttribute(self, node, frame):
1554 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
1556 def visit_ImportedName(self, node, frame):
1557 self.write(self.import_aliases[node.importname])
1559 def visit_InternalName(self, node, frame):
1560 self.write(node.name)
1562 def visit_ContextReference(self, node, frame):
1563 self.write('context')
1565 def visit_Continue(self, node, frame):
1566 self.writeline('continue', node)
1568 def visit_Break(self, node, frame):
1569 self.writeline('break', node)
1571 def visit_Scope(self, node, frame):
1572 scope_frame = frame.inner()
1573 scope_frame.inspect(node.iter_child_nodes())
1574 aliases = self.push_scope(scope_frame)
1575 self.pull_locals(scope_frame)
1576 self.blockvisit(node.body, scope_frame)
1577 self.pop_scope(aliases, scope_frame)