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):
57 """Generate the python source for a node tree."""
58 if not isinstance(node, nodes.Template):
59 raise TypeError('Can\'t compile non template nodes')
60 generator = CodeGenerator(environment, name, filename, stream)
63 return generator.stream.getvalue()
66 def has_safe_repr(value):
67 """Does the node have a safe representation?"""
68 if value is None or value is NotImplemented or value is Ellipsis:
70 if isinstance(value, (bool, int, long, float, complex, basestring,
73 if isinstance(value, (tuple, list, set, frozenset)):
75 if not has_safe_repr(item):
78 elif isinstance(value, dict):
79 for key, value in value.iteritems():
80 if not has_safe_repr(key):
82 if not has_safe_repr(value):
88 def find_undeclared(nodes, names):
89 """Check if the names passed are accessed undeclared. The return value
90 is a set of all the undeclared names from the sequence of names found.
92 visitor = UndeclaredNameVisitor(names)
98 return visitor.undeclared
101 class Identifiers(object):
102 """Tracks the status of identifiers in frames."""
105 # variables that are known to be declared (probably from outer
106 # frames or because they are special for the frame)
107 self.declared = set()
109 # undeclared variables from outer scopes
110 self.outer_undeclared = set()
112 # names that are accessed without being explicitly declared by
113 # this one or any of the outer scopes. Names can appear both in
114 # declared and undeclared.
115 self.undeclared = set()
117 # names that are declared locally
118 self.declared_locally = set()
120 # names that are declared by parameters
121 self.declared_parameter = set()
123 def add_special(self, name):
124 """Register a special name like `loop`."""
125 self.undeclared.discard(name)
126 self.declared.add(name)
128 def is_declared(self, name, local_only=False):
129 """Check if a name is declared in this or an outer scope."""
130 if name in self.declared_locally or name in self.declared_parameter:
134 return name in self.declared
137 return deepcopy(self)
141 """Holds compile time information for us."""
143 def __init__(self, parent=None):
144 self.identifiers = Identifiers()
146 # a toplevel frame is the root + soft frames such as if conditions.
147 self.toplevel = False
149 # the root frame is basically just the outermost frame, so no if
150 # conditions. This information is used to optimize inheritance
152 self.rootlevel = False
154 # in some dynamic inheritance situations the compiler needs to add
155 # write tests around output statements.
156 self.require_output_check = parent and parent.require_output_check
158 # inside some tags we are using a buffer rather than yield statements.
159 # this for example affects {% filter %} or {% macro %}. If a frame
160 # is buffered this variable points to the name of the list used as
164 # the name of the block we're in, otherwise None.
165 self.block = parent and parent.block or None
167 # a set of actually assigned names
168 self.assigned_names = set()
170 # the parent of this frame
173 if parent is not None:
174 self.identifiers.declared.update(
175 parent.identifiers.declared |
176 parent.identifiers.declared_parameter |
177 parent.assigned_names
179 self.identifiers.outer_undeclared.update(
180 parent.identifiers.undeclared -
181 self.identifiers.declared
183 self.buffer = parent.buffer
186 """Create a copy of the current one."""
187 rv = object.__new__(self.__class__)
188 rv.__dict__.update(self.__dict__)
189 rv.identifiers = object.__new__(self.identifiers.__class__)
190 rv.identifiers.__dict__.update(self.identifiers.__dict__)
193 def inspect(self, nodes, hard_scope=False):
194 """Walk the node and check for identifiers. If the scope is hard (eg:
195 enforce on a python level) overrides from outer scopes are tracked
198 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
202 def find_shadowed(self, extra=()):
203 """Find all the shadowed names. extra is an iterable of variables
204 that may be defined with `add_special` which may occour scoped.
207 return (i.declared | i.outer_undeclared) & \
208 (i.declared_locally | i.declared_parameter) | \
209 set(x for x in extra if i.is_declared(x))
212 """Return an inner frame."""
216 """Return a soft frame. A soft frame may not be modified as
217 standalone thing as it shares the resources with the frame it
218 was created of, but it's not a rootlevel frame any longer.
227 class VisitorExit(RuntimeError):
228 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
231 class DependencyFinderVisitor(NodeVisitor):
232 """A visitor that collects filter and test calls."""
238 def visit_Filter(self, node):
239 self.generic_visit(node)
240 self.filters.add(node.name)
242 def visit_Test(self, node):
243 self.generic_visit(node)
244 self.tests.add(node.name)
246 def visit_Block(self, node):
247 """Stop visiting at blocks."""
250 class UndeclaredNameVisitor(NodeVisitor):
251 """A visitor that checks if a name is accessed without being
252 declared. This is different from the frame visitor as it will
253 not stop at closure frames.
256 def __init__(self, names):
257 self.names = set(names)
258 self.undeclared = set()
260 def visit_Name(self, node):
261 if node.ctx == 'load' and node.name in self.names:
262 self.undeclared.add(node.name)
263 if self.undeclared == self.names:
266 self.names.discard(node.name)
268 def visit_Block(self, node):
269 """Stop visiting a blocks."""
272 class FrameIdentifierVisitor(NodeVisitor):
273 """A visitor for `Frame.inspect`."""
275 def __init__(self, identifiers, hard_scope):
276 self.identifiers = identifiers
277 self.hard_scope = hard_scope
279 def visit_Name(self, node):
280 """All assignments to names go through this function."""
281 if node.ctx == 'store':
282 self.identifiers.declared_locally.add(node.name)
283 elif node.ctx == 'param':
284 self.identifiers.declared_parameter.add(node.name)
285 elif node.ctx == 'load' and not \
286 self.identifiers.is_declared(node.name, self.hard_scope):
287 self.identifiers.undeclared.add(node.name)
289 def visit_If(self, node):
290 self.visit(node.test)
291 real_identifiers = self.identifiers
293 old_names = real_identifiers.declared | \
294 real_identifiers.declared_locally | \
295 real_identifiers.declared_parameter
297 def inner_visit(nodes):
300 self.identifiers = real_identifiers.copy()
301 for subnode in nodes:
303 rv = self.identifiers.declared_locally - old_names
304 # we have to remember the undeclared variables of this branch
305 # because we will have to pull them.
306 real_identifiers.undeclared.update(self.identifiers.undeclared)
307 self.identifiers = real_identifiers
310 body = inner_visit(node.body)
311 else_ = inner_visit(node.else_ or ())
313 # the differences between the two branches are also pulled as
314 # undeclared variables
315 real_identifiers.undeclared.update(body.symmetric_difference(else_))
317 # remember those that are declared.
318 real_identifiers.declared_locally.update(body | else_)
320 def visit_Macro(self, node):
321 self.identifiers.declared_locally.add(node.name)
323 def visit_Import(self, node):
324 self.generic_visit(node)
325 self.identifiers.declared_locally.add(node.target)
327 def visit_FromImport(self, node):
328 self.generic_visit(node)
329 for name in node.names:
330 if isinstance(name, tuple):
331 self.identifiers.declared_locally.add(name[1])
333 self.identifiers.declared_locally.add(name)
335 def visit_Assign(self, node):
336 """Visit assignments in the correct order."""
337 self.visit(node.node)
338 self.visit(node.target)
340 def visit_For(self, node):
341 """Visiting stops at for blocks. However the block sequence
342 is visited as part of the outer scope.
344 self.visit(node.iter)
346 def visit_CallBlock(self, node):
347 self.visit(node.call)
349 def visit_FilterBlock(self, node):
350 self.visit(node.filter)
352 def visit_Scope(self, node):
353 """Stop visiting at scopes."""
355 def visit_Block(self, node):
356 """Stop visiting at blocks."""
359 class CompilerExit(Exception):
360 """Raised if the compiler encountered a situation where it just
361 doesn't make sense to further process the code. Any block that
362 raises such an exception is not further processed.
366 class CodeGenerator(NodeVisitor):
368 def __init__(self, environment, name, filename, stream=None):
371 self.environment = environment
373 self.filename = filename
375 self.created_block_context = False
377 # aliases for imports
378 self.import_aliases = {}
380 # a registry for all blocks. Because blocks are moved out
381 # into the global python scope they are registered here
384 # the number of extends statements so far
385 self.extends_so_far = 0
387 # some templates have a rootlevel extends. In this case we
388 # can safely assume that we're a child template and do some
389 # more optimizations.
390 self.has_known_extends = False
392 # the current line number
395 # registry of all filters and tests (global, not block local)
399 # the debug information
401 self._write_debug_info = None
403 # the number of new lines before the next write()
406 # the line number of the last written statement
409 # true if nothing was written so far.
410 self._first_write = True
412 # used by the `temporary_identifier` method to get new
413 # unique, temporary identifier
414 self._last_identifier = 0
416 # the current indentation
417 self._indentation = 0
419 # -- Various compilation helpers
421 def fail(self, msg, lineno):
422 """Fail with a `TemplateAssertionError`."""
423 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
425 def temporary_identifier(self):
426 """Get a new unique identifier."""
427 self._last_identifier += 1
428 return 't_%d' % self._last_identifier
430 def buffer(self, frame):
431 """Enable buffering for the frame from that point onwards."""
432 frame.buffer = self.temporary_identifier()
433 self.writeline('%s = []' % frame.buffer)
435 def return_buffer_contents(self, frame):
436 """Return the buffer contents of the frame."""
437 if self.environment.autoescape:
438 self.writeline('return Markup(concat(%s))' % frame.buffer)
440 self.writeline('return concat(%s)' % frame.buffer)
444 self._indentation += 1
446 def outdent(self, step=1):
447 """Outdent by step."""
448 self._indentation -= step
450 def start_write(self, frame, node=None):
451 """Yield or write into the frame buffer."""
452 if frame.buffer is None:
453 self.writeline('yield ', node)
455 self.writeline('%s.append(' % frame.buffer, node)
457 def end_write(self, frame):
458 """End the writing process started by `start_write`."""
459 if frame.buffer is not None:
462 def simple_write(self, s, frame, node=None):
463 """Simple shortcut for start_write + write + end_write."""
464 self.start_write(frame, node)
466 self.end_write(frame)
468 def blockvisit(self, nodes, frame):
469 """Visit a list of nodes as block in a frame. If the current frame
470 is no buffer a dummy ``if 0: yield None`` is written automatically
471 unless the force_generator parameter is set to False.
473 if frame.buffer is None:
474 self.writeline('if 0: yield None')
476 self.writeline('pass')
479 self.visit(node, frame)
484 """Write a string into the output stream."""
486 if not self._first_write:
487 self.stream.write('\n' * self._new_lines)
488 self.code_lineno += self._new_lines
489 if self._write_debug_info is not None:
490 self.debug_info.append((self._write_debug_info,
492 self._write_debug_info = None
493 self._first_write = False
494 self.stream.write(' ' * self._indentation)
498 def writeline(self, x, node=None, extra=0):
499 """Combination of newline and write."""
500 self.newline(node, extra)
503 def newline(self, node=None, extra=0):
504 """Add one or more newlines before the next write."""
505 self._new_lines = max(self._new_lines, 1 + extra)
506 if node is not None and node.lineno != self._last_line:
507 self._write_debug_info = node.lineno
508 self._last_line = node.lineno
510 def signature(self, node, frame, extra_kwargs=None):
511 """Writes a function call to the stream for the current node.
512 A leading comma is added automatically. The extra keyword
513 arguments may not include python keywords otherwise a syntax
514 error could occour. The extra keyword arguments should be given
517 # if any of the given keyword arguments is a python keyword
518 # we have to make sure that no invalid call is created.
519 kwarg_workaround = False
520 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
521 if is_python_keyword(kwarg):
522 kwarg_workaround = True
525 for arg in node.args:
527 self.visit(arg, frame)
529 if not kwarg_workaround:
530 for kwarg in node.kwargs:
532 self.visit(kwarg, frame)
533 if extra_kwargs is not None:
534 for key, value in extra_kwargs.iteritems():
535 self.write(', %s=%s' % (key, value))
538 self.visit(node.dyn_args, frame)
541 if node.dyn_kwargs is not None:
542 self.write(', **dict({')
545 for kwarg in node.kwargs:
546 self.write('%r: ' % kwarg.key)
547 self.visit(kwarg.value, frame)
549 if extra_kwargs is not None:
550 for key, value in extra_kwargs.iteritems():
551 self.write('%r: %s, ' % (key, value))
552 if node.dyn_kwargs is not None:
554 self.visit(node.dyn_kwargs, frame)
559 elif node.dyn_kwargs is not None:
561 self.visit(node.dyn_kwargs, frame)
563 def pull_locals(self, frame):
564 """Pull all the references identifiers into the local scope."""
565 for name in frame.identifiers.undeclared:
566 self.writeline('l_%s = context.resolve(%r)' % (name, name))
568 def pull_dependencies(self, nodes):
569 """Pull all the dependencies."""
570 visitor = DependencyFinderVisitor()
573 for dependency in 'filters', 'tests':
574 mapping = getattr(self, dependency)
575 for name in getattr(visitor, dependency):
576 if name not in mapping:
577 mapping[name] = self.temporary_identifier()
578 self.writeline('%s = environment.%s[%r]' %
579 (mapping[name], dependency, name))
581 def unoptimize_scope(self, frame):
582 """Disable Python optimizations for the frame."""
583 # XXX: this is not that nice but it has no real overhead. It
584 # mainly works because python finds the locals before dead code
585 # is removed. If that breaks we have to add a dummy function
586 # that just accepts the arguments and does nothing.
587 if frame.identifiers.declared:
588 self.writeline('%sdummy(%s)' % (
589 unoptimize_before_dead_code and 'if 0: ' or '',
590 ', '.join('l_' + name for name in frame.identifiers.declared)
593 def push_scope(self, frame, extra_vars=()):
594 """This function returns all the shadowed variables in a dict
595 in the form name: alias and will write the required assignments
596 into the current scope. No indentation takes place.
598 This also predefines locally declared variables from the loop
599 body because under some circumstances it may be the case that
601 `extra_vars` is passed to `Frame.find_shadowed`.
604 for name in frame.find_shadowed(extra_vars):
605 aliases[name] = ident = self.temporary_identifier()
606 self.writeline('%s = l_%s' % (ident, name))
608 for name in frame.identifiers.declared_locally:
609 if name not in aliases:
610 to_declare.add('l_' + name)
612 self.writeline(' = '.join(to_declare) + ' = missing')
615 def pop_scope(self, aliases, frame):
616 """Restore all aliases and delete unused variables."""
617 for name, alias in aliases.iteritems():
618 self.writeline('l_%s = %s' % (name, alias))
620 for name in frame.identifiers.declared_locally:
621 if name not in aliases:
622 to_delete.add('l_' + name)
624 # we cannot use the del statement here because enclosed
625 # scopes can trigger a SyntaxError:
626 # a = 42; b = lambda: a; del a
627 self.writeline(' = '.join(to_delete) + ' = missing')
629 def function_scoping(self, node, frame, children=None,
631 """In Jinja a few statements require the help of anonymous
632 functions. Those are currently macros and call blocks and in
633 the future also recursive loops. As there is currently
634 technical limitation that doesn't allow reading and writing a
635 variable in a scope where the initial value is coming from an
636 outer scope, this function tries to fall back with a common
637 error message. Additionally the frame passed is modified so
638 that the argumetns are collected and callers are looked up.
640 This will return the modified frame.
642 # we have to iterate twice over it, make sure that works
644 children = node.iter_child_nodes()
645 children = list(children)
646 func_frame = frame.inner()
647 func_frame.inspect(children, hard_scope=True)
649 # variables that are undeclared (accessed before declaration) and
650 # declared locally *and* part of an outside scope raise a template
651 # assertion error. Reason: we can't generate reasonable code from
652 # it without aliasing all the variables.
653 # this could be fixed in Python 3 where we have the nonlocal
654 # keyword or if we switch to bytecode generation
655 overriden_closure_vars = (
656 func_frame.identifiers.undeclared &
657 func_frame.identifiers.declared &
658 (func_frame.identifiers.declared_locally |
659 func_frame.identifiers.declared_parameter)
661 if overriden_closure_vars:
662 self.fail('It\'s not possible to set and access variables '
663 'derived from an outer scope! (affects: %s)' %
664 ', '.join(sorted(overriden_closure_vars)), node.lineno)
666 # remove variables from a closure from the frame's undeclared
668 func_frame.identifiers.undeclared -= (
669 func_frame.identifiers.undeclared &
670 func_frame.identifiers.declared
673 # no special variables for this scope, abort early
677 func_frame.accesses_kwargs = False
678 func_frame.accesses_varargs = False
679 func_frame.accesses_caller = False
680 func_frame.arguments = args = ['l_' + x.name for x in node.args]
682 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
684 if 'caller' in undeclared:
685 func_frame.accesses_caller = True
686 func_frame.identifiers.add_special('caller')
687 args.append('l_caller')
688 if 'kwargs' in undeclared:
689 func_frame.accesses_kwargs = True
690 func_frame.identifiers.add_special('kwargs')
691 args.append('l_kwargs')
692 if 'varargs' in undeclared:
693 func_frame.accesses_varargs = True
694 func_frame.identifiers.add_special('varargs')
695 args.append('l_varargs')
698 def macro_body(self, node, frame, children=None):
699 """Dump the function def of a macro or call block."""
700 frame = self.function_scoping(node, frame, children)
701 # macros are delayed, they never require output checks
702 frame.require_output_check = False
703 args = frame.arguments
704 # XXX: this is an ugly fix for the loop nesting bug
705 # (tests.test_old_bugs.test_loop_call_bug). This works around
706 # a identifier nesting problem we have in general. It's just more
707 # likely to happen in loops which is why we work around it. The
708 # real solution would be "nonlocal" all the identifiers that are
709 # leaking into a new python frame and might be used both unassigned
711 if 'loop' in frame.identifiers.declared:
712 args = args + ['l_loop=l_loop']
713 self.writeline('def macro(%s):' % ', '.join(args), node)
716 self.pull_locals(frame)
717 self.blockvisit(node.body, frame)
718 self.return_buffer_contents(frame)
722 def macro_def(self, node, frame):
723 """Dump the macro definition for the def created by macro_body."""
724 arg_tuple = ', '.join(repr(x.name) for x in node.args)
725 name = getattr(node, 'name', None)
726 if len(node.args) == 1:
728 self.write('Macro(environment, macro, %r, (%s), (' %
730 for arg in node.defaults:
731 self.visit(arg, frame)
733 self.write('), %r, %r, %r)' % (
734 bool(frame.accesses_kwargs),
735 bool(frame.accesses_varargs),
736 bool(frame.accesses_caller)
739 def position(self, node):
740 """Return a human readable position for the node."""
741 rv = 'line %d' % node.lineno
742 if self.name is not None:
743 rv += ' in ' + repr(self.name)
746 # -- Statement Visitors
748 def visit_Template(self, node, frame=None):
749 assert frame is None, 'no root frame allowed'
750 from jinja2.runtime import __all__ as exported
751 self.writeline('from __future__ import division')
752 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
753 if not unoptimize_before_dead_code:
754 self.writeline('dummy = lambda *x: None')
756 # do we have an extends tag at all? If not, we can save some
757 # overhead by just not processing any inheritance code.
758 have_extends = node.find(nodes.Extends) is not None
761 for block in node.find_all(nodes.Block):
762 if block.name in self.blocks:
763 self.fail('block %r defined twice' % block.name, block.lineno)
764 self.blocks[block.name] = block
766 # find all imports and import them
767 for import_ in node.find_all(nodes.ImportedName):
768 if import_.importname not in self.import_aliases:
769 imp = import_.importname
770 self.import_aliases[imp] = alias = self.temporary_identifier()
772 module, obj = imp.rsplit('.', 1)
773 self.writeline('from %s import %s as %s' %
774 (module, obj, alias))
776 self.writeline('import %s as %s' % (imp, alias))
779 self.writeline('name = %r' % self.name)
781 # generate the root render function.
782 self.writeline('def root(context, environment=environment):', extra=1)
786 frame.inspect(node.body)
787 frame.toplevel = frame.rootlevel = True
788 frame.require_output_check = have_extends and not self.has_known_extends
791 self.writeline('parent_template = None')
792 if 'self' in find_undeclared(node.body, ('self',)):
793 frame.identifiers.add_special('self')
794 self.writeline('l_self = TemplateReference(context)')
795 self.pull_locals(frame)
796 self.pull_dependencies(node.body)
797 self.blockvisit(node.body, frame)
800 # make sure that the parent root is called.
802 if not self.has_known_extends:
804 self.writeline('if parent_template is not None:')
806 self.writeline('for event in parent_template.'
807 'root_render_func(context):')
809 self.writeline('yield event')
810 self.outdent(2 + (not self.has_known_extends))
812 # at this point we now have the blocks collected and can visit them too.
813 for name, block in self.blocks.iteritems():
814 block_frame = Frame()
815 block_frame.inspect(block.body)
816 block_frame.block = name
817 self.writeline('def block_%s(context, environment=environment):'
820 undeclared = find_undeclared(block.body, ('self', 'super'))
821 if 'self' in undeclared:
822 block_frame.identifiers.add_special('self')
823 self.writeline('l_self = TemplateReference(context)')
824 if 'super' in undeclared:
825 block_frame.identifiers.add_special('super')
826 self.writeline('l_super = context.super(%r, '
827 'block_%s)' % (name, name))
828 self.pull_locals(block_frame)
829 self.pull_dependencies(block.body)
830 self.blockvisit(block.body, block_frame)
833 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
834 for x in self.blocks),
837 # add a function that returns the debug info
838 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
841 def visit_Block(self, node, frame):
842 """Call a block and register it for the template."""
845 # if we know that we are a child template, there is no need to
846 # check if we are one
847 if self.has_known_extends:
849 if self.extends_so_far > 0:
850 self.writeline('if parent_template is None:')
853 context = node.scoped and 'context.derived(locals())' or 'context'
854 self.writeline('for event in context.blocks[%r][0](%s):' % (
855 node.name, context), node)
857 self.simple_write('event', frame)
860 def visit_Extends(self, node, frame):
861 """Calls the extender."""
862 if not frame.toplevel:
863 self.fail('cannot use extend from a non top-level scope',
866 # if the number of extends statements in general is zero so
867 # far, we don't have to add a check if something extended
868 # the template before this one.
869 if self.extends_so_far > 0:
871 # if we have a known extends we just add a template runtime
872 # error into the generated code. We could catch that at compile
873 # time too, but i welcome it not to confuse users by throwing the
874 # same error at different times just "because we can".
875 if not self.has_known_extends:
876 self.writeline('if parent_template is not None:')
878 self.writeline('raise TemplateRuntimeError(%r)' %
879 'extended multiple times')
882 # if we have a known extends already we don't need that code here
883 # as we know that the template execution will end here.
884 if self.has_known_extends:
887 self.writeline('parent_template = environment.get_template(', node)
888 self.visit(node.template, frame)
889 self.write(', %r)' % self.name)
890 self.writeline('for name, parent_block in parent_template.'
891 'blocks.%s():' % dict_item_iter)
893 self.writeline('context.blocks.setdefault(name, []).'
894 'append(parent_block)')
897 # if this extends statement was in the root level we can take
898 # advantage of that information and simplify the generated code
899 # in the top level from this point onwards
901 self.has_known_extends = True
903 # and now we have one more
904 self.extends_so_far += 1
906 def visit_Include(self, node, frame):
907 """Handles includes."""
908 if node.with_context:
909 self.unoptimize_scope(frame)
910 if node.ignore_missing:
911 self.writeline('try:')
914 func_name = 'get_or_select_template'
915 if isinstance(node.template, nodes.Const):
916 if isinstance(node.template.value, basestring):
917 func_name = 'get_template'
918 elif isinstance(node.template.value, (tuple, list)):
919 func_name = 'select_template'
920 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
921 func_name = 'select_template'
923 self.writeline('template = environment.%s(' % func_name, node)
924 self.visit(node.template, frame)
925 self.write(', %r)' % self.name)
926 if node.ignore_missing:
928 self.writeline('except TemplateNotFound:')
930 self.writeline('pass')
932 self.writeline('else:')
935 if node.with_context:
936 self.writeline('for event in template.root_render_func('
937 'template.new_context(context.parent, True, '
940 self.writeline('for event in template.module._body_stream:')
943 self.simple_write('event', frame)
946 if node.ignore_missing:
949 def visit_Import(self, node, frame):
950 """Visit regular imports."""
951 if node.with_context:
952 self.unoptimize_scope(frame)
953 self.writeline('l_%s = ' % node.target, node)
955 self.write('context.vars[%r] = ' % node.target)
956 self.write('environment.get_template(')
957 self.visit(node.template, frame)
958 self.write(', %r).' % self.name)
959 if node.with_context:
960 self.write('make_module(context.parent, True, locals())')
963 if frame.toplevel and not node.target.startswith('_'):
964 self.writeline('context.exported_vars.discard(%r)' % node.target)
965 frame.assigned_names.add(node.target)
967 def visit_FromImport(self, node, frame):
968 """Visit named imports."""
970 self.write('included_template = environment.get_template(')
971 self.visit(node.template, frame)
972 self.write(', %r).' % self.name)
973 if node.with_context:
974 self.write('make_module(context.parent, True)')
980 for name in node.names:
981 if isinstance(name, tuple):
985 self.writeline('l_%s = getattr(included_template, '
986 '%r, missing)' % (alias, name))
987 self.writeline('if l_%s is missing:' % alias)
989 self.writeline('l_%s = environment.undefined(%r %% '
990 'included_template.__name__, '
992 (alias, 'the template %%r (imported on %s) does '
993 'not export the requested name %s' % (
999 var_names.append(alias)
1000 if not alias.startswith('_'):
1001 discarded_names.append(alias)
1002 frame.assigned_names.add(alias)
1005 if len(var_names) == 1:
1007 self.writeline('context.vars[%r] = l_%s' % (name, name))
1009 self.writeline('context.vars.update({%s})' % ', '.join(
1010 '%r: l_%s' % (name, name) for name in var_names
1013 if len(discarded_names) == 1:
1014 self.writeline('context.exported_vars.discard(%r)' %
1017 self.writeline('context.exported_vars.difference_'
1018 'update((%s))' % ', '.join(map(repr, discarded_names)))
1020 def visit_For(self, node, frame):
1021 # when calculating the nodes for the inner frame we have to exclude
1022 # the iterator contents from it
1023 children = node.iter_child_nodes(exclude=('iter',))
1025 loop_frame = self.function_scoping(node, frame, children,
1028 loop_frame = frame.inner()
1029 loop_frame.inspect(children)
1031 # try to figure out if we have an extended loop. An extended loop
1032 # is necessary if the loop is in recursive mode if the special loop
1033 # variable is accessed in the body.
1034 extended_loop = node.recursive or 'loop' in \
1035 find_undeclared(node.iter_child_nodes(
1036 only=('body',)), ('loop',))
1038 # if we don't have an recursive loop we have to find the shadowed
1039 # variables at that point. Because loops can be nested but the loop
1040 # variable is a special one we have to enforce aliasing for it.
1041 if not node.recursive:
1042 aliases = self.push_scope(loop_frame, ('loop',))
1044 # otherwise we set up a buffer and add a function def
1046 self.writeline('def loop(reciter, loop_render_func):', node)
1048 self.buffer(loop_frame)
1051 # make sure the loop variable is a special one and raise a template
1052 # assertion error if a loop tries to write to loop
1054 loop_frame.identifiers.add_special('loop')
1055 for name in node.find_all(nodes.Name):
1056 if name.ctx == 'store' and name.name == 'loop':
1057 self.fail('Can\'t assign to special loop variable '
1058 'in for-loop target', name.lineno)
1060 self.pull_locals(loop_frame)
1062 iteration_indicator = self.temporary_identifier()
1063 self.writeline('%s = 1' % iteration_indicator)
1065 # Create a fake parent loop if the else or test section of a
1066 # loop is accessing the special loop variable and no parent loop
1068 if 'loop' not in aliases and 'loop' in find_undeclared(
1069 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1070 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
1071 ("'loop' is undefined. the filter section of a loop as well "
1072 "as the else block doesn't have access to the special 'loop'"
1073 " variable of the current loop. Because there is no parent "
1074 "loop it's undefined. Happened in loop on %s" %
1075 self.position(node)))
1077 self.writeline('for ', node)
1078 self.visit(node.target, loop_frame)
1079 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
1081 # if we have an extened loop and a node test, we filter in the
1083 if extended_loop and node.test is not None:
1085 self.visit(node.target, loop_frame)
1087 self.visit(node.target, loop_frame)
1090 self.write('reciter')
1092 self.visit(node.iter, loop_frame)
1094 test_frame = loop_frame.copy()
1095 self.visit(node.test, test_frame)
1098 elif node.recursive:
1099 self.write('reciter')
1101 self.visit(node.iter, loop_frame)
1104 self.write(', recurse=loop_render_func):')
1106 self.write(extended_loop and '):' or ':')
1108 # tests in not extended loops become a continue
1109 if not extended_loop and node.test is not None:
1111 self.writeline('if not ')
1112 self.visit(node.test, loop_frame)
1115 self.writeline('continue')
1119 self.blockvisit(node.body, loop_frame)
1121 self.writeline('%s = 0' % iteration_indicator)
1125 self.writeline('if %s:' % iteration_indicator)
1127 self.blockvisit(node.else_, loop_frame)
1130 # reset the aliases if there are any.
1131 if not node.recursive:
1132 self.pop_scope(aliases, loop_frame)
1134 # if the node was recursive we have to return the buffer contents
1135 # and start the iteration code
1137 self.return_buffer_contents(loop_frame)
1139 self.start_write(frame, node)
1141 self.visit(node.iter, frame)
1142 self.write(', loop)')
1143 self.end_write(frame)
1145 def visit_If(self, node, frame):
1146 if_frame = frame.soft()
1147 self.writeline('if ', node)
1148 self.visit(node.test, if_frame)
1151 self.blockvisit(node.body, if_frame)
1154 self.writeline('else:')
1156 self.blockvisit(node.else_, if_frame)
1159 def visit_Macro(self, node, frame):
1160 macro_frame = self.macro_body(node, frame)
1163 if not node.name.startswith('_'):
1164 self.write('context.exported_vars.add(%r)' % node.name)
1165 self.writeline('context.vars[%r] = ' % node.name)
1166 self.write('l_%s = ' % node.name)
1167 self.macro_def(node, macro_frame)
1168 frame.assigned_names.add(node.name)
1170 def visit_CallBlock(self, node, frame):
1171 children = node.iter_child_nodes(exclude=('call',))
1172 call_frame = self.macro_body(node, frame, children)
1173 self.writeline('caller = ')
1174 self.macro_def(node, call_frame)
1175 self.start_write(frame, node)
1176 self.visit_Call(node.call, call_frame, forward_caller=True)
1177 self.end_write(frame)
1179 def visit_FilterBlock(self, node, frame):
1180 filter_frame = frame.inner()
1181 filter_frame.inspect(node.iter_child_nodes())
1182 aliases = self.push_scope(filter_frame)
1183 self.pull_locals(filter_frame)
1184 self.buffer(filter_frame)
1185 self.blockvisit(node.body, filter_frame)
1186 self.start_write(frame, node)
1187 self.visit_Filter(node.filter, filter_frame)
1188 self.end_write(frame)
1189 self.pop_scope(aliases, filter_frame)
1191 def visit_ExprStmt(self, node, frame):
1193 self.visit(node.node, frame)
1195 def visit_Output(self, node, frame):
1196 # if we have a known extends statement, we don't output anything
1197 # if we are in a require_output_check section
1198 if self.has_known_extends and frame.require_output_check:
1201 if self.environment.finalize:
1202 finalize = lambda x: unicode(self.environment.finalize(x))
1208 # if we are inside a frame that requires output checking, we do so
1209 outdent_later = False
1210 if frame.require_output_check:
1211 self.writeline('if parent_template is None:')
1213 outdent_later = True
1215 # try to evaluate as many chunks as possible into a static
1216 # string at compile time.
1218 for child in node.nodes:
1220 const = child.as_const()
1221 except nodes.Impossible:
1225 if self.environment.autoescape:
1226 if hasattr(const, '__html__'):
1227 const = const.__html__()
1229 const = escape(const)
1230 const = finalize(const)
1232 # if something goes wrong here we evaluate the node
1233 # at runtime for easier debugging
1236 if body and isinstance(body[-1], list):
1237 body[-1].append(const)
1239 body.append([const])
1241 # if we have less than 3 nodes or a buffer we yield or extend/append
1242 if len(body) < 3 or frame.buffer is not None:
1243 if frame.buffer is not None:
1244 # for one item we append, for more we extend
1246 self.writeline('%s.append(' % frame.buffer)
1248 self.writeline('%s.extend((' % frame.buffer)
1251 if isinstance(item, list):
1252 val = repr(concat(item))
1253 if frame.buffer is None:
1254 self.writeline('yield ' + val)
1256 self.writeline(val + ', ')
1258 if frame.buffer is None:
1259 self.writeline('yield ', item)
1263 if self.environment.autoescape:
1264 self.write('escape(')
1266 self.write('to_string(')
1267 if self.environment.finalize is not None:
1268 self.write('environment.finalize(')
1270 self.visit(item, frame)
1271 self.write(')' * close)
1272 if frame.buffer is not None:
1274 if frame.buffer is not None:
1275 # close the open parentheses
1277 self.writeline(len(body) == 1 and ')' or '))')
1279 # otherwise we create a format string as this is faster in that case
1284 if isinstance(item, list):
1285 format.append(concat(item).replace('%', '%%'))
1288 arguments.append(item)
1289 self.writeline('yield ')
1290 self.write(repr(concat(format)) + ' % (')
1293 for argument in arguments:
1294 self.newline(argument)
1296 if self.environment.autoescape:
1297 self.write('escape(')
1299 if self.environment.finalize is not None:
1300 self.write('environment.finalize(')
1302 self.visit(argument, frame)
1303 self.write(')' * close + ', ')
1310 def visit_Assign(self, node, frame):
1312 # toplevel assignments however go into the local namespace and
1313 # the current template's context. We create a copy of the frame
1314 # here and add a set so that the Name visitor can add the assigned
1317 assignment_frame = frame.copy()
1318 assignment_frame.toplevel_assignments = set()
1320 assignment_frame = frame
1321 self.visit(node.target, assignment_frame)
1323 self.visit(node.node, frame)
1325 # make sure toplevel assignments are added to the context.
1327 public_names = [x for x in assignment_frame.toplevel_assignments
1328 if not x.startswith('_')]
1329 if len(assignment_frame.toplevel_assignments) == 1:
1330 name = next(iter(assignment_frame.toplevel_assignments))
1331 self.writeline('context.vars[%r] = l_%s' % (name, name))
1333 self.writeline('context.vars.update({')
1334 for idx, name in enumerate(assignment_frame.toplevel_assignments):
1337 self.write('%r: l_%s' % (name, name))
1340 if len(public_names) == 1:
1341 self.writeline('context.exported_vars.add(%r)' %
1344 self.writeline('context.exported_vars.update((%s))' %
1345 ', '.join(map(repr, public_names)))
1347 # -- Expression Visitors
1349 def visit_Name(self, node, frame):
1350 if node.ctx == 'store' and frame.toplevel:
1351 frame.toplevel_assignments.add(node.name)
1352 self.write('l_' + node.name)
1353 frame.assigned_names.add(node.name)
1355 def visit_Const(self, node, frame):
1357 if isinstance(val, float):
1358 self.write(str(val))
1360 self.write(repr(val))
1362 def visit_TemplateData(self, node, frame):
1363 self.write(repr(node.as_const()))
1365 def visit_Tuple(self, node, frame):
1368 for idx, item in enumerate(node.items):
1371 self.visit(item, frame)
1372 self.write(idx == 0 and ',)' or ')')
1374 def visit_List(self, node, frame):
1376 for idx, item in enumerate(node.items):
1379 self.visit(item, frame)
1382 def visit_Dict(self, node, frame):
1384 for idx, item in enumerate(node.items):
1387 self.visit(item.key, frame)
1389 self.visit(item.value, frame)
1392 def binop(operator):
1393 def visitor(self, node, frame):
1395 self.visit(node.left, frame)
1396 self.write(' %s ' % operator)
1397 self.visit(node.right, frame)
1402 def visitor(self, node, frame):
1403 self.write('(' + operator)
1404 self.visit(node.node, frame)
1408 visit_Add = binop('+')
1409 visit_Sub = binop('-')
1410 visit_Mul = binop('*')
1411 visit_Div = binop('/')
1412 visit_FloorDiv = binop('//')
1413 visit_Pow = binop('**')
1414 visit_Mod = binop('%')
1415 visit_And = binop('and')
1416 visit_Or = binop('or')
1417 visit_Pos = uaop('+')
1418 visit_Neg = uaop('-')
1419 visit_Not = uaop('not ')
1422 def visit_Concat(self, node, frame):
1423 self.write('%s((' % (self.environment.autoescape and
1424 'markup_join' or 'unicode_join'))
1425 for arg in node.nodes:
1426 self.visit(arg, frame)
1430 def visit_Compare(self, node, frame):
1431 self.visit(node.expr, frame)
1433 self.visit(op, frame)
1435 def visit_Operand(self, node, frame):
1436 self.write(' %s ' % operators[node.op])
1437 self.visit(node.expr, frame)
1439 def visit_Getattr(self, node, frame):
1440 self.write('environment.getattr(')
1441 self.visit(node.node, frame)
1442 self.write(', %r)' % node.attr)
1444 def visit_Getitem(self, node, frame):
1445 # slices bypass the environment getitem method.
1446 if isinstance(node.arg, nodes.Slice):
1447 self.visit(node.node, frame)
1449 self.visit(node.arg, frame)
1452 self.write('environment.getitem(')
1453 self.visit(node.node, frame)
1455 self.visit(node.arg, frame)
1458 def visit_Slice(self, node, frame):
1459 if node.start is not None:
1460 self.visit(node.start, frame)
1462 if node.stop is not None:
1463 self.visit(node.stop, frame)
1464 if node.step is not None:
1466 self.visit(node.step, frame)
1468 def visit_Filter(self, node, frame):
1469 self.write(self.filters[node.name] + '(')
1470 func = self.environment.filters.get(node.name)
1472 self.fail('no filter named %r' % node.name, node.lineno)
1473 if getattr(func, 'contextfilter', False):
1474 self.write('context, ')
1475 elif getattr(func, 'environmentfilter', False):
1476 self.write('environment, ')
1478 # if the filter node is None we are inside a filter block
1479 # and want to write to the current buffer
1480 if node.node is not None:
1481 self.visit(node.node, frame)
1482 elif self.environment.autoescape:
1483 self.write('Markup(concat(%s))' % frame.buffer)
1485 self.write('concat(%s)' % frame.buffer)
1486 self.signature(node, frame)
1489 def visit_Test(self, node, frame):
1490 self.write(self.tests[node.name] + '(')
1491 if node.name not in self.environment.tests:
1492 self.fail('no test named %r' % node.name, node.lineno)
1493 self.visit(node.node, frame)
1494 self.signature(node, frame)
1497 def visit_CondExpr(self, node, frame):
1499 if node.expr2 is not None:
1500 return self.visit(node.expr2, frame)
1501 self.write('environment.undefined(%r)' % ('the inline if-'
1502 'expression on %s evaluated to false and '
1503 'no else section was defined.' % self.position(node)))
1505 if not have_condexpr:
1507 self.visit(node.test, frame)
1508 self.write(') and (')
1509 self.visit(node.expr1, frame)
1510 self.write(',) or (')
1512 self.write(',))[0]')
1515 self.visit(node.expr1, frame)
1517 self.visit(node.test, frame)
1518 self.write(' else ')
1522 def visit_Call(self, node, frame, forward_caller=False):
1523 if self.environment.sandboxed:
1524 self.write('environment.call(context, ')
1526 self.write('context.call(')
1527 self.visit(node.node, frame)
1528 extra_kwargs = forward_caller and {'caller': 'caller'} or None
1529 self.signature(node, frame, extra_kwargs)
1532 def visit_Keyword(self, node, frame):
1533 self.write(node.key + '=')
1534 self.visit(node.value, frame)
1536 # -- Unused nodes for extensions
1538 def visit_MarkSafe(self, node, frame):
1539 self.write('Markup(')
1540 self.visit(node.expr, frame)
1543 def visit_EnvironmentAttribute(self, node, frame):
1544 self.write('environment.' + node.name)
1546 def visit_ExtensionAttribute(self, node, frame):
1547 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
1549 def visit_ImportedName(self, node, frame):
1550 self.write(self.import_aliases[node.importname])
1552 def visit_InternalName(self, node, frame):
1553 self.write(node.name)
1555 def visit_ContextReference(self, node, frame):
1556 self.write('context')
1558 def visit_Continue(self, node, frame):
1559 self.writeline('continue', node)
1561 def visit_Break(self, node, frame):
1562 self.writeline('break', node)
1564 def visit_Scope(self, node, frame):
1565 scope_frame = frame.inner()
1566 scope_frame.inspect(node.iter_child_nodes())
1567 aliases = self.push_scope(scope_frame)
1568 self.pull_locals(scope_frame)
1569 self.blockvisit(node.body, scope_frame)
1570 self.pop_scope(aliases, scope_frame)