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 jinja2 import nodes
14 from jinja2.visitor import NodeVisitor, NodeTransformer
15 from jinja2.exceptions import TemplateAssertionError
16 from jinja2.utils import Markup, concat, escape, is_python_keyword, next
31 exec '(0 if 0 else 0)'
38 def generate(node, environment, name, filename, stream=None):
39 """Generate the python source for a node tree."""
40 if not isinstance(node, nodes.Template):
41 raise TypeError('Can\'t compile non template nodes')
42 generator = CodeGenerator(environment, name, filename, stream)
45 return generator.stream.getvalue()
48 def has_safe_repr(value):
49 """Does the node have a safe representation?"""
50 if value is None or value is NotImplemented or value is Ellipsis:
52 if isinstance(value, (bool, int, long, float, complex, basestring,
55 if isinstance(value, (tuple, list, set, frozenset)):
57 if not has_safe_repr(item):
60 elif isinstance(value, dict):
61 for key, value in value.iteritems():
62 if not has_safe_repr(key):
64 if not has_safe_repr(value):
70 def find_undeclared(nodes, names):
71 """Check if the names passed are accessed undeclared. The return value
72 is a set of all the undeclared names from the sequence of names found.
74 visitor = UndeclaredNameVisitor(names)
80 return visitor.undeclared
83 class Identifiers(object):
84 """Tracks the status of identifiers in frames."""
87 # variables that are known to be declared (probably from outer
88 # frames or because they are special for the frame)
91 # undeclared variables from outer scopes
92 self.outer_undeclared = set()
94 # names that are accessed without being explicitly declared by
95 # this one or any of the outer scopes. Names can appear both in
96 # declared and undeclared.
97 self.undeclared = set()
99 # names that are declared locally
100 self.declared_locally = set()
102 # names that are declared by parameters
103 self.declared_parameter = set()
105 def add_special(self, name):
106 """Register a special name like `loop`."""
107 self.undeclared.discard(name)
108 self.declared.add(name)
110 def is_declared(self, name, local_only=False):
111 """Check if a name is declared in this or an outer scope."""
112 if name in self.declared_locally or name in self.declared_parameter:
116 return name in self.declared
120 """Holds compile time information for us."""
122 def __init__(self, parent=None):
123 self.identifiers = Identifiers()
125 # a toplevel frame is the root + soft frames such as if conditions.
126 self.toplevel = False
128 # the root frame is basically just the outermost frame, so no if
129 # conditions. This information is used to optimize inheritance
131 self.rootlevel = False
133 # in some dynamic inheritance situations the compiler needs to add
134 # write tests around output statements.
135 self.require_output_check = parent and parent.require_output_check
137 # inside some tags we are using a buffer rather than yield statements.
138 # this for example affects {% filter %} or {% macro %}. If a frame
139 # is buffered this variable points to the name of the list used as
143 # the name of the block we're in, otherwise None.
144 self.block = parent and parent.block or None
146 # a set of actually assigned names
147 self.assigned_names = set()
149 # the parent of this frame
152 if parent is not None:
153 self.identifiers.declared.update(
154 parent.identifiers.declared |
155 parent.identifiers.declared_parameter |
156 parent.assigned_names
158 self.identifiers.outer_undeclared.update(
159 parent.identifiers.undeclared -
160 self.identifiers.declared
162 self.buffer = parent.buffer
165 """Create a copy of the current one."""
166 rv = object.__new__(self.__class__)
167 rv.__dict__.update(self.__dict__)
168 rv.identifiers = object.__new__(self.identifiers.__class__)
169 rv.identifiers.__dict__.update(self.identifiers.__dict__)
172 def inspect(self, nodes, hard_scope=False):
173 """Walk the node and check for identifiers. If the scope is hard (eg:
174 enforce on a python level) overrides from outer scopes are tracked
177 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
181 def find_shadowed(self, extra=()):
182 """Find all the shadowed names. extra is an iterable of variables
183 that may be defined with `add_special` which may occour scoped.
186 return (i.declared | i.outer_undeclared) & \
187 (i.declared_locally | i.declared_parameter) | \
188 set(x for x in extra if i.is_declared(x))
191 """Return an inner frame."""
195 """Return a soft frame. A soft frame may not be modified as
196 standalone thing as it shares the resources with the frame it
197 was created of, but it's not a rootlevel frame any longer.
206 class VisitorExit(RuntimeError):
207 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
210 class DependencyFinderVisitor(NodeVisitor):
211 """A visitor that collects filter and test calls."""
217 def visit_Filter(self, node):
218 self.generic_visit(node)
219 self.filters.add(node.name)
221 def visit_Test(self, node):
222 self.generic_visit(node)
223 self.tests.add(node.name)
225 def visit_Block(self, node):
226 """Stop visiting at blocks."""
229 class UndeclaredNameVisitor(NodeVisitor):
230 """A visitor that checks if a name is accessed without being
231 declared. This is different from the frame visitor as it will
232 not stop at closure frames.
235 def __init__(self, names):
236 self.names = set(names)
237 self.undeclared = set()
239 def visit_Name(self, node):
240 if node.ctx == 'load' and node.name in self.names:
241 self.undeclared.add(node.name)
242 if self.undeclared == self.names:
245 self.names.discard(node.name)
247 def visit_Block(self, node):
248 """Stop visiting a blocks."""
251 class FrameIdentifierVisitor(NodeVisitor):
252 """A visitor for `Frame.inspect`."""
254 def __init__(self, identifiers, hard_scope):
255 self.identifiers = identifiers
256 self.hard_scope = hard_scope
258 def visit_Name(self, node):
259 """All assignments to names go through this function."""
260 if node.ctx == 'store':
261 self.identifiers.declared_locally.add(node.name)
262 elif node.ctx == 'param':
263 self.identifiers.declared_parameter.add(node.name)
264 elif node.ctx == 'load' and not \
265 self.identifiers.is_declared(node.name, self.hard_scope):
266 self.identifiers.undeclared.add(node.name)
268 def visit_If(self, node):
269 self.visit(node.test)
271 # remember all the names that are locally assigned in the body
272 old_locals = self.identifiers.declared_locally.copy()
273 for subnode in node.body:
275 body = self.identifiers.declared_locally - old_locals
278 self.identifiers.declared_locally = old_locals.copy()
279 for subnode in node.else_ or ():
281 else_ = self.identifiers.declared_locally - old_locals
283 # the differences between the two branches are also pulled as
284 # undeclared variables
285 self.identifiers.undeclared.update(body.symmetric_difference(else_))
287 # declared_locally is currently the set of all variables assigned
288 # in the else part, add the new vars from body as well. That means
289 # that undeclared variables if unbalanced are considered local.
290 self.identifiers.declared_locally.update(body)
292 def visit_Macro(self, node):
293 self.identifiers.declared_locally.add(node.name)
295 def visit_Import(self, node):
296 self.generic_visit(node)
297 self.identifiers.declared_locally.add(node.target)
299 def visit_FromImport(self, node):
300 self.generic_visit(node)
301 for name in node.names:
302 if isinstance(name, tuple):
303 self.identifiers.declared_locally.add(name[1])
305 self.identifiers.declared_locally.add(name)
307 def visit_Assign(self, node):
308 """Visit assignments in the correct order."""
309 self.visit(node.node)
310 self.visit(node.target)
312 def visit_For(self, node):
313 """Visiting stops at for blocks. However the block sequence
314 is visited as part of the outer scope.
316 self.visit(node.iter)
318 def visit_CallBlock(self, node):
319 for child in node.iter_child_nodes(exclude=('body',)):
322 def visit_FilterBlock(self, node):
323 self.visit(node.filter)
325 def visit_Scope(self, node):
326 """Stop visiting at scopes."""
328 def visit_Block(self, node):
329 """Stop visiting at blocks."""
332 class CompilerExit(Exception):
333 """Raised if the compiler encountered a situation where it just
334 doesn't make sense to further process the code. Any block that
335 raises such an exception is not further processed.
339 class CodeGenerator(NodeVisitor):
341 def __init__(self, environment, name, filename, stream=None):
344 self.environment = environment
346 self.filename = filename
349 # aliases for imports
350 self.import_aliases = {}
352 # a registry for all blocks. Because blocks are moved out
353 # into the global python scope they are registered here
356 # the number of extends statements so far
357 self.extends_so_far = 0
359 # some templates have a rootlevel extends. In this case we
360 # can safely assume that we're a child template and do some
361 # more optimizations.
362 self.has_known_extends = False
364 # the current line number
367 # registry of all filters and tests (global, not block local)
371 # the debug information
373 self._write_debug_info = None
375 # the number of new lines before the next write()
378 # the line number of the last written statement
381 # true if nothing was written so far.
382 self._first_write = True
384 # used by the `temporary_identifier` method to get new
385 # unique, temporary identifier
386 self._last_identifier = 0
388 # the current indentation
389 self._indentation = 0
391 # -- Various compilation helpers
393 def fail(self, msg, lineno):
394 """Fail with a `TemplateAssertionError`."""
395 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
397 def temporary_identifier(self):
398 """Get a new unique identifier."""
399 self._last_identifier += 1
400 return 't_%d' % self._last_identifier
402 def buffer(self, frame):
403 """Enable buffering for the frame from that point onwards."""
404 frame.buffer = self.temporary_identifier()
405 self.writeline('%s = []' % frame.buffer)
407 def return_buffer_contents(self, frame):
408 """Return the buffer contents of the frame."""
409 if self.environment.autoescape:
410 self.writeline('return Markup(concat(%s))' % frame.buffer)
412 self.writeline('return concat(%s)' % frame.buffer)
416 self._indentation += 1
418 def outdent(self, step=1):
419 """Outdent by step."""
420 self._indentation -= step
422 def start_write(self, frame, node=None):
423 """Yield or write into the frame buffer."""
424 if frame.buffer is None:
425 self.writeline('yield ', node)
427 self.writeline('%s.append(' % frame.buffer, node)
429 def end_write(self, frame):
430 """End the writing process started by `start_write`."""
431 if frame.buffer is not None:
434 def simple_write(self, s, frame, node=None):
435 """Simple shortcut for start_write + write + end_write."""
436 self.start_write(frame, node)
438 self.end_write(frame)
440 def blockvisit(self, nodes, frame):
441 """Visit a list of nodes as block in a frame. If the current frame
442 is no buffer a dummy ``if 0: yield None`` is written automatically
443 unless the force_generator parameter is set to False.
445 if frame.buffer is None:
446 self.writeline('if 0: yield None')
448 self.writeline('pass')
451 self.visit(node, frame)
456 """Write a string into the output stream."""
458 if not self._first_write:
459 self.stream.write('\n' * self._new_lines)
460 self.code_lineno += self._new_lines
461 if self._write_debug_info is not None:
462 self.debug_info.append((self._write_debug_info,
464 self._write_debug_info = None
465 self._first_write = False
466 self.stream.write(' ' * self._indentation)
470 def writeline(self, x, node=None, extra=0):
471 """Combination of newline and write."""
472 self.newline(node, extra)
475 def newline(self, node=None, extra=0):
476 """Add one or more newlines before the next write."""
477 self._new_lines = max(self._new_lines, 1 + extra)
478 if node is not None and node.lineno != self._last_line:
479 self._write_debug_info = node.lineno
480 self._last_line = node.lineno
482 def signature(self, node, frame, extra_kwargs=None):
483 """Writes a function call to the stream for the current node.
484 A leading comma is added automatically. The extra keyword
485 arguments may not include python keywords otherwise a syntax
486 error could occour. The extra keyword arguments should be given
489 # if any of the given keyword arguments is a python keyword
490 # we have to make sure that no invalid call is created.
491 kwarg_workaround = False
492 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
493 if is_python_keyword(kwarg):
494 kwarg_workaround = True
497 for arg in node.args:
499 self.visit(arg, frame)
501 if not kwarg_workaround:
502 for kwarg in node.kwargs:
504 self.visit(kwarg, frame)
505 if extra_kwargs is not None:
506 for key, value in extra_kwargs.iteritems():
507 self.write(', %s=%s' % (key, value))
510 self.visit(node.dyn_args, frame)
513 if node.dyn_kwargs is not None:
514 self.write(', **dict({')
517 for kwarg in node.kwargs:
518 self.write('%r: ' % kwarg.key)
519 self.visit(kwarg.value, frame)
521 if extra_kwargs is not None:
522 for key, value in extra_kwargs.iteritems():
523 self.write('%r: %s, ' % (key, value))
524 if node.dyn_kwargs is not None:
526 self.visit(node.dyn_kwargs, frame)
531 elif node.dyn_kwargs is not None:
533 self.visit(node.dyn_kwargs, frame)
535 def pull_locals(self, frame):
536 """Pull all the references identifiers into the local scope."""
537 for name in frame.identifiers.undeclared:
538 self.writeline('l_%s = context.resolve(%r)' % (name, name))
540 def pull_dependencies(self, nodes):
541 """Pull all the dependencies."""
542 visitor = DependencyFinderVisitor()
545 for dependency in 'filters', 'tests':
546 mapping = getattr(self, dependency)
547 for name in getattr(visitor, dependency):
548 if name not in mapping:
549 mapping[name] = self.temporary_identifier()
550 self.writeline('%s = environment.%s[%r]' %
551 (mapping[name], dependency, name))
553 def unoptimize_scope(self, frame):
554 """Disable Python optimizations for the frame."""
555 # XXX: this is not that nice but it has no real overhead. It
556 # mainly works because python finds the locals before dead code
557 # is removed. If that breaks we have to add a dummy function
558 # that just accepts the arguments and does nothing.
559 if frame.identifiers.declared:
560 self.writeline('if 0: dummy(%s)' % ', '.join(
561 'l_' + name for name in frame.identifiers.declared))
563 def push_scope(self, frame, extra_vars=()):
564 """This function returns all the shadowed variables in a dict
565 in the form name: alias and will write the required assignments
566 into the current scope. No indentation takes place.
568 This also predefines locally declared variables from the loop
569 body because under some circumstances it may be the case that
571 `extra_vars` is passed to `Frame.find_shadowed`.
574 for name in frame.find_shadowed(extra_vars):
575 aliases[name] = ident = self.temporary_identifier()
576 self.writeline('%s = l_%s' % (ident, name))
578 for name in frame.identifiers.declared_locally:
579 if name not in aliases:
580 to_declare.add('l_' + name)
582 self.writeline(' = '.join(to_declare) + ' = missing')
585 def pop_scope(self, aliases, frame):
586 """Restore all aliases and delete unused variables."""
587 for name, alias in aliases.iteritems():
588 self.writeline('l_%s = %s' % (name, alias))
590 for name in frame.identifiers.declared_locally:
591 if name not in aliases:
592 to_delete.add('l_' + name)
594 # we cannot use the del statement here because enclosed
595 # scopes can trigger a SyntaxError:
596 # a = 42; b = lambda: a; del a
597 self.writeline(' = '.join(to_delete) + ' = missing')
599 def function_scoping(self, node, frame, children=None,
601 """In Jinja a few statements require the help of anonymous
602 functions. Those are currently macros and call blocks and in
603 the future also recursive loops. As there is currently
604 technical limitation that doesn't allow reading and writing a
605 variable in a scope where the initial value is coming from an
606 outer scope, this function tries to fall back with a common
607 error message. Additionally the frame passed is modified so
608 that the argumetns are collected and callers are looked up.
610 This will return the modified frame.
612 # we have to iterate twice over it, make sure that works
614 children = node.iter_child_nodes()
615 children = list(children)
616 func_frame = frame.inner()
617 func_frame.inspect(children, hard_scope=True)
619 # variables that are undeclared (accessed before declaration) and
620 # declared locally *and* part of an outside scope raise a template
621 # assertion error. Reason: we can't generate reasonable code from
622 # it without aliasing all the variables.
623 # this could be fixed in Python 3 where we have the nonlocal
624 # keyword or if we switch to bytecode generation
625 overriden_closure_vars = (
626 func_frame.identifiers.undeclared &
627 func_frame.identifiers.declared &
628 (func_frame.identifiers.declared_locally |
629 func_frame.identifiers.declared_parameter)
631 if overriden_closure_vars:
632 self.fail('It\'s not possible to set and access variables '
633 'derived from an outer scope! (affects: %s)' %
634 ', '.join(sorted(overriden_closure_vars)), node.lineno)
636 # remove variables from a closure from the frame's undeclared
638 func_frame.identifiers.undeclared -= (
639 func_frame.identifiers.undeclared &
640 func_frame.identifiers.declared
643 # no special variables for this scope, abort early
647 func_frame.accesses_kwargs = False
648 func_frame.accesses_varargs = False
649 func_frame.accesses_caller = False
650 func_frame.arguments = args = ['l_' + x.name for x in node.args]
652 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
654 if 'caller' in undeclared:
655 func_frame.accesses_caller = True
656 func_frame.identifiers.add_special('caller')
657 args.append('l_caller')
658 if 'kwargs' in undeclared:
659 func_frame.accesses_kwargs = True
660 func_frame.identifiers.add_special('kwargs')
661 args.append('l_kwargs')
662 if 'varargs' in undeclared:
663 func_frame.accesses_varargs = True
664 func_frame.identifiers.add_special('varargs')
665 args.append('l_varargs')
668 def macro_body(self, node, frame, children=None):
669 """Dump the function def of a macro or call block."""
670 frame = self.function_scoping(node, frame, children)
671 # macros are delayed, they never require output checks
672 frame.require_output_check = False
673 args = frame.arguments
674 # XXX: this is an ugly fix for the loop nesting bug
675 # (tests.test_old_bugs.test_loop_call_bug). This works around
676 # a identifier nesting problem we have in general. It's just more
677 # likely to happen in loops which is why we work around it. The
678 # real solution would be "nonlocal" all the identifiers that are
679 # leaking into a new python frame and might be used both unassigned
681 if 'loop' in frame.identifiers.declared:
682 args = args + ['l_loop=l_loop']
683 self.writeline('def macro(%s):' % ', '.join(args), node)
686 self.pull_locals(frame)
687 self.blockvisit(node.body, frame)
688 self.return_buffer_contents(frame)
692 def macro_def(self, node, frame):
693 """Dump the macro definition for the def created by macro_body."""
694 arg_tuple = ', '.join(repr(x.name) for x in node.args)
695 name = getattr(node, 'name', None)
696 if len(node.args) == 1:
698 self.write('Macro(environment, macro, %r, (%s), (' %
700 for arg in node.defaults:
701 self.visit(arg, frame)
703 self.write('), %r, %r, %r)' % (
704 bool(frame.accesses_kwargs),
705 bool(frame.accesses_varargs),
706 bool(frame.accesses_caller)
709 def position(self, node):
710 """Return a human readable position for the node."""
711 rv = 'line %d' % node.lineno
712 if self.name is not None:
713 rv += ' in ' + repr(self.name)
716 # -- Statement Visitors
718 def visit_Template(self, node, frame=None):
719 assert frame is None, 'no root frame allowed'
720 from jinja2.runtime import __all__ as exported
721 self.writeline('from __future__ import division')
722 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
724 # do we have an extends tag at all? If not, we can save some
725 # overhead by just not processing any inheritance code.
726 have_extends = node.find(nodes.Extends) is not None
728 # are there any block tags? If yes, we need a copy of the scope.
729 have_blocks = node.find(nodes.Block) is not None
732 for block in node.find_all(nodes.Block):
733 if block.name in self.blocks:
734 self.fail('block %r defined twice' % block.name, block.lineno)
735 self.blocks[block.name] = block
737 # find all imports and import them
738 for import_ in node.find_all(nodes.ImportedName):
739 if import_.importname not in self.import_aliases:
740 imp = import_.importname
741 self.import_aliases[imp] = alias = self.temporary_identifier()
743 module, obj = imp.rsplit('.', 1)
744 self.writeline('from %s import %s as %s' %
745 (module, obj, alias))
747 self.writeline('import %s as %s' % (imp, alias))
750 self.writeline('name = %r' % self.name)
752 # generate the root render function.
753 self.writeline('def root(context, environment=environment):', extra=1)
757 frame.inspect(node.body)
758 frame.toplevel = frame.rootlevel = True
759 frame.require_output_check = have_extends and not self.has_known_extends
762 self.writeline('parent_template = None')
764 self.writeline('block_context = context._block()')
765 if 'self' in find_undeclared(node.body, ('self',)):
766 frame.identifiers.add_special('self')
767 self.writeline('l_self = TemplateReference(context)')
768 self.pull_locals(frame)
769 self.pull_dependencies(node.body)
770 self.blockvisit(node.body, frame)
773 # make sure that the parent root is called.
775 if not self.has_known_extends:
777 self.writeline('if parent_template is not None:')
779 self.writeline('for event in parent_template.'
780 'root_render_func(context):')
782 self.writeline('yield event')
783 self.outdent(2 + (not self.has_known_extends))
785 # at this point we now have the blocks collected and can visit them too.
786 for name, block in self.blocks.iteritems():
787 block_frame = Frame()
788 block_frame.inspect(block.body)
789 block_frame.block = name
790 self.writeline('def block_%s(context, environment=environment):'
793 undeclared = find_undeclared(block.body, ('self', 'super'))
794 if 'self' in undeclared:
795 block_frame.identifiers.add_special('self')
796 self.writeline('l_self = TemplateReference(context)')
797 if block.find(nodes.Block) is not None:
798 self.writeline('block_context = context._block(%r)' % name)
799 if 'super' in undeclared:
800 block_frame.identifiers.add_special('super')
801 self.writeline('l_super = context.super(%r, '
802 'block_%s)' % (name, name))
803 self.pull_locals(block_frame)
804 self.pull_dependencies(block.body)
805 self.blockvisit(block.body, block_frame)
808 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
809 for x in self.blocks),
812 # add a function that returns the debug info
813 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
816 def visit_Block(self, node, frame):
817 """Call a block and register it for the template."""
820 # if we know that we are a child template, there is no need to
821 # check if we are one
822 if self.has_known_extends:
824 if self.extends_so_far > 0:
825 self.writeline('if parent_template is None:')
829 context = 'block_context.derived(locals())'
831 context = 'block_context'
832 self.writeline('for event in context.blocks[%r][0](%s):' % (
833 node.name, context), node)
835 self.simple_write('event', frame)
838 def visit_Extends(self, node, frame):
839 """Calls the extender."""
840 if not frame.toplevel:
841 self.fail('cannot use extend from a non top-level scope',
844 # if the number of extends statements in general is zero so
845 # far, we don't have to add a check if something extended
846 # the template before this one.
847 if self.extends_so_far > 0:
849 # if we have a known extends we just add a template runtime
850 # error into the generated code. We could catch that at compile
851 # time too, but i welcome it not to confuse users by throwing the
852 # same error at different times just "because we can".
853 if not self.has_known_extends:
854 self.writeline('if parent_template is not None:')
856 self.writeline('raise TemplateRuntimeError(%r)' %
857 'extended multiple times')
860 # if we have a known extends already we don't need that code here
861 # as we know that the template execution will end here.
862 if self.has_known_extends:
865 self.writeline('parent_template = environment.get_template(', node)
866 self.visit(node.template, frame)
867 self.write(', %r)' % self.name)
868 self.writeline('for name, parent_block in parent_template.'
869 'blocks.iteritems():')
871 self.writeline('context.blocks.setdefault(name, []).'
872 'append(parent_block)')
875 # if this extends statement was in the root level we can take
876 # advantage of that information and simplify the generated code
877 # in the top level from this point onwards
879 self.has_known_extends = True
881 # and now we have one more
882 self.extends_so_far += 1
884 def visit_Include(self, node, frame):
885 """Handles includes."""
886 if node.with_context:
887 self.unoptimize_scope(frame)
888 if node.ignore_missing:
889 self.writeline('try:')
891 self.writeline('template = environment.get_template(', node)
892 self.visit(node.template, frame)
893 self.write(', %r)' % self.name)
894 if node.ignore_missing:
896 self.writeline('except TemplateNotFound:')
898 self.writeline('pass')
900 self.writeline('else:')
903 if node.with_context:
904 self.writeline('for event in template.root_render_func('
905 'template.new_context(context.parent, True, '
908 self.writeline('for event in template.module._body_stream:')
911 self.simple_write('event', frame)
914 if node.ignore_missing:
917 def visit_Import(self, node, frame):
918 """Visit regular imports."""
919 if node.with_context:
920 self.unoptimize_scope(frame)
921 self.writeline('l_%s = ' % node.target, node)
923 self.write('context.vars[%r] = ' % node.target)
924 self.write('environment.get_template(')
925 self.visit(node.template, frame)
926 self.write(', %r).' % self.name)
927 if node.with_context:
928 self.write('make_module(context.parent, True, locals())')
931 if frame.toplevel and not node.target.startswith('_'):
932 self.writeline('context.exported_vars.discard(%r)' % node.target)
933 frame.assigned_names.add(node.target)
935 def visit_FromImport(self, node, frame):
936 """Visit named imports."""
938 self.write('included_template = environment.get_template(')
939 self.visit(node.template, frame)
940 self.write(', %r).' % self.name)
941 if node.with_context:
942 self.write('make_module(context.parent, True)')
948 for name in node.names:
949 if isinstance(name, tuple):
953 self.writeline('l_%s = getattr(included_template, '
954 '%r, missing)' % (alias, name))
955 self.writeline('if l_%s is missing:' % alias)
957 self.writeline('l_%s = environment.undefined(%r %% '
958 'included_template.__name__, '
960 (alias, 'the template %%r (imported on %s) does '
961 'not export the requested name %s' % (
967 var_names.append(alias)
968 if not alias.startswith('_'):
969 discarded_names.append(alias)
970 frame.assigned_names.add(alias)
973 if len(var_names) == 1:
975 self.writeline('context.vars[%r] = l_%s' % (name, name))
977 self.writeline('context.vars.update({%s})' % ', '.join(
978 '%r: l_%s' % (name, name) for name in var_names
981 if len(discarded_names) == 1:
982 self.writeline('context.exported_vars.discard(%r)' %
985 self.writeline('context.exported_vars.difference_'
986 'update((%s))' % ', '.join(map(repr, discarded_names)))
988 def visit_For(self, node, frame):
989 # when calculating the nodes for the inner frame we have to exclude
990 # the iterator contents from it
991 children = node.iter_child_nodes(exclude=('iter',))
993 loop_frame = self.function_scoping(node, frame, children,
996 loop_frame = frame.inner()
997 loop_frame.inspect(children)
999 # try to figure out if we have an extended loop. An extended loop
1000 # is necessary if the loop is in recursive mode if the special loop
1001 # variable is accessed in the body.
1002 extended_loop = node.recursive or 'loop' in \
1003 find_undeclared(node.iter_child_nodes(
1004 only=('body',)), ('loop',))
1006 # if we don't have an recursive loop we have to find the shadowed
1007 # variables at that point. Because loops can be nested but the loop
1008 # variable is a special one we have to enforce aliasing for it.
1009 if not node.recursive:
1010 aliases = self.push_scope(loop_frame, ('loop',))
1012 # otherwise we set up a buffer and add a function def
1014 self.writeline('def loop(reciter, loop_render_func):', node)
1016 self.buffer(loop_frame)
1019 # make sure the loop variable is a special one and raise a template
1020 # assertion error if a loop tries to write to loop
1022 loop_frame.identifiers.add_special('loop')
1023 for name in node.find_all(nodes.Name):
1024 if name.ctx == 'store' and name.name == 'loop':
1025 self.fail('Can\'t assign to special loop variable '
1026 'in for-loop target', name.lineno)
1028 self.pull_locals(loop_frame)
1030 iteration_indicator = self.temporary_identifier()
1031 self.writeline('%s = 1' % iteration_indicator)
1033 # Create a fake parent loop if the else or test section of a
1034 # loop is accessing the special loop variable and no parent loop
1036 if 'loop' not in aliases and 'loop' in find_undeclared(
1037 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1038 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
1039 ("'loop' is undefined. the filter section of a loop as well "
1040 "as the else block doesn't have access to the special 'loop'"
1041 " variable of the current loop. Because there is no parent "
1042 "loop it's undefined. Happened in loop on %s" %
1043 self.position(node)))
1045 self.writeline('for ', node)
1046 self.visit(node.target, loop_frame)
1047 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
1049 # if we have an extened loop and a node test, we filter in the
1051 if extended_loop and node.test is not None:
1053 self.visit(node.target, loop_frame)
1055 self.visit(node.target, loop_frame)
1058 self.write('reciter')
1060 self.visit(node.iter, loop_frame)
1062 test_frame = loop_frame.copy()
1063 self.visit(node.test, test_frame)
1066 elif node.recursive:
1067 self.write('reciter')
1069 self.visit(node.iter, loop_frame)
1072 self.write(', recurse=loop_render_func):')
1074 self.write(extended_loop and '):' or ':')
1076 # tests in not extended loops become a continue
1077 if not extended_loop and node.test is not None:
1079 self.writeline('if not ')
1080 self.visit(node.test, loop_frame)
1083 self.writeline('continue')
1087 self.blockvisit(node.body, loop_frame)
1089 self.writeline('%s = 0' % iteration_indicator)
1093 self.writeline('if %s:' % iteration_indicator)
1095 self.blockvisit(node.else_, loop_frame)
1098 # reset the aliases if there are any.
1099 if not node.recursive:
1100 self.pop_scope(aliases, loop_frame)
1102 # if the node was recursive we have to return the buffer contents
1103 # and start the iteration code
1105 self.return_buffer_contents(loop_frame)
1107 self.start_write(frame, node)
1109 self.visit(node.iter, frame)
1110 self.write(', loop)')
1111 self.end_write(frame)
1113 def visit_If(self, node, frame):
1114 if_frame = frame.soft()
1115 self.writeline('if ', node)
1116 self.visit(node.test, if_frame)
1119 self.blockvisit(node.body, if_frame)
1122 self.writeline('else:')
1124 self.blockvisit(node.else_, if_frame)
1127 def visit_Macro(self, node, frame):
1128 macro_frame = self.macro_body(node, frame)
1131 if not node.name.startswith('_'):
1132 self.write('context.exported_vars.add(%r)' % node.name)
1133 self.writeline('context.vars[%r] = ' % node.name)
1134 self.write('l_%s = ' % node.name)
1135 self.macro_def(node, macro_frame)
1136 frame.assigned_names.add(node.name)
1138 def visit_CallBlock(self, node, frame):
1139 children = node.iter_child_nodes(exclude=('call',))
1140 call_frame = self.macro_body(node, frame, children)
1141 self.writeline('caller = ')
1142 self.macro_def(node, call_frame)
1143 self.start_write(frame, node)
1144 self.visit_Call(node.call, call_frame, forward_caller=True)
1145 self.end_write(frame)
1147 def visit_FilterBlock(self, node, frame):
1148 filter_frame = frame.inner()
1149 filter_frame.inspect(node.iter_child_nodes())
1150 aliases = self.push_scope(filter_frame)
1151 self.pull_locals(filter_frame)
1152 self.buffer(filter_frame)
1153 self.blockvisit(node.body, filter_frame)
1154 self.start_write(frame, node)
1155 self.visit_Filter(node.filter, filter_frame)
1156 self.end_write(frame)
1157 self.pop_scope(aliases, filter_frame)
1159 def visit_ExprStmt(self, node, frame):
1161 self.visit(node.node, frame)
1163 def visit_Output(self, node, frame):
1164 # if we have a known extends statement, we don't output anything
1165 # if we are in a require_output_check section
1166 if self.has_known_extends and frame.require_output_check:
1169 if self.environment.finalize:
1170 finalize = lambda x: unicode(self.environment.finalize(x))
1176 # if we are inside a frame that requires output checking, we do so
1177 outdent_later = False
1178 if frame.require_output_check:
1179 self.writeline('if parent_template is None:')
1181 outdent_later = True
1183 # try to evaluate as many chunks as possible into a static
1184 # string at compile time.
1186 for child in node.nodes:
1188 const = child.as_const()
1189 except nodes.Impossible:
1193 if self.environment.autoescape:
1194 if hasattr(const, '__html__'):
1195 const = const.__html__()
1197 const = escape(const)
1198 const = finalize(const)
1200 # if something goes wrong here we evaluate the node
1201 # at runtime for easier debugging
1204 if body and isinstance(body[-1], list):
1205 body[-1].append(const)
1207 body.append([const])
1209 # if we have less than 3 nodes or a buffer we yield or extend/append
1210 if len(body) < 3 or frame.buffer is not None:
1211 if frame.buffer is not None:
1212 # for one item we append, for more we extend
1214 self.writeline('%s.append(' % frame.buffer)
1216 self.writeline('%s.extend((' % frame.buffer)
1219 if isinstance(item, list):
1220 val = repr(concat(item))
1221 if frame.buffer is None:
1222 self.writeline('yield ' + val)
1224 self.writeline(val + ', ')
1226 if frame.buffer is None:
1227 self.writeline('yield ', item)
1231 if self.environment.autoescape:
1232 self.write('escape(')
1234 self.write('to_string(')
1235 if self.environment.finalize is not None:
1236 self.write('environment.finalize(')
1238 self.visit(item, frame)
1239 self.write(')' * close)
1240 if frame.buffer is not None:
1242 if frame.buffer is not None:
1243 # close the open parentheses
1245 self.writeline(len(body) == 1 and ')' or '))')
1247 # otherwise we create a format string as this is faster in that case
1252 if isinstance(item, list):
1253 format.append(concat(item).replace('%', '%%'))
1256 arguments.append(item)
1257 self.writeline('yield ')
1258 self.write(repr(concat(format)) + ' % (')
1261 for argument in arguments:
1262 self.newline(argument)
1264 if self.environment.autoescape:
1265 self.write('escape(')
1267 if self.environment.finalize is not None:
1268 self.write('environment.finalize(')
1270 self.visit(argument, frame)
1271 self.write(')' * close + ', ')
1278 def visit_Assign(self, node, frame):
1280 # toplevel assignments however go into the local namespace and
1281 # the current template's context. We create a copy of the frame
1282 # here and add a set so that the Name visitor can add the assigned
1285 assignment_frame = frame.copy()
1286 assignment_frame.toplevel_assignments = set()
1288 assignment_frame = frame
1289 self.visit(node.target, assignment_frame)
1291 self.visit(node.node, frame)
1293 # make sure toplevel assignments are added to the context.
1295 public_names = [x for x in assignment_frame.toplevel_assignments
1296 if not x.startswith('_')]
1297 if len(assignment_frame.toplevel_assignments) == 1:
1298 name = next(iter(assignment_frame.toplevel_assignments))
1299 self.writeline('context.vars[%r] = l_%s' % (name, name))
1301 self.writeline('context.vars.update({')
1302 for idx, name in enumerate(assignment_frame.toplevel_assignments):
1305 self.write('%r: l_%s' % (name, name))
1308 if len(public_names) == 1:
1309 self.writeline('context.exported_vars.add(%r)' %
1312 self.writeline('context.exported_vars.update((%s))' %
1313 ', '.join(map(repr, public_names)))
1315 # -- Expression Visitors
1317 def visit_Name(self, node, frame):
1318 if node.ctx == 'store' and frame.toplevel:
1319 frame.toplevel_assignments.add(node.name)
1320 self.write('l_' + node.name)
1321 frame.assigned_names.add(node.name)
1323 def visit_Const(self, node, frame):
1325 if isinstance(val, float):
1326 self.write(str(val))
1328 self.write(repr(val))
1330 def visit_TemplateData(self, node, frame):
1331 self.write(repr(node.as_const()))
1333 def visit_Tuple(self, node, frame):
1336 for idx, item in enumerate(node.items):
1339 self.visit(item, frame)
1340 self.write(idx == 0 and ',)' or ')')
1342 def visit_List(self, node, frame):
1344 for idx, item in enumerate(node.items):
1347 self.visit(item, frame)
1350 def visit_Dict(self, node, frame):
1352 for idx, item in enumerate(node.items):
1355 self.visit(item.key, frame)
1357 self.visit(item.value, frame)
1360 def binop(operator):
1361 def visitor(self, node, frame):
1363 self.visit(node.left, frame)
1364 self.write(' %s ' % operator)
1365 self.visit(node.right, frame)
1370 def visitor(self, node, frame):
1371 self.write('(' + operator)
1372 self.visit(node.node, frame)
1376 visit_Add = binop('+')
1377 visit_Sub = binop('-')
1378 visit_Mul = binop('*')
1379 visit_Div = binop('/')
1380 visit_FloorDiv = binop('//')
1381 visit_Pow = binop('**')
1382 visit_Mod = binop('%')
1383 visit_And = binop('and')
1384 visit_Or = binop('or')
1385 visit_Pos = uaop('+')
1386 visit_Neg = uaop('-')
1387 visit_Not = uaop('not ')
1390 def visit_Concat(self, node, frame):
1391 self.write('%s((' % (self.environment.autoescape and
1392 'markup_join' or 'unicode_join'))
1393 for arg in node.nodes:
1394 self.visit(arg, frame)
1398 def visit_Compare(self, node, frame):
1399 self.visit(node.expr, frame)
1401 self.visit(op, frame)
1403 def visit_Operand(self, node, frame):
1404 self.write(' %s ' % operators[node.op])
1405 self.visit(node.expr, frame)
1407 def visit_Getattr(self, node, frame):
1408 self.write('environment.getattr(')
1409 self.visit(node.node, frame)
1410 self.write(', %r)' % node.attr)
1412 def visit_Getitem(self, node, frame):
1413 # slices bypass the environment getitem method.
1414 if isinstance(node.arg, nodes.Slice):
1415 self.visit(node.node, frame)
1417 self.visit(node.arg, frame)
1420 self.write('environment.getitem(')
1421 self.visit(node.node, frame)
1423 self.visit(node.arg, frame)
1426 def visit_Slice(self, node, frame):
1427 if node.start is not None:
1428 self.visit(node.start, frame)
1430 if node.stop is not None:
1431 self.visit(node.stop, frame)
1432 if node.step is not None:
1434 self.visit(node.step, frame)
1436 def visit_Filter(self, node, frame):
1437 self.write(self.filters[node.name] + '(')
1438 func = self.environment.filters.get(node.name)
1440 self.fail('no filter named %r' % node.name, node.lineno)
1441 if getattr(func, 'contextfilter', False):
1442 self.write('context, ')
1443 elif getattr(func, 'environmentfilter', False):
1444 self.write('environment, ')
1446 # if the filter node is None we are inside a filter block
1447 # and want to write to the current buffer
1448 if node.node is not None:
1449 self.visit(node.node, frame)
1450 elif self.environment.autoescape:
1451 self.write('Markup(concat(%s))' % frame.buffer)
1453 self.write('concat(%s)' % frame.buffer)
1454 self.signature(node, frame)
1457 def visit_Test(self, node, frame):
1458 self.write(self.tests[node.name] + '(')
1459 if node.name not in self.environment.tests:
1460 self.fail('no test named %r' % node.name, node.lineno)
1461 self.visit(node.node, frame)
1462 self.signature(node, frame)
1465 def visit_CondExpr(self, node, frame):
1467 if node.expr2 is not None:
1468 return self.visit(node.expr2, frame)
1469 self.write('environment.undefined(%r)' % ('the inline if-'
1470 'expression on %s evaluated to false and '
1471 'no else section was defined.' % self.position(node)))
1473 if not have_condexpr:
1475 self.visit(node.test, frame)
1476 self.write(') and (')
1477 self.visit(node.expr1, frame)
1478 self.write(',) or (')
1480 self.write(',))[0]')
1483 self.visit(node.expr1, frame)
1485 self.visit(node.test, frame)
1486 self.write(' else ')
1490 def visit_Call(self, node, frame, forward_caller=False):
1491 if self.environment.sandboxed:
1492 self.write('environment.call(context, ')
1494 self.write('context.call(')
1495 self.visit(node.node, frame)
1496 extra_kwargs = forward_caller and {'caller': 'caller'} or None
1497 self.signature(node, frame, extra_kwargs)
1500 def visit_Keyword(self, node, frame):
1501 self.write(node.key + '=')
1502 self.visit(node.value, frame)
1504 # -- Unused nodes for extensions
1506 def visit_MarkSafe(self, node, frame):
1507 self.write('Markup(')
1508 self.visit(node.expr, frame)
1511 def visit_EnvironmentAttribute(self, node, frame):
1512 self.write('environment.' + node.name)
1514 def visit_ExtensionAttribute(self, node, frame):
1515 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
1517 def visit_ImportedName(self, node, frame):
1518 self.write(self.import_aliases[node.importname])
1520 def visit_InternalName(self, node, frame):
1521 self.write(node.name)
1523 def visit_ContextReference(self, node, frame):
1524 self.write('context')
1526 def visit_Continue(self, node, frame):
1527 self.writeline('continue', node)
1529 def visit_Break(self, node, frame):
1530 self.writeline('break', node)
1532 def visit_Scope(self, node, frame):
1533 scope_frame = frame.inner()
1534 scope_frame.inspect(node.iter_child_nodes())
1535 aliases = self.push_scope(scope_frame)
1536 self.pull_locals(scope_frame)
1537 self.blockvisit(node.body, scope_frame)
1538 self.pop_scope(aliases, scope_frame)