1 # -*- coding: utf-8 -*-
6 Compiles nodes into python code.
8 :copyright: (c) 2009 by the Jinja Team.
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 def generate(node, environment, name, filename, stream=None):
40 """Generate the python source for a node tree."""
41 if not isinstance(node, nodes.Template):
42 raise TypeError('Can\'t compile non template nodes')
43 generator = CodeGenerator(environment, name, filename, stream)
46 return generator.stream.getvalue()
49 def has_safe_repr(value):
50 """Does the node have a safe representation?"""
51 if value is None or value is NotImplemented or value is Ellipsis:
53 if isinstance(value, (bool, int, long, float, complex, basestring,
56 if isinstance(value, (tuple, list, set, frozenset)):
58 if not has_safe_repr(item):
61 elif isinstance(value, dict):
62 for key, value in value.iteritems():
63 if not has_safe_repr(key):
65 if not has_safe_repr(value):
71 def find_undeclared(nodes, names):
72 """Check if the names passed are accessed undeclared. The return value
73 is a set of all the undeclared names from the sequence of names found.
75 visitor = UndeclaredNameVisitor(names)
81 return visitor.undeclared
84 class Identifiers(object):
85 """Tracks the status of identifiers in frames."""
88 # variables that are known to be declared (probably from outer
89 # frames or because they are special for the frame)
92 # undeclared variables from outer scopes
93 self.outer_undeclared = set()
95 # names that are accessed without being explicitly declared by
96 # this one or any of the outer scopes. Names can appear both in
97 # declared and undeclared.
98 self.undeclared = set()
100 # names that are declared locally
101 self.declared_locally = set()
103 # names that are declared by parameters
104 self.declared_parameter = set()
106 def add_special(self, name):
107 """Register a special name like `loop`."""
108 self.undeclared.discard(name)
109 self.declared.add(name)
111 def is_declared(self, name, local_only=False):
112 """Check if a name is declared in this or an outer scope."""
113 if name in self.declared_locally or name in self.declared_parameter:
117 return name in self.declared
120 return deepcopy(self)
124 """Holds compile time information for us."""
126 def __init__(self, parent=None):
127 self.identifiers = Identifiers()
129 # a toplevel frame is the root + soft frames such as if conditions.
130 self.toplevel = False
132 # the root frame is basically just the outermost frame, so no if
133 # conditions. This information is used to optimize inheritance
135 self.rootlevel = False
137 # in some dynamic inheritance situations the compiler needs to add
138 # write tests around output statements.
139 self.require_output_check = parent and parent.require_output_check
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
147 # the name of the block we're in, otherwise None.
148 self.block = parent and parent.block or None
150 # a set of actually assigned names
151 self.assigned_names = set()
153 # the parent of this frame
156 if parent is not None:
157 self.identifiers.declared.update(
158 parent.identifiers.declared |
159 parent.identifiers.declared_parameter |
160 parent.assigned_names
162 self.identifiers.outer_undeclared.update(
163 parent.identifiers.undeclared -
164 self.identifiers.declared
166 self.buffer = parent.buffer
169 """Create a copy of the current one."""
170 rv = object.__new__(self.__class__)
171 rv.__dict__.update(self.__dict__)
172 rv.identifiers = object.__new__(self.identifiers.__class__)
173 rv.identifiers.__dict__.update(self.identifiers.__dict__)
176 def inspect(self, nodes, hard_scope=False):
177 """Walk the node and check for identifiers. If the scope is hard (eg:
178 enforce on a python level) overrides from outer scopes are tracked
181 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
185 def find_shadowed(self, extra=()):
186 """Find all the shadowed names. extra is an iterable of variables
187 that may be defined with `add_special` which may occour scoped.
190 return (i.declared | i.outer_undeclared) & \
191 (i.declared_locally | i.declared_parameter) | \
192 set(x for x in extra if i.is_declared(x))
195 """Return an inner frame."""
199 """Return a soft frame. A soft frame may not be modified as
200 standalone thing as it shares the resources with the frame it
201 was created of, but it's not a rootlevel frame any longer.
210 class VisitorExit(RuntimeError):
211 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
214 class DependencyFinderVisitor(NodeVisitor):
215 """A visitor that collects filter and test calls."""
221 def visit_Filter(self, node):
222 self.generic_visit(node)
223 self.filters.add(node.name)
225 def visit_Test(self, node):
226 self.generic_visit(node)
227 self.tests.add(node.name)
229 def visit_Block(self, node):
230 """Stop visiting at blocks."""
233 class UndeclaredNameVisitor(NodeVisitor):
234 """A visitor that checks if a name is accessed without being
235 declared. This is different from the frame visitor as it will
236 not stop at closure frames.
239 def __init__(self, names):
240 self.names = set(names)
241 self.undeclared = set()
243 def visit_Name(self, node):
244 if node.ctx == 'load' and node.name in self.names:
245 self.undeclared.add(node.name)
246 if self.undeclared == self.names:
249 self.names.discard(node.name)
251 def visit_Block(self, node):
252 """Stop visiting a blocks."""
255 class FrameIdentifierVisitor(NodeVisitor):
256 """A visitor for `Frame.inspect`."""
258 def __init__(self, identifiers, hard_scope):
259 self.identifiers = identifiers
260 self.hard_scope = hard_scope
262 def visit_Name(self, node):
263 """All assignments to names go through this function."""
264 if node.ctx == 'store':
265 self.identifiers.declared_locally.add(node.name)
266 elif node.ctx == 'param':
267 self.identifiers.declared_parameter.add(node.name)
268 elif node.ctx == 'load' and not \
269 self.identifiers.is_declared(node.name, self.hard_scope):
270 self.identifiers.undeclared.add(node.name)
272 def visit_If(self, node):
273 self.visit(node.test)
274 real_identifiers = self.identifiers
276 old_names = real_identifiers.declared | \
277 real_identifiers.declared_locally | \
278 real_identifiers.declared_parameter
280 def inner_visit(nodes):
283 self.identifiers = real_identifiers.copy()
284 for subnode in nodes:
286 rv = self.identifiers.declared_locally - old_names
287 # we have to remember the undeclared variables of this branch
288 # because we will have to pull them.
289 real_identifiers.undeclared.update(self.identifiers.undeclared)
290 self.identifiers = real_identifiers
293 body = inner_visit(node.body)
294 else_ = inner_visit(node.else_ or ())
296 # the differences between the two branches are also pulled as
297 # undeclared variables
298 real_identifiers.undeclared.update(body.symmetric_difference(else_))
300 # remember those that are declared.
301 real_identifiers.declared_locally.update(body | else_)
303 def visit_Macro(self, node):
304 self.identifiers.declared_locally.add(node.name)
306 def visit_Import(self, node):
307 self.generic_visit(node)
308 self.identifiers.declared_locally.add(node.target)
310 def visit_FromImport(self, node):
311 self.generic_visit(node)
312 for name in node.names:
313 if isinstance(name, tuple):
314 self.identifiers.declared_locally.add(name[1])
316 self.identifiers.declared_locally.add(name)
318 def visit_Assign(self, node):
319 """Visit assignments in the correct order."""
320 self.visit(node.node)
321 self.visit(node.target)
323 def visit_For(self, node):
324 """Visiting stops at for blocks. However the block sequence
325 is visited as part of the outer scope.
327 self.visit(node.iter)
329 def visit_CallBlock(self, node):
330 for child in node.iter_child_nodes(exclude=('body',)):
333 def visit_FilterBlock(self, node):
334 self.visit(node.filter)
336 def visit_Scope(self, node):
337 """Stop visiting at scopes."""
339 def visit_Block(self, node):
340 """Stop visiting at blocks."""
343 class CompilerExit(Exception):
344 """Raised if the compiler encountered a situation where it just
345 doesn't make sense to further process the code. Any block that
346 raises such an exception is not further processed.
350 class CodeGenerator(NodeVisitor):
352 def __init__(self, environment, name, filename, stream=None):
355 self.environment = environment
357 self.filename = filename
359 self.created_block_context = False
361 # aliases for imports
362 self.import_aliases = {}
364 # a registry for all blocks. Because blocks are moved out
365 # into the global python scope they are registered here
368 # the number of extends statements so far
369 self.extends_so_far = 0
371 # some templates have a rootlevel extends. In this case we
372 # can safely assume that we're a child template and do some
373 # more optimizations.
374 self.has_known_extends = False
376 # the current line number
379 # registry of all filters and tests (global, not block local)
383 # the debug information
385 self._write_debug_info = None
387 # the number of new lines before the next write()
390 # the line number of the last written statement
393 # true if nothing was written so far.
394 self._first_write = True
396 # used by the `temporary_identifier` method to get new
397 # unique, temporary identifier
398 self._last_identifier = 0
400 # the current indentation
401 self._indentation = 0
403 # -- Various compilation helpers
405 def fail(self, msg, lineno):
406 """Fail with a `TemplateAssertionError`."""
407 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
409 def temporary_identifier(self):
410 """Get a new unique identifier."""
411 self._last_identifier += 1
412 return 't_%d' % self._last_identifier
414 def buffer(self, frame):
415 """Enable buffering for the frame from that point onwards."""
416 frame.buffer = self.temporary_identifier()
417 self.writeline('%s = []' % frame.buffer)
419 def return_buffer_contents(self, frame):
420 """Return the buffer contents of the frame."""
421 if self.environment.autoescape:
422 self.writeline('return Markup(concat(%s))' % frame.buffer)
424 self.writeline('return concat(%s)' % frame.buffer)
428 self._indentation += 1
430 def outdent(self, step=1):
431 """Outdent by step."""
432 self._indentation -= step
434 def start_write(self, frame, node=None):
435 """Yield or write into the frame buffer."""
436 if frame.buffer is None:
437 self.writeline('yield ', node)
439 self.writeline('%s.append(' % frame.buffer, node)
441 def end_write(self, frame):
442 """End the writing process started by `start_write`."""
443 if frame.buffer is not None:
446 def simple_write(self, s, frame, node=None):
447 """Simple shortcut for start_write + write + end_write."""
448 self.start_write(frame, node)
450 self.end_write(frame)
452 def blockvisit(self, nodes, frame):
453 """Visit a list of nodes as block in a frame. If the current frame
454 is no buffer a dummy ``if 0: yield None`` is written automatically
455 unless the force_generator parameter is set to False.
457 if frame.buffer is None:
458 self.writeline('if 0: yield None')
460 self.writeline('pass')
463 self.visit(node, frame)
468 """Write a string into the output stream."""
470 if not self._first_write:
471 self.stream.write('\n' * self._new_lines)
472 self.code_lineno += self._new_lines
473 if self._write_debug_info is not None:
474 self.debug_info.append((self._write_debug_info,
476 self._write_debug_info = None
477 self._first_write = False
478 self.stream.write(' ' * self._indentation)
482 def writeline(self, x, node=None, extra=0):
483 """Combination of newline and write."""
484 self.newline(node, extra)
487 def newline(self, node=None, extra=0):
488 """Add one or more newlines before the next write."""
489 self._new_lines = max(self._new_lines, 1 + extra)
490 if node is not None and node.lineno != self._last_line:
491 self._write_debug_info = node.lineno
492 self._last_line = node.lineno
494 def signature(self, node, frame, extra_kwargs=None):
495 """Writes a function call to the stream for the current node.
496 A leading comma is added automatically. The extra keyword
497 arguments may not include python keywords otherwise a syntax
498 error could occour. The extra keyword arguments should be given
501 # if any of the given keyword arguments is a python keyword
502 # we have to make sure that no invalid call is created.
503 kwarg_workaround = False
504 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
505 if is_python_keyword(kwarg):
506 kwarg_workaround = True
509 for arg in node.args:
511 self.visit(arg, frame)
513 if not kwarg_workaround:
514 for kwarg in node.kwargs:
516 self.visit(kwarg, frame)
517 if extra_kwargs is not None:
518 for key, value in extra_kwargs.iteritems():
519 self.write(', %s=%s' % (key, value))
522 self.visit(node.dyn_args, frame)
525 if node.dyn_kwargs is not None:
526 self.write(', **dict({')
529 for kwarg in node.kwargs:
530 self.write('%r: ' % kwarg.key)
531 self.visit(kwarg.value, frame)
533 if extra_kwargs is not None:
534 for key, value in extra_kwargs.iteritems():
535 self.write('%r: %s, ' % (key, value))
536 if node.dyn_kwargs is not None:
538 self.visit(node.dyn_kwargs, frame)
543 elif node.dyn_kwargs is not None:
545 self.visit(node.dyn_kwargs, frame)
547 def pull_locals(self, frame):
548 """Pull all the references identifiers into the local scope."""
549 for name in frame.identifiers.undeclared:
550 self.writeline('l_%s = context.resolve(%r)' % (name, name))
552 def pull_dependencies(self, nodes):
553 """Pull all the dependencies."""
554 visitor = DependencyFinderVisitor()
557 for dependency in 'filters', 'tests':
558 mapping = getattr(self, dependency)
559 for name in getattr(visitor, dependency):
560 if name not in mapping:
561 mapping[name] = self.temporary_identifier()
562 self.writeline('%s = environment.%s[%r]' %
563 (mapping[name], dependency, name))
565 def unoptimize_scope(self, frame):
566 """Disable Python optimizations for the frame."""
567 # XXX: this is not that nice but it has no real overhead. It
568 # mainly works because python finds the locals before dead code
569 # is removed. If that breaks we have to add a dummy function
570 # that just accepts the arguments and does nothing.
571 if frame.identifiers.declared:
572 self.writeline('if 0: dummy(%s)' % ', '.join(
573 'l_' + name for name in frame.identifiers.declared))
575 def push_scope(self, frame, extra_vars=()):
576 """This function returns all the shadowed variables in a dict
577 in the form name: alias and will write the required assignments
578 into the current scope. No indentation takes place.
580 This also predefines locally declared variables from the loop
581 body because under some circumstances it may be the case that
583 `extra_vars` is passed to `Frame.find_shadowed`.
586 for name in frame.find_shadowed(extra_vars):
587 aliases[name] = ident = self.temporary_identifier()
588 self.writeline('%s = l_%s' % (ident, name))
590 for name in frame.identifiers.declared_locally:
591 if name not in aliases:
592 to_declare.add('l_' + name)
594 self.writeline(' = '.join(to_declare) + ' = missing')
597 def pop_scope(self, aliases, frame):
598 """Restore all aliases and delete unused variables."""
599 for name, alias in aliases.iteritems():
600 self.writeline('l_%s = %s' % (name, alias))
602 for name in frame.identifiers.declared_locally:
603 if name not in aliases:
604 to_delete.add('l_' + name)
606 # we cannot use the del statement here because enclosed
607 # scopes can trigger a SyntaxError:
608 # a = 42; b = lambda: a; del a
609 self.writeline(' = '.join(to_delete) + ' = missing')
611 def function_scoping(self, node, frame, children=None,
613 """In Jinja a few statements require the help of anonymous
614 functions. Those are currently macros and call blocks and in
615 the future also recursive loops. As there is currently
616 technical limitation that doesn't allow reading and writing a
617 variable in a scope where the initial value is coming from an
618 outer scope, this function tries to fall back with a common
619 error message. Additionally the frame passed is modified so
620 that the argumetns are collected and callers are looked up.
622 This will return the modified frame.
624 # we have to iterate twice over it, make sure that works
626 children = node.iter_child_nodes()
627 children = list(children)
628 func_frame = frame.inner()
629 func_frame.inspect(children, hard_scope=True)
631 # variables that are undeclared (accessed before declaration) and
632 # declared locally *and* part of an outside scope raise a template
633 # assertion error. Reason: we can't generate reasonable code from
634 # it without aliasing all the variables.
635 # this could be fixed in Python 3 where we have the nonlocal
636 # keyword or if we switch to bytecode generation
637 overriden_closure_vars = (
638 func_frame.identifiers.undeclared &
639 func_frame.identifiers.declared &
640 (func_frame.identifiers.declared_locally |
641 func_frame.identifiers.declared_parameter)
643 if overriden_closure_vars:
644 self.fail('It\'s not possible to set and access variables '
645 'derived from an outer scope! (affects: %s)' %
646 ', '.join(sorted(overriden_closure_vars)), node.lineno)
648 # remove variables from a closure from the frame's undeclared
650 func_frame.identifiers.undeclared -= (
651 func_frame.identifiers.undeclared &
652 func_frame.identifiers.declared
655 # no special variables for this scope, abort early
659 func_frame.accesses_kwargs = False
660 func_frame.accesses_varargs = False
661 func_frame.accesses_caller = False
662 func_frame.arguments = args = ['l_' + x.name for x in node.args]
664 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
666 if 'caller' in undeclared:
667 func_frame.accesses_caller = True
668 func_frame.identifiers.add_special('caller')
669 args.append('l_caller')
670 if 'kwargs' in undeclared:
671 func_frame.accesses_kwargs = True
672 func_frame.identifiers.add_special('kwargs')
673 args.append('l_kwargs')
674 if 'varargs' in undeclared:
675 func_frame.accesses_varargs = True
676 func_frame.identifiers.add_special('varargs')
677 args.append('l_varargs')
680 def macro_body(self, node, frame, children=None):
681 """Dump the function def of a macro or call block."""
682 frame = self.function_scoping(node, frame, children)
683 # macros are delayed, they never require output checks
684 frame.require_output_check = False
685 args = frame.arguments
686 # XXX: this is an ugly fix for the loop nesting bug
687 # (tests.test_old_bugs.test_loop_call_bug). This works around
688 # a identifier nesting problem we have in general. It's just more
689 # likely to happen in loops which is why we work around it. The
690 # real solution would be "nonlocal" all the identifiers that are
691 # leaking into a new python frame and might be used both unassigned
693 if 'loop' in frame.identifiers.declared:
694 args = args + ['l_loop=l_loop']
695 self.writeline('def macro(%s):' % ', '.join(args), node)
698 self.pull_locals(frame)
699 self.blockvisit(node.body, frame)
700 self.return_buffer_contents(frame)
704 def macro_def(self, node, frame):
705 """Dump the macro definition for the def created by macro_body."""
706 arg_tuple = ', '.join(repr(x.name) for x in node.args)
707 name = getattr(node, 'name', None)
708 if len(node.args) == 1:
710 self.write('Macro(environment, macro, %r, (%s), (' %
712 for arg in node.defaults:
713 self.visit(arg, frame)
715 self.write('), %r, %r, %r)' % (
716 bool(frame.accesses_kwargs),
717 bool(frame.accesses_varargs),
718 bool(frame.accesses_caller)
721 def position(self, node):
722 """Return a human readable position for the node."""
723 rv = 'line %d' % node.lineno
724 if self.name is not None:
725 rv += ' in ' + repr(self.name)
728 # -- Statement Visitors
730 def visit_Template(self, node, frame=None):
731 assert frame is None, 'no root frame allowed'
732 from jinja2.runtime import __all__ as exported
733 self.writeline('from __future__ import division')
734 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
736 # do we have an extends tag at all? If not, we can save some
737 # overhead by just not processing any inheritance code.
738 have_extends = node.find(nodes.Extends) is not None
741 for block in node.find_all(nodes.Block):
742 if block.name in self.blocks:
743 self.fail('block %r defined twice' % block.name, block.lineno)
744 self.blocks[block.name] = block
746 # find all imports and import them
747 for import_ in node.find_all(nodes.ImportedName):
748 if import_.importname not in self.import_aliases:
749 imp = import_.importname
750 self.import_aliases[imp] = alias = self.temporary_identifier()
752 module, obj = imp.rsplit('.', 1)
753 self.writeline('from %s import %s as %s' %
754 (module, obj, alias))
756 self.writeline('import %s as %s' % (imp, alias))
759 self.writeline('name = %r' % self.name)
761 # generate the root render function.
762 self.writeline('def root(context, environment=environment):', extra=1)
766 frame.inspect(node.body)
767 frame.toplevel = frame.rootlevel = True
768 frame.require_output_check = have_extends and not self.has_known_extends
771 self.writeline('parent_template = None')
772 if 'self' in find_undeclared(node.body, ('self',)):
773 frame.identifiers.add_special('self')
774 self.writeline('l_self = TemplateReference(context)')
775 self.pull_locals(frame)
776 self.pull_dependencies(node.body)
777 self.blockvisit(node.body, frame)
780 # make sure that the parent root is called.
782 if not self.has_known_extends:
784 self.writeline('if parent_template is not None:')
786 self.writeline('for event in parent_template.'
787 'root_render_func(context):')
789 self.writeline('yield event')
790 self.outdent(2 + (not self.has_known_extends))
792 # at this point we now have the blocks collected and can visit them too.
793 for name, block in self.blocks.iteritems():
794 block_frame = Frame()
795 block_frame.inspect(block.body)
796 block_frame.block = name
797 self.writeline('def block_%s(context, environment=environment):'
800 undeclared = find_undeclared(block.body, ('self', 'super'))
801 if 'self' in undeclared:
802 block_frame.identifiers.add_special('self')
803 self.writeline('l_self = TemplateReference(context)')
804 if 'super' in undeclared:
805 block_frame.identifiers.add_special('super')
806 self.writeline('l_super = context.super(%r, '
807 'block_%s)' % (name, name))
808 self.pull_locals(block_frame)
809 self.pull_dependencies(block.body)
810 self.blockvisit(block.body, block_frame)
813 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
814 for x in self.blocks),
817 # add a function that returns the debug info
818 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
821 def visit_Block(self, node, frame):
822 """Call a block and register it for the template."""
825 # if we know that we are a child template, there is no need to
826 # check if we are one
827 if self.has_known_extends:
829 if self.extends_so_far > 0:
830 self.writeline('if parent_template is None:')
833 context = node.scoped and 'context.derived(locals())' or 'context'
834 self.writeline('for event in context.blocks[%r][0](%s):' % (
835 node.name, context), node)
837 self.simple_write('event', frame)
840 def visit_Extends(self, node, frame):
841 """Calls the extender."""
842 if not frame.toplevel:
843 self.fail('cannot use extend from a non top-level scope',
846 # if the number of extends statements in general is zero so
847 # far, we don't have to add a check if something extended
848 # the template before this one.
849 if self.extends_so_far > 0:
851 # if we have a known extends we just add a template runtime
852 # error into the generated code. We could catch that at compile
853 # time too, but i welcome it not to confuse users by throwing the
854 # same error at different times just "because we can".
855 if not self.has_known_extends:
856 self.writeline('if parent_template is not None:')
858 self.writeline('raise TemplateRuntimeError(%r)' %
859 'extended multiple times')
862 # if we have a known extends already we don't need that code here
863 # as we know that the template execution will end here.
864 if self.has_known_extends:
867 self.writeline('parent_template = environment.get_template(', node)
868 self.visit(node.template, frame)
869 self.write(', %r)' % self.name)
870 self.writeline('for name, parent_block in parent_template.'
871 'blocks.iteritems():')
873 self.writeline('context.blocks.setdefault(name, []).'
874 'append(parent_block)')
877 # if this extends statement was in the root level we can take
878 # advantage of that information and simplify the generated code
879 # in the top level from this point onwards
881 self.has_known_extends = True
883 # and now we have one more
884 self.extends_so_far += 1
886 def visit_Include(self, node, frame):
887 """Handles includes."""
888 if node.with_context:
889 self.unoptimize_scope(frame)
890 if node.ignore_missing:
891 self.writeline('try:')
894 func_name = 'get_or_select_template'
895 if isinstance(node.template, nodes.Const):
896 if isinstance(node.template.value, basestring):
897 func_name = 'get_template'
898 elif isinstance(node.template.value, (tuple, list)):
899 func_name = 'select_template'
900 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
901 func_name = 'select_template'
903 self.writeline('template = environment.%s(' % func_name, node)
904 self.visit(node.template, frame)
905 self.write(', %r)' % self.name)
906 if node.ignore_missing:
908 self.writeline('except TemplateNotFound:')
910 self.writeline('pass')
912 self.writeline('else:')
915 if node.with_context:
916 self.writeline('for event in template.root_render_func('
917 'template.new_context(context.parent, True, '
920 self.writeline('for event in template.module._body_stream:')
923 self.simple_write('event', frame)
926 if node.ignore_missing:
929 def visit_Import(self, node, frame):
930 """Visit regular imports."""
931 if node.with_context:
932 self.unoptimize_scope(frame)
933 self.writeline('l_%s = ' % node.target, node)
935 self.write('context.vars[%r] = ' % node.target)
936 self.write('environment.get_template(')
937 self.visit(node.template, frame)
938 self.write(', %r).' % self.name)
939 if node.with_context:
940 self.write('make_module(context.parent, True, locals())')
943 if frame.toplevel and not node.target.startswith('_'):
944 self.writeline('context.exported_vars.discard(%r)' % node.target)
945 frame.assigned_names.add(node.target)
947 def visit_FromImport(self, node, frame):
948 """Visit named imports."""
950 self.write('included_template = environment.get_template(')
951 self.visit(node.template, frame)
952 self.write(', %r).' % self.name)
953 if node.with_context:
954 self.write('make_module(context.parent, True)')
960 for name in node.names:
961 if isinstance(name, tuple):
965 self.writeline('l_%s = getattr(included_template, '
966 '%r, missing)' % (alias, name))
967 self.writeline('if l_%s is missing:' % alias)
969 self.writeline('l_%s = environment.undefined(%r %% '
970 'included_template.__name__, '
972 (alias, 'the template %%r (imported on %s) does '
973 'not export the requested name %s' % (
979 var_names.append(alias)
980 if not alias.startswith('_'):
981 discarded_names.append(alias)
982 frame.assigned_names.add(alias)
985 if len(var_names) == 1:
987 self.writeline('context.vars[%r] = l_%s' % (name, name))
989 self.writeline('context.vars.update({%s})' % ', '.join(
990 '%r: l_%s' % (name, name) for name in var_names
993 if len(discarded_names) == 1:
994 self.writeline('context.exported_vars.discard(%r)' %
997 self.writeline('context.exported_vars.difference_'
998 'update((%s))' % ', '.join(map(repr, discarded_names)))
1000 def visit_For(self, node, frame):
1001 # when calculating the nodes for the inner frame we have to exclude
1002 # the iterator contents from it
1003 children = node.iter_child_nodes(exclude=('iter',))
1005 loop_frame = self.function_scoping(node, frame, children,
1008 loop_frame = frame.inner()
1009 loop_frame.inspect(children)
1011 # try to figure out if we have an extended loop. An extended loop
1012 # is necessary if the loop is in recursive mode if the special loop
1013 # variable is accessed in the body.
1014 extended_loop = node.recursive or 'loop' in \
1015 find_undeclared(node.iter_child_nodes(
1016 only=('body',)), ('loop',))
1018 # if we don't have an recursive loop we have to find the shadowed
1019 # variables at that point. Because loops can be nested but the loop
1020 # variable is a special one we have to enforce aliasing for it.
1021 if not node.recursive:
1022 aliases = self.push_scope(loop_frame, ('loop',))
1024 # otherwise we set up a buffer and add a function def
1026 self.writeline('def loop(reciter, loop_render_func):', node)
1028 self.buffer(loop_frame)
1031 # make sure the loop variable is a special one and raise a template
1032 # assertion error if a loop tries to write to loop
1034 loop_frame.identifiers.add_special('loop')
1035 for name in node.find_all(nodes.Name):
1036 if name.ctx == 'store' and name.name == 'loop':
1037 self.fail('Can\'t assign to special loop variable '
1038 'in for-loop target', name.lineno)
1040 self.pull_locals(loop_frame)
1042 iteration_indicator = self.temporary_identifier()
1043 self.writeline('%s = 1' % iteration_indicator)
1045 # Create a fake parent loop if the else or test section of a
1046 # loop is accessing the special loop variable and no parent loop
1048 if 'loop' not in aliases and 'loop' in find_undeclared(
1049 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1050 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
1051 ("'loop' is undefined. the filter section of a loop as well "
1052 "as the else block doesn't have access to the special 'loop'"
1053 " variable of the current loop. Because there is no parent "
1054 "loop it's undefined. Happened in loop on %s" %
1055 self.position(node)))
1057 self.writeline('for ', node)
1058 self.visit(node.target, loop_frame)
1059 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
1061 # if we have an extened loop and a node test, we filter in the
1063 if extended_loop and node.test is not None:
1065 self.visit(node.target, loop_frame)
1067 self.visit(node.target, loop_frame)
1070 self.write('reciter')
1072 self.visit(node.iter, loop_frame)
1074 test_frame = loop_frame.copy()
1075 self.visit(node.test, test_frame)
1078 elif node.recursive:
1079 self.write('reciter')
1081 self.visit(node.iter, loop_frame)
1084 self.write(', recurse=loop_render_func):')
1086 self.write(extended_loop and '):' or ':')
1088 # tests in not extended loops become a continue
1089 if not extended_loop and node.test is not None:
1091 self.writeline('if not ')
1092 self.visit(node.test, loop_frame)
1095 self.writeline('continue')
1099 self.blockvisit(node.body, loop_frame)
1101 self.writeline('%s = 0' % iteration_indicator)
1105 self.writeline('if %s:' % iteration_indicator)
1107 self.blockvisit(node.else_, loop_frame)
1110 # reset the aliases if there are any.
1111 if not node.recursive:
1112 self.pop_scope(aliases, loop_frame)
1114 # if the node was recursive we have to return the buffer contents
1115 # and start the iteration code
1117 self.return_buffer_contents(loop_frame)
1119 self.start_write(frame, node)
1121 self.visit(node.iter, frame)
1122 self.write(', loop)')
1123 self.end_write(frame)
1125 def visit_If(self, node, frame):
1126 if_frame = frame.soft()
1127 self.writeline('if ', node)
1128 self.visit(node.test, if_frame)
1131 self.blockvisit(node.body, if_frame)
1134 self.writeline('else:')
1136 self.blockvisit(node.else_, if_frame)
1139 def visit_Macro(self, node, frame):
1140 macro_frame = self.macro_body(node, frame)
1143 if not node.name.startswith('_'):
1144 self.write('context.exported_vars.add(%r)' % node.name)
1145 self.writeline('context.vars[%r] = ' % node.name)
1146 self.write('l_%s = ' % node.name)
1147 self.macro_def(node, macro_frame)
1148 frame.assigned_names.add(node.name)
1150 def visit_CallBlock(self, node, frame):
1151 children = node.iter_child_nodes(exclude=('call',))
1152 call_frame = self.macro_body(node, frame, children)
1153 self.writeline('caller = ')
1154 self.macro_def(node, call_frame)
1155 self.start_write(frame, node)
1156 self.visit_Call(node.call, call_frame, forward_caller=True)
1157 self.end_write(frame)
1159 def visit_FilterBlock(self, node, frame):
1160 filter_frame = frame.inner()
1161 filter_frame.inspect(node.iter_child_nodes())
1162 aliases = self.push_scope(filter_frame)
1163 self.pull_locals(filter_frame)
1164 self.buffer(filter_frame)
1165 self.blockvisit(node.body, filter_frame)
1166 self.start_write(frame, node)
1167 self.visit_Filter(node.filter, filter_frame)
1168 self.end_write(frame)
1169 self.pop_scope(aliases, filter_frame)
1171 def visit_ExprStmt(self, node, frame):
1173 self.visit(node.node, frame)
1175 def visit_Output(self, node, frame):
1176 # if we have a known extends statement, we don't output anything
1177 # if we are in a require_output_check section
1178 if self.has_known_extends and frame.require_output_check:
1181 if self.environment.finalize:
1182 finalize = lambda x: unicode(self.environment.finalize(x))
1188 # if we are inside a frame that requires output checking, we do so
1189 outdent_later = False
1190 if frame.require_output_check:
1191 self.writeline('if parent_template is None:')
1193 outdent_later = True
1195 # try to evaluate as many chunks as possible into a static
1196 # string at compile time.
1198 for child in node.nodes:
1200 const = child.as_const()
1201 except nodes.Impossible:
1205 if self.environment.autoescape:
1206 if hasattr(const, '__html__'):
1207 const = const.__html__()
1209 const = escape(const)
1210 const = finalize(const)
1212 # if something goes wrong here we evaluate the node
1213 # at runtime for easier debugging
1216 if body and isinstance(body[-1], list):
1217 body[-1].append(const)
1219 body.append([const])
1221 # if we have less than 3 nodes or a buffer we yield or extend/append
1222 if len(body) < 3 or frame.buffer is not None:
1223 if frame.buffer is not None:
1224 # for one item we append, for more we extend
1226 self.writeline('%s.append(' % frame.buffer)
1228 self.writeline('%s.extend((' % frame.buffer)
1231 if isinstance(item, list):
1232 val = repr(concat(item))
1233 if frame.buffer is None:
1234 self.writeline('yield ' + val)
1236 self.writeline(val + ', ')
1238 if frame.buffer is None:
1239 self.writeline('yield ', item)
1243 if self.environment.autoescape:
1244 self.write('escape(')
1246 self.write('to_string(')
1247 if self.environment.finalize is not None:
1248 self.write('environment.finalize(')
1250 self.visit(item, frame)
1251 self.write(')' * close)
1252 if frame.buffer is not None:
1254 if frame.buffer is not None:
1255 # close the open parentheses
1257 self.writeline(len(body) == 1 and ')' or '))')
1259 # otherwise we create a format string as this is faster in that case
1264 if isinstance(item, list):
1265 format.append(concat(item).replace('%', '%%'))
1268 arguments.append(item)
1269 self.writeline('yield ')
1270 self.write(repr(concat(format)) + ' % (')
1273 for argument in arguments:
1274 self.newline(argument)
1276 if self.environment.autoescape:
1277 self.write('escape(')
1279 if self.environment.finalize is not None:
1280 self.write('environment.finalize(')
1282 self.visit(argument, frame)
1283 self.write(')' * close + ', ')
1290 def visit_Assign(self, node, frame):
1292 # toplevel assignments however go into the local namespace and
1293 # the current template's context. We create a copy of the frame
1294 # here and add a set so that the Name visitor can add the assigned
1297 assignment_frame = frame.copy()
1298 assignment_frame.toplevel_assignments = set()
1300 assignment_frame = frame
1301 self.visit(node.target, assignment_frame)
1303 self.visit(node.node, frame)
1305 # make sure toplevel assignments are added to the context.
1307 public_names = [x for x in assignment_frame.toplevel_assignments
1308 if not x.startswith('_')]
1309 if len(assignment_frame.toplevel_assignments) == 1:
1310 name = next(iter(assignment_frame.toplevel_assignments))
1311 self.writeline('context.vars[%r] = l_%s' % (name, name))
1313 self.writeline('context.vars.update({')
1314 for idx, name in enumerate(assignment_frame.toplevel_assignments):
1317 self.write('%r: l_%s' % (name, name))
1320 if len(public_names) == 1:
1321 self.writeline('context.exported_vars.add(%r)' %
1324 self.writeline('context.exported_vars.update((%s))' %
1325 ', '.join(map(repr, public_names)))
1327 # -- Expression Visitors
1329 def visit_Name(self, node, frame):
1330 if node.ctx == 'store' and frame.toplevel:
1331 frame.toplevel_assignments.add(node.name)
1332 self.write('l_' + node.name)
1333 frame.assigned_names.add(node.name)
1335 def visit_Const(self, node, frame):
1337 if isinstance(val, float):
1338 self.write(str(val))
1340 self.write(repr(val))
1342 def visit_TemplateData(self, node, frame):
1343 self.write(repr(node.as_const()))
1345 def visit_Tuple(self, node, frame):
1348 for idx, item in enumerate(node.items):
1351 self.visit(item, frame)
1352 self.write(idx == 0 and ',)' or ')')
1354 def visit_List(self, node, frame):
1356 for idx, item in enumerate(node.items):
1359 self.visit(item, frame)
1362 def visit_Dict(self, node, frame):
1364 for idx, item in enumerate(node.items):
1367 self.visit(item.key, frame)
1369 self.visit(item.value, frame)
1372 def binop(operator):
1373 def visitor(self, node, frame):
1375 self.visit(node.left, frame)
1376 self.write(' %s ' % operator)
1377 self.visit(node.right, frame)
1382 def visitor(self, node, frame):
1383 self.write('(' + operator)
1384 self.visit(node.node, frame)
1388 visit_Add = binop('+')
1389 visit_Sub = binop('-')
1390 visit_Mul = binop('*')
1391 visit_Div = binop('/')
1392 visit_FloorDiv = binop('//')
1393 visit_Pow = binop('**')
1394 visit_Mod = binop('%')
1395 visit_And = binop('and')
1396 visit_Or = binop('or')
1397 visit_Pos = uaop('+')
1398 visit_Neg = uaop('-')
1399 visit_Not = uaop('not ')
1402 def visit_Concat(self, node, frame):
1403 self.write('%s((' % (self.environment.autoescape and
1404 'markup_join' or 'unicode_join'))
1405 for arg in node.nodes:
1406 self.visit(arg, frame)
1410 def visit_Compare(self, node, frame):
1411 self.visit(node.expr, frame)
1413 self.visit(op, frame)
1415 def visit_Operand(self, node, frame):
1416 self.write(' %s ' % operators[node.op])
1417 self.visit(node.expr, frame)
1419 def visit_Getattr(self, node, frame):
1420 self.write('environment.getattr(')
1421 self.visit(node.node, frame)
1422 self.write(', %r)' % node.attr)
1424 def visit_Getitem(self, node, frame):
1425 # slices bypass the environment getitem method.
1426 if isinstance(node.arg, nodes.Slice):
1427 self.visit(node.node, frame)
1429 self.visit(node.arg, frame)
1432 self.write('environment.getitem(')
1433 self.visit(node.node, frame)
1435 self.visit(node.arg, frame)
1438 def visit_Slice(self, node, frame):
1439 if node.start is not None:
1440 self.visit(node.start, frame)
1442 if node.stop is not None:
1443 self.visit(node.stop, frame)
1444 if node.step is not None:
1446 self.visit(node.step, frame)
1448 def visit_Filter(self, node, frame):
1449 self.write(self.filters[node.name] + '(')
1450 func = self.environment.filters.get(node.name)
1452 self.fail('no filter named %r' % node.name, node.lineno)
1453 if getattr(func, 'contextfilter', False):
1454 self.write('context, ')
1455 elif getattr(func, 'environmentfilter', False):
1456 self.write('environment, ')
1458 # if the filter node is None we are inside a filter block
1459 # and want to write to the current buffer
1460 if node.node is not None:
1461 self.visit(node.node, frame)
1462 elif self.environment.autoescape:
1463 self.write('Markup(concat(%s))' % frame.buffer)
1465 self.write('concat(%s)' % frame.buffer)
1466 self.signature(node, frame)
1469 def visit_Test(self, node, frame):
1470 self.write(self.tests[node.name] + '(')
1471 if node.name not in self.environment.tests:
1472 self.fail('no test named %r' % node.name, node.lineno)
1473 self.visit(node.node, frame)
1474 self.signature(node, frame)
1477 def visit_CondExpr(self, node, frame):
1479 if node.expr2 is not None:
1480 return self.visit(node.expr2, frame)
1481 self.write('environment.undefined(%r)' % ('the inline if-'
1482 'expression on %s evaluated to false and '
1483 'no else section was defined.' % self.position(node)))
1485 if not have_condexpr:
1487 self.visit(node.test, frame)
1488 self.write(') and (')
1489 self.visit(node.expr1, frame)
1490 self.write(',) or (')
1492 self.write(',))[0]')
1495 self.visit(node.expr1, frame)
1497 self.visit(node.test, frame)
1498 self.write(' else ')
1502 def visit_Call(self, node, frame, forward_caller=False):
1503 if self.environment.sandboxed:
1504 self.write('environment.call(context, ')
1506 self.write('context.call(')
1507 self.visit(node.node, frame)
1508 extra_kwargs = forward_caller and {'caller': 'caller'} or None
1509 self.signature(node, frame, extra_kwargs)
1512 def visit_Keyword(self, node, frame):
1513 self.write(node.key + '=')
1514 self.visit(node.value, frame)
1516 # -- Unused nodes for extensions
1518 def visit_MarkSafe(self, node, frame):
1519 self.write('Markup(')
1520 self.visit(node.expr, frame)
1523 def visit_EnvironmentAttribute(self, node, frame):
1524 self.write('environment.' + node.name)
1526 def visit_ExtensionAttribute(self, node, frame):
1527 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
1529 def visit_ImportedName(self, node, frame):
1530 self.write(self.import_aliases[node.importname])
1532 def visit_InternalName(self, node, frame):
1533 self.write(node.name)
1535 def visit_ContextReference(self, node, frame):
1536 self.write('context')
1538 def visit_Continue(self, node, frame):
1539 self.writeline('continue', node)
1541 def visit_Break(self, node, frame):
1542 self.writeline('break', node)
1544 def visit_Scope(self, node, frame):
1545 scope_frame = frame.inner()
1546 scope_frame.inspect(node.iter_child_nodes())
1547 aliases = self.push_scope(scope_frame)
1548 self.pull_locals(scope_frame)
1549 self.blockvisit(node.body, scope_frame)
1550 self.pop_scope(aliases, scope_frame)