1 # -*- coding: utf-8 -*-
6 Compiles nodes into python code.
8 :copyright: Copyright 2008 by Armin Ronacher.
12 from keyword import iskeyword
13 from cStringIO import StringIO
14 from itertools import chain
15 from jinja2 import nodes
16 from jinja2.visitor import NodeVisitor, NodeTransformer
17 from jinja2.exceptions import TemplateAssertionError
18 from jinja2.utils import Markup, concat, escape
33 exec '(0 if 0 else 0)'
40 def generate(node, environment, name, filename, stream=None):
41 """Generate the python source for a node tree."""
42 if not isinstance(node, nodes.Template):
43 raise TypeError('Can\'t compile non template nodes')
44 generator = CodeGenerator(environment, name, filename, stream)
47 return generator.stream.getvalue()
50 def has_safe_repr(value):
51 """Does the node have a safe representation?"""
52 if value is None or value is NotImplemented or value is Ellipsis:
54 if isinstance(value, (bool, int, long, float, complex, basestring,
57 if isinstance(value, (tuple, list, set, frozenset)):
59 if not has_safe_repr(item):
62 elif isinstance(value, dict):
63 for key, value in value.iteritems():
64 if not has_safe_repr(key):
66 if not has_safe_repr(value):
72 def find_undeclared(nodes, names):
73 """Check if the names passed are accessed undeclared. The return value
74 is a set of all the undeclared names from the sequence of names found.
76 visitor = UndeclaredNameVisitor(names)
82 return visitor.undeclared
85 class Identifiers(object):
86 """Tracks the status of identifiers in frames."""
89 # variables that are known to be declared (probably from outer
90 # frames or because they are special for the frame)
93 # undeclared variables from outer scopes
94 self.outer_undeclared = set()
96 # names that are accessed without being explicitly declared by
97 # this one or any of the outer scopes. Names can appear both in
98 # declared and undeclared.
99 self.undeclared = set()
101 # names that are declared locally
102 self.declared_locally = set()
104 # names that are declared by parameters
105 self.declared_parameter = set()
107 def add_special(self, name):
108 """Register a special name like `loop`."""
109 self.undeclared.discard(name)
110 self.declared.add(name)
112 def is_declared(self, name, local_only=False):
113 """Check if a name is declared in this or an outer scope."""
114 if name in self.declared_locally or name in self.declared_parameter:
118 return name in self.declared
120 def find_shadowed(self):
121 """Find all the shadowed names."""
122 return (self.declared | self.outer_undeclared) & \
123 (self.declared_locally | self.declared_parameter)
127 """Holds compile time information for us."""
129 def __init__(self, parent=None):
130 self.identifiers = Identifiers()
132 # a toplevel frame is the root + soft frames such as if conditions.
133 self.toplevel = False
135 # the root frame is basically just the outermost frame, so no if
136 # conditions. This information is used to optimize inheritance
138 self.rootlevel = False
140 # inside some tags we are using a buffer rather than yield statements.
141 # this for example affects {% filter %} or {% macro %}. If a frame
142 # is buffered this variable points to the name of the list used as
146 # the name of the block we're in, otherwise None.
147 self.block = parent and parent.block or None
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_locally |
156 parent.identifiers.declared_parameter |
157 parent.identifiers.undeclared
159 self.identifiers.outer_undeclared.update(
160 parent.identifiers.undeclared -
161 self.identifiers.declared
163 self.buffer = parent.buffer
166 """Create a copy of the current one."""
168 rv.identifiers = copy(self.identifiers)
171 def inspect(self, nodes, hard_scope=False):
172 """Walk the node and check for identifiers. If the scope is hard (eg:
173 enforce on a python level) overrides from outer scopes are tracked
176 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
181 """Return an inner frame."""
185 """Return a soft frame. A soft frame may not be modified as
186 standalone thing as it shares the resources with the frame it
187 was created of, but it's not a rootlevel frame any longer.
194 class VisitorExit(RuntimeError):
195 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
198 class DependencyFinderVisitor(NodeVisitor):
199 """A visitor that collects filter and test calls."""
205 def visit_Filter(self, node):
206 self.generic_visit(node)
207 self.filters.add(node.name)
209 def visit_Test(self, node):
210 self.generic_visit(node)
211 self.tests.add(node.name)
213 def visit_Block(self, node):
214 """Stop visiting at blocks."""
217 class UndeclaredNameVisitor(NodeVisitor):
218 """A visitor that checks if a name is accessed without being
219 declared. This is different from the frame visitor as it will
220 not stop at closure frames.
223 def __init__(self, names):
224 self.names = set(names)
225 self.undeclared = set()
227 def visit_Name(self, node):
228 if node.ctx == 'load' and node.name in self.names:
229 self.undeclared.add(node.name)
230 if self.undeclared == self.names:
233 self.names.discard(node.name)
235 def visit_Block(self, node):
236 """Stop visiting a blocks."""
239 class FrameIdentifierVisitor(NodeVisitor):
240 """A visitor for `Frame.inspect`."""
242 def __init__(self, identifiers, hard_scope):
243 self.identifiers = identifiers
244 self.hard_scope = hard_scope
246 def visit_Name(self, node):
247 """All assignments to names go through this function."""
248 if node.ctx == 'store':
249 self.identifiers.declared_locally.add(node.name)
250 elif node.ctx == 'param':
251 self.identifiers.declared_parameter.add(node.name)
252 elif node.ctx == 'load' and not \
253 self.identifiers.is_declared(node.name, self.hard_scope):
254 self.identifiers.undeclared.add(node.name)
256 def visit_Macro(self, node):
257 self.identifiers.declared_locally.add(node.name)
259 def visit_Import(self, node):
260 self.generic_visit(node)
261 self.identifiers.declared_locally.add(node.target)
263 def visit_FromImport(self, node):
264 self.generic_visit(node)
265 for name in node.names:
266 if isinstance(name, tuple):
267 self.identifiers.declared_locally.add(name[1])
269 self.identifiers.declared_locally.add(name)
271 def visit_Assign(self, node):
272 """Visit assignments in the correct order."""
273 self.visit(node.node)
274 self.visit(node.target)
276 def visit_For(self, node):
277 """Visiting stops at for blocks. However the block sequence
278 is visited as part of the outer scope.
280 self.visit(node.iter)
282 def visit_CallBlock(self, node):
283 for child in node.iter_child_nodes(exclude=('body',)):
286 def visit_FilterBlock(self, node):
287 self.visit(node.filter)
289 def visit_Block(self, node):
290 """Stop visiting at blocks."""
293 class CompilerExit(Exception):
294 """Raised if the compiler encountered a situation where it just
295 doesn't make sense to further process the code. Any block that
296 raises such an exception is not further processed.
300 class CodeGenerator(NodeVisitor):
302 def __init__(self, environment, name, filename, stream=None):
305 self.environment = environment
307 self.filename = filename
310 # aliases for imports
311 self.import_aliases = {}
313 # a registry for all blocks. Because blocks are moved out
314 # into the global python scope they are registered here
317 # the number of extends statements so far
318 self.extends_so_far = 0
320 # some templates have a rootlevel extends. In this case we
321 # can safely assume that we're a child template and do some
322 # more optimizations.
323 self.has_known_extends = False
325 # the current line number
328 # registry of all filters and tests (global, not block local)
332 # the debug information
334 self._write_debug_info = None
336 # the number of new lines before the next write()
339 # the line number of the last written statement
342 # true if nothing was written so far.
343 self._first_write = True
345 # used by the `temporary_identifier` method to get new
346 # unique, temporary identifier
347 self._last_identifier = 0
349 # the current indentation
350 self._indentation = 0
352 # -- Various compilation helpers
354 def fail(self, msg, lineno):
355 """Fail with a `TemplateAssertionError`."""
356 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
358 def temporary_identifier(self):
359 """Get a new unique identifier."""
360 self._last_identifier += 1
361 return 't_%d' % self._last_identifier
363 def buffer(self, frame):
364 """Enable buffering for the frame from that point onwards."""
365 frame.buffer = self.temporary_identifier()
366 self.writeline('%s = []' % frame.buffer)
368 def return_buffer_contents(self, frame):
369 """Return the buffer contents of the frame."""
370 if self.environment.autoescape:
371 self.writeline('return Markup(concat(%s))' % frame.buffer)
373 self.writeline('return concat(%s)' % frame.buffer)
377 self._indentation += 1
379 def outdent(self, step=1):
380 """Outdent by step."""
381 self._indentation -= step
383 def start_write(self, frame, node=None):
384 """Yield or write into the frame buffer."""
385 if frame.buffer is None:
386 self.writeline('yield ', node)
388 self.writeline('%s.append(' % frame.buffer, node)
390 def end_write(self, frame):
391 """End the writing process started by `start_write`."""
392 if frame.buffer is not None:
395 def simple_write(self, s, frame, node=None):
396 """Simple shortcut for start_write + write + end_write."""
397 self.start_write(frame, node)
399 self.end_write(frame)
401 def blockvisit(self, nodes, frame, force_generator=True):
402 """Visit a list of nodes as block in a frame. If the current frame
403 is no buffer a dummy ``if 0: yield None`` is written automatically
404 unless the force_generator parameter is set to False.
406 if frame.buffer is None and force_generator:
407 self.writeline('if 0: yield None')
410 self.visit(node, frame)
415 """Write a string into the output stream."""
417 if not self._first_write:
418 self.stream.write('\n' * self._new_lines)
419 self.code_lineno += self._new_lines
420 if self._write_debug_info is not None:
421 self.debug_info.append((self._write_debug_info,
423 self._write_debug_info = None
424 self._first_write = False
425 self.stream.write(' ' * self._indentation)
429 def writeline(self, x, node=None, extra=0):
430 """Combination of newline and write."""
431 self.newline(node, extra)
434 def newline(self, node=None, extra=0):
435 """Add one or more newlines before the next write."""
436 self._new_lines = max(self._new_lines, 1 + extra)
437 if node is not None and node.lineno != self._last_line:
438 self._write_debug_info = node.lineno
439 self._last_line = node.lineno
441 def signature(self, node, frame, extra_kwargs=None):
442 """Writes a function call to the stream for the current node.
443 A leading comma is added automatically. The extra keyword
444 arguments may not include python keywords otherwise a syntax
445 error could occour. The extra keyword arguments should be given
448 # if any of the given keyword arguments is a python keyword
449 # we have to make sure that no invalid call is created.
450 kwarg_workaround = False
451 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
453 kwarg_workaround = True
456 for arg in node.args:
458 self.visit(arg, frame)
460 if not kwarg_workaround:
461 for kwarg in node.kwargs:
463 self.visit(kwarg, frame)
464 if extra_kwargs is not None:
465 for key, value in extra_kwargs.iteritems():
466 self.write(', %s=%s' % (key, value))
469 self.visit(node.dyn_args, frame)
472 if node.dyn_kwargs is not None:
473 self.write(', **dict({')
476 for kwarg in node.kwargs:
477 self.write('%r: ' % kwarg.key)
478 self.visit(kwarg.value, frame)
480 if extra_kwargs is not None:
481 for key, value in extra_kwargs.iteritems():
482 self.write('%r: %s, ' % (key, value))
483 if node.dyn_kwargs is not None:
485 self.visit(node.dyn_kwargs, frame)
490 elif node.dyn_kwargs is not None:
492 self.visit(node.dyn_kwargs, frame)
494 def pull_locals(self, frame):
495 """Pull all the references identifiers into the local scope."""
496 for name in frame.identifiers.undeclared:
497 self.writeline('l_%s = context.resolve(%r)' % (name, name))
499 def pull_dependencies(self, nodes):
500 """Pull all the dependencies."""
501 visitor = DependencyFinderVisitor()
504 for dependency in 'filters', 'tests':
505 mapping = getattr(self, dependency)
506 for name in getattr(visitor, dependency):
507 if name not in mapping:
508 mapping[name] = self.temporary_identifier()
509 self.writeline('%s = environment.%s[%r]' %
510 (mapping[name], dependency, name))
512 def collect_shadowed(self, frame):
513 """This function returns all the shadowed variables in a dict
514 in the form name: alias and will write the required assignments
515 into the current scope. No indentation takes place.
518 for name in frame.identifiers.find_shadowed():
519 aliases[name] = ident = self.temporary_identifier()
520 self.writeline('%s = l_%s' % (ident, name))
523 def restore_shadowed(self, aliases):
524 """Restore all aliases."""
525 for name, alias in aliases.iteritems():
526 self.writeline('l_%s = %s' % (name, alias))
528 def function_scoping(self, node, frame, children=None,
530 """In Jinja a few statements require the help of anonymous
531 functions. Those are currently macros and call blocks and in
532 the future also recursive loops. As there is currently
533 technical limitation that doesn't allow reading and writing a
534 variable in a scope where the initial value is coming from an
535 outer scope, this function tries to fall back with a common
536 error message. Additionally the frame passed is modified so
537 that the argumetns are collected and callers are looked up.
539 This will return the modified frame.
541 # we have to iterate twice over it, make sure that works
543 children = node.iter_child_nodes()
544 children = list(children)
545 func_frame = frame.inner()
546 func_frame.inspect(children, hard_scope=True)
548 # variables that are undeclared (accessed before declaration) and
549 # declared locally *and* part of an outside scope raise a template
550 # assertion error. Reason: we can't generate reasonable code from
551 # it without aliasing all the variables. XXX: alias them ^^
552 overriden_closure_vars = (
553 func_frame.identifiers.undeclared &
554 func_frame.identifiers.declared &
555 (func_frame.identifiers.declared_locally |
556 func_frame.identifiers.declared_parameter)
558 if overriden_closure_vars:
559 self.fail('It\'s not possible to set and access variables '
560 'derived from an outer scope! (affects: %s' %
561 ', '.join(sorted(overriden_closure_vars)), node.lineno)
563 # remove variables from a closure from the frame's undeclared
565 func_frame.identifiers.undeclared -= (
566 func_frame.identifiers.undeclared &
567 func_frame.identifiers.declared
570 # no special variables for this scope, abort early
574 func_frame.accesses_kwargs = False
575 func_frame.accesses_varargs = False
576 func_frame.accesses_caller = False
577 func_frame.arguments = args = ['l_' + x.name for x in node.args]
579 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
581 if 'caller' in undeclared:
582 func_frame.accesses_caller = True
583 func_frame.identifiers.add_special('caller')
584 args.append('l_caller')
585 if 'kwargs' in undeclared:
586 func_frame.accesses_kwargs = True
587 func_frame.identifiers.add_special('kwargs')
588 args.append('l_kwargs')
589 if 'varargs' in undeclared:
590 func_frame.accesses_varargs = True
591 func_frame.identifiers.add_special('varargs')
592 args.append('l_varargs')
595 def macro_body(self, node, frame, children=None):
596 """Dump the function def of a macro or call block."""
597 frame = self.function_scoping(node, frame, children)
598 args = frame.arguments
599 self.writeline('def macro(%s):' % ', '.join(args), node)
602 self.pull_locals(frame)
603 self.blockvisit(node.body, frame)
604 self.return_buffer_contents(frame)
608 def macro_def(self, node, frame):
609 """Dump the macro definition for the def created by macro_body."""
610 arg_tuple = ', '.join(repr(x.name) for x in node.args)
611 name = getattr(node, 'name', None)
612 if len(node.args) == 1:
614 self.write('Macro(environment, macro, %r, (%s), (' %
616 for arg in node.defaults:
617 self.visit(arg, frame)
619 self.write('), %r, %r, %r)' % (
620 bool(frame.accesses_kwargs),
621 bool(frame.accesses_varargs),
622 bool(frame.accesses_caller)
625 def position(self, node):
626 """Return a human readable position for the node."""
627 rv = 'line %d' % node.lineno
628 if self.name is not None:
629 rv += ' in' + repr(self.name)
632 # -- Statement Visitors
634 def visit_Template(self, node, frame=None):
635 assert frame is None, 'no root frame allowed'
636 from jinja2.runtime import __all__ as exported
637 self.writeline('from __future__ import division')
638 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
640 # do we have an extends tag at all? If not, we can save some
641 # overhead by just not processing any inheritance code.
642 have_extends = node.find(nodes.Extends) is not None
645 for block in node.find_all(nodes.Block):
646 if block.name in self.blocks:
647 self.fail('block %r defined twice' % block.name, block.lineno)
648 self.blocks[block.name] = block
650 # find all imports and import them
651 for import_ in node.find_all(nodes.ImportedName):
652 if import_.importname not in self.import_aliases:
653 imp = import_.importname
654 self.import_aliases[imp] = alias = self.temporary_identifier()
656 module, obj = imp.rsplit('.', 1)
657 self.writeline('from %s import %s as %s' %
658 (module, obj, alias))
660 self.writeline('import %s as %s' % (imp, alias))
663 self.writeline('name = %r' % self.name)
665 # generate the root render function.
666 self.writeline('def root(context, environment=environment):', extra=1)
670 frame.inspect(node.body)
671 frame.toplevel = frame.rootlevel = True
674 self.writeline('parent_template = None')
675 if 'self' in find_undeclared(node.body, ('self',)):
676 frame.identifiers.add_special('self')
677 self.writeline('l_self = TemplateReference(context)')
678 self.pull_locals(frame)
679 self.pull_dependencies(node.body)
680 self.blockvisit(node.body, frame)
683 # make sure that the parent root is called.
685 if not self.has_known_extends:
687 self.writeline('if parent_template is not None:')
689 self.writeline('for event in parent_template.'
690 'root_render_func(context):')
692 self.writeline('yield event')
693 self.outdent(2 + (not self.has_known_extends))
695 # at this point we now have the blocks collected and can visit them too.
696 for name, block in self.blocks.iteritems():
697 block_frame = Frame()
698 block_frame.inspect(block.body)
699 block_frame.block = name
700 self.writeline('def block_%s(context, environment=environment):'
703 undeclared = find_undeclared(block.body, ('self', 'super'))
704 if 'self' in undeclared:
705 block_frame.identifiers.add_special('self')
706 self.writeline('l_self = TemplateReference(context)')
707 if 'super' in undeclared:
708 block_frame.identifiers.add_special('super')
709 self.writeline('l_super = context.super(%r, '
710 'block_%s)' % (name, name))
711 self.pull_locals(block_frame)
712 self.pull_dependencies(block.body)
713 self.blockvisit(block.body, block_frame)
716 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
717 for x in self.blocks),
720 # add a function that returns the debug info
721 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
724 def visit_Block(self, node, frame):
725 """Call a block and register it for the template."""
728 # if we know that we are a child template, there is no need to
729 # check if we are one
730 if self.has_known_extends:
732 if self.extends_so_far > 0:
733 self.writeline('if parent_template is None:')
736 self.writeline('for event in context.blocks[%r][0](context):' %
739 self.simple_write('event', frame)
742 def visit_Extends(self, node, frame):
743 """Calls the extender."""
744 if not frame.toplevel:
745 self.fail('cannot use extend from a non top-level scope',
748 # if the number of extends statements in general is zero so
749 # far, we don't have to add a check if something extended
750 # the template before this one.
751 if self.extends_so_far > 0:
753 # if we have a known extends we just add a template runtime
754 # error into the generated code. We could catch that at compile
755 # time too, but i welcome it not to confuse users by throwing the
756 # same error at different times just "because we can".
757 if not self.has_known_extends:
758 self.writeline('if parent_template is not None:')
760 self.writeline('raise TemplateRuntimeError(%r)' %
761 'extended multiple times')
763 # if we have a known extends already we don't need that code here
764 # as we know that the template execution will end here.
765 if self.has_known_extends:
769 self.writeline('parent_template = environment.get_template(', node)
770 self.visit(node.template, frame)
771 self.write(', %r)' % self.name)
772 self.writeline('for name, parent_block in parent_template.'
773 'blocks.iteritems():')
775 self.writeline('context.blocks.setdefault(name, []).'
776 'append(parent_block)')
779 # if this extends statement was in the root level we can take
780 # advantage of that information and simplify the generated code
781 # in the top level from this point onwards
783 self.has_known_extends = True
785 # and now we have one more
786 self.extends_so_far += 1
788 def visit_Include(self, node, frame):
789 """Handles includes."""
790 if node.with_context:
791 self.writeline('template = environment.get_template(', node)
792 self.visit(node.template, frame)
793 self.write(', %r)' % self.name)
794 self.writeline('for event in template.root_render_func('
795 'template.new_context(context.parent, True)):')
797 self.writeline('for event in environment.get_template(', node)
798 self.visit(node.template, frame)
799 self.write(', %r).module._body_stream:' %
802 self.simple_write('event', frame)
805 def visit_Import(self, node, frame):
806 """Visit regular imports."""
807 self.writeline('l_%s = ' % node.target, node)
809 self.write('context.vars[%r] = ' % node.target)
810 self.write('environment.get_template(')
811 self.visit(node.template, frame)
812 self.write(', %r).' % self.name)
813 if node.with_context:
814 self.write('make_module(context.parent, True)')
817 if frame.toplevel and not node.target.startswith('_'):
818 self.writeline('context.exported_vars.discard(%r)' % node.target)
820 def visit_FromImport(self, node, frame):
821 """Visit named imports."""
823 self.write('included_template = environment.get_template(')
824 self.visit(node.template, frame)
825 self.write(', %r).' % self.name)
826 if node.with_context:
827 self.write('make_module(context.parent, True)')
833 for name in node.names:
834 if isinstance(name, tuple):
838 self.writeline('l_%s = getattr(included_template, '
839 '%r, missing)' % (alias, name))
840 self.writeline('if l_%s is missing:' % alias)
842 self.writeline('l_%s = environment.undefined(%r %% '
843 'included_template.__name__, '
845 (alias, 'the template %%r (imported on %s) does '
846 'not export the requested name %s' % (
852 var_names.append(alias)
853 if not alias.startswith('_'):
854 discarded_names.append(alias)
857 if len(var_names) == 1:
859 self.writeline('context.vars[%r] = l_%s' % (name, name))
861 self.writeline('context.vars.update({%s})' % ', '.join(
862 '%r: l_%s' % (name, name) for name in var_names
865 if len(discarded_names) == 1:
866 self.writeline('context.exported_vars.discard(%r)' %
869 self.writeline('context.exported_vars.difference_'
870 'update((%s))' % ', '.join(map(repr, discarded_names)))
872 def visit_For(self, node, frame):
873 # when calculating the nodes for the inner frame we have to exclude
874 # the iterator contents from it
875 children = node.iter_child_nodes(exclude=('iter',))
877 loop_frame = self.function_scoping(node, frame, children,
880 loop_frame = frame.inner()
881 loop_frame.inspect(children)
883 # try to figure out if we have an extended loop. An extended loop
884 # is necessary if the loop is in recursive mode if the special loop
885 # variable is accessed in the body.
886 extended_loop = node.recursive or 'loop' in \
887 find_undeclared(node.iter_child_nodes(
888 only=('body',)), ('loop',))
890 # make sure the loop variable is a special one and raise a template
891 # assertion error if a loop tries to write to loop
892 loop_frame.identifiers.add_special('loop')
893 for name in node.find_all(nodes.Name):
894 if name.ctx == 'store' and name.name == 'loop':
895 self.fail('Can\'t assign to special loop variable '
896 'in for-loop target', name.lineno)
898 # if we don't have an recursive loop we have to find the shadowed
899 # variables at that point
900 if not node.recursive:
901 aliases = self.collect_shadowed(loop_frame)
903 # otherwise we set up a buffer and add a function def
905 self.writeline('def loop(reciter, loop_render_func):', node)
907 self.buffer(loop_frame)
910 self.pull_locals(loop_frame)
912 iteration_indicator = self.temporary_identifier()
913 self.writeline('%s = 1' % iteration_indicator)
915 # Create a fake parent loop if the else or test section of a
916 # loop is accessing the special loop variable and no parent loop
918 if 'loop' not in aliases and 'loop' in find_undeclared(
919 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
920 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
921 ("'loop' is undefined. the filter section of a loop as well "
922 "as the else block doesn't have access to the special 'loop'"
923 " variable of the current loop. Because there is no parent "
924 "loop it's undefined. Happened in loop on %s" %
925 self.position(node)))
927 self.writeline('for ', node)
928 self.visit(node.target, loop_frame)
929 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
931 # if we have an extened loop and a node test, we filter in the
933 if extended_loop and node.test is not None:
935 self.visit(node.target, loop_frame)
937 self.visit(node.target, loop_frame)
940 self.write('reciter')
942 self.visit(node.iter, loop_frame)
944 test_frame = loop_frame.copy()
945 self.visit(node.test, test_frame)
949 self.write('reciter')
951 self.visit(node.iter, loop_frame)
954 self.write(', recurse=loop_render_func):')
956 self.write(extended_loop and '):' or ':')
958 # tests in not extended loops become a continue
959 if not extended_loop and node.test is not None:
961 self.writeline('if not ')
962 self.visit(node.test, loop_frame)
965 self.writeline('continue')
969 self.blockvisit(node.body, loop_frame, force_generator=True)
971 self.writeline('%s = 0' % iteration_indicator)
975 self.writeline('if %s:' % iteration_indicator)
977 self.blockvisit(node.else_, loop_frame, force_generator=False)
980 # reset the aliases if there are any.
981 self.restore_shadowed(aliases)
983 # if the node was recursive we have to return the buffer contents
984 # and start the iteration code
986 self.return_buffer_contents(loop_frame)
988 self.start_write(frame, node)
990 self.visit(node.iter, frame)
991 self.write(', loop)')
992 self.end_write(frame)
994 def visit_If(self, node, frame):
995 if_frame = frame.soft()
996 self.writeline('if ', node)
997 self.visit(node.test, if_frame)
1000 self.blockvisit(node.body, if_frame)
1003 self.writeline('else:')
1005 self.blockvisit(node.else_, if_frame)
1008 def visit_Macro(self, node, frame):
1009 macro_frame = self.macro_body(node, frame)
1012 if not node.name.startswith('_'):
1013 self.write('context.exported_vars.add(%r)' % node.name)
1014 self.writeline('context.vars[%r] = ' % node.name)
1015 self.write('l_%s = ' % node.name)
1016 self.macro_def(node, macro_frame)
1018 def visit_CallBlock(self, node, frame):
1019 children = node.iter_child_nodes(exclude=('call',))
1020 call_frame = self.macro_body(node, frame, children)
1021 self.writeline('caller = ')
1022 self.macro_def(node, call_frame)
1023 self.start_write(frame, node)
1024 self.visit_Call(node.call, call_frame, forward_caller=True)
1025 self.end_write(frame)
1027 def visit_FilterBlock(self, node, frame):
1028 filter_frame = frame.inner()
1029 filter_frame.inspect(node.iter_child_nodes())
1030 aliases = self.collect_shadowed(filter_frame)
1031 self.pull_locals(filter_frame)
1032 self.buffer(filter_frame)
1033 self.blockvisit(node.body, filter_frame, force_generator=False)
1034 self.start_write(frame, node)
1035 self.visit_Filter(node.filter, filter_frame)
1036 self.end_write(frame)
1037 self.restore_shadowed(aliases)
1039 def visit_ExprStmt(self, node, frame):
1041 self.visit(node.node, frame)
1043 def visit_Output(self, node, frame):
1044 # if we have a known extends statement, we don't output anything
1045 if self.has_known_extends and frame.toplevel:
1048 if self.environment.finalize:
1049 finalize = lambda x: unicode(self.environment.finalize(x))
1055 # if we are in the toplevel scope and there was already an extends
1056 # statement we have to add a check that disables our yield(s) here
1057 # so that they don't appear in the output.
1058 outdent_later = False
1059 if frame.toplevel and self.extends_so_far != 0:
1060 self.writeline('if parent_template is None:')
1062 outdent_later = True
1064 # try to evaluate as many chunks as possible into a static
1065 # string at compile time.
1067 for child in node.nodes:
1069 const = child.as_const()
1070 except nodes.Impossible:
1074 if self.environment.autoescape:
1075 if hasattr(const, '__html__'):
1076 const = const.__html__()
1078 const = escape(const)
1079 const = finalize(const)
1081 # if something goes wrong here we evaluate the node
1082 # at runtime for easier debugging
1085 if body and isinstance(body[-1], list):
1086 body[-1].append(const)
1088 body.append([const])
1090 # if we have less than 3 nodes or a buffer we yield or extend/append
1091 if len(body) < 3 or frame.buffer is not None:
1092 if frame.buffer is not None:
1093 # for one item we append, for more we extend
1095 self.writeline('%s.append(' % frame.buffer)
1097 self.writeline('%s.extend((' % frame.buffer)
1100 if isinstance(item, list):
1101 val = repr(concat(item))
1102 if frame.buffer is None:
1103 self.writeline('yield ' + val)
1105 self.writeline(val + ', ')
1107 if frame.buffer is None:
1108 self.writeline('yield ', item)
1112 if self.environment.autoescape:
1113 self.write('escape(')
1115 self.write('unicode(')
1116 if self.environment.finalize is not None:
1117 self.write('environment.finalize(')
1119 self.visit(item, frame)
1120 self.write(')' * close)
1121 if frame.buffer is not None:
1123 if frame.buffer is not None:
1124 # close the open parentheses
1126 self.writeline(len(body) == 1 and ')' or '))')
1128 # otherwise we create a format string as this is faster in that case
1133 if isinstance(item, list):
1134 format.append(concat(item).replace('%', '%%'))
1137 arguments.append(item)
1138 self.writeline('yield ')
1139 self.write(repr(concat(format)) + ' % (')
1142 for argument in arguments:
1143 self.newline(argument)
1145 if self.environment.autoescape:
1146 self.write('escape(')
1148 if self.environment.finalize is not None:
1149 self.write('environment.finalize(')
1151 self.visit(argument, frame)
1152 self.write(')' * close + ', ')
1159 def visit_Assign(self, node, frame):
1161 # toplevel assignments however go into the local namespace and
1162 # the current template's context. We create a copy of the frame
1163 # here and add a set so that the Name visitor can add the assigned
1166 assignment_frame = frame.copy()
1167 assignment_frame.assigned_names = set()
1169 assignment_frame = frame
1170 self.visit(node.target, assignment_frame)
1172 self.visit(node.node, frame)
1174 # make sure toplevel assignments are added to the context.
1176 public_names = [x for x in assignment_frame.assigned_names
1177 if not x.startswith('_')]
1178 if len(assignment_frame.assigned_names) == 1:
1179 name = iter(assignment_frame.assigned_names).next()
1180 self.writeline('context.vars[%r] = l_%s' % (name, name))
1182 self.writeline('context.vars.update({')
1183 for idx, name in enumerate(assignment_frame.assigned_names):
1186 self.write('%r: l_%s' % (name, name))
1189 if len(public_names) == 1:
1190 self.writeline('context.exported_vars.add(%r)' %
1193 self.writeline('context.exported_vars.update((%s))' %
1194 ', '.join(map(repr, public_names)))
1196 # -- Expression Visitors
1198 def visit_Name(self, node, frame):
1199 if node.ctx == 'store' and frame.toplevel:
1200 frame.assigned_names.add(node.name)
1201 self.write('l_' + node.name)
1203 def visit_Const(self, node, frame):
1205 if isinstance(val, float):
1206 self.write(str(val))
1208 self.write(repr(val))
1210 def visit_TemplateData(self, node, frame):
1211 self.write(repr(node.as_const()))
1213 def visit_Tuple(self, node, frame):
1216 for idx, item in enumerate(node.items):
1219 self.visit(item, frame)
1220 self.write(idx == 0 and ',)' or ')')
1222 def visit_List(self, node, frame):
1224 for idx, item in enumerate(node.items):
1227 self.visit(item, frame)
1230 def visit_Dict(self, node, frame):
1232 for idx, item in enumerate(node.items):
1235 self.visit(item.key, frame)
1237 self.visit(item.value, frame)
1240 def binop(operator):
1241 def visitor(self, node, frame):
1243 self.visit(node.left, frame)
1244 self.write(' %s ' % operator)
1245 self.visit(node.right, frame)
1250 def visitor(self, node, frame):
1251 self.write('(' + operator)
1252 self.visit(node.node, frame)
1256 visit_Add = binop('+')
1257 visit_Sub = binop('-')
1258 visit_Mul = binop('*')
1259 visit_Div = binop('/')
1260 visit_FloorDiv = binop('//')
1261 visit_Pow = binop('**')
1262 visit_Mod = binop('%')
1263 visit_And = binop('and')
1264 visit_Or = binop('or')
1265 visit_Pos = uaop('+')
1266 visit_Neg = uaop('-')
1267 visit_Not = uaop('not ')
1270 def visit_Concat(self, node, frame):
1271 self.write('%s((' % (self.environment.autoescape and
1272 'markup_join' or 'unicode_join'))
1273 for arg in node.nodes:
1274 self.visit(arg, frame)
1278 def visit_Compare(self, node, frame):
1279 self.visit(node.expr, frame)
1281 self.visit(op, frame)
1283 def visit_Operand(self, node, frame):
1284 self.write(' %s ' % operators[node.op])
1285 self.visit(node.expr, frame)
1287 def visit_Getattr(self, node, frame):
1288 self.write('environment.getattr(')
1289 self.visit(node.node, frame)
1290 self.write(', %r)' % node.attr)
1292 def visit_Getitem(self, node, frame):
1293 # slices or integer subscriptions bypass the getitem
1294 # method if we can determine that at compile time.
1295 if isinstance(node.arg, nodes.Slice) or \
1296 (isinstance(node.arg, nodes.Const) and
1297 isinstance(node.arg.value, (int, long))):
1298 self.visit(node.node, frame)
1300 self.visit(node.arg, frame)
1303 self.write('environment.getitem(')
1304 self.visit(node.node, frame)
1306 self.visit(node.arg, frame)
1309 def visit_Slice(self, node, frame):
1310 if node.start is not None:
1311 self.visit(node.start, frame)
1313 if node.stop is not None:
1314 self.visit(node.stop, frame)
1315 if node.step is not None:
1317 self.visit(node.step, frame)
1319 def visit_Filter(self, node, frame):
1320 self.write(self.filters[node.name] + '(')
1321 func = self.environment.filters.get(node.name)
1323 self.fail('no filter named %r' % node.name, node.lineno)
1324 if getattr(func, 'contextfilter', False):
1325 self.write('context, ')
1326 elif getattr(func, 'environmentfilter', False):
1327 self.write('environment, ')
1329 # if the filter node is None we are inside a filter block
1330 # and want to write to the current buffer
1331 if node.node is not None:
1332 self.visit(node.node, frame)
1333 elif self.environment.autoescape:
1334 self.write('Markup(concat(%s))' % frame.buffer)
1336 self.write('concat(%s)' % frame.buffer)
1337 self.signature(node, frame)
1340 def visit_Test(self, node, frame):
1341 self.write(self.tests[node.name] + '(')
1342 if node.name not in self.environment.tests:
1343 self.fail('no test named %r' % node.name, node.lineno)
1344 self.visit(node.node, frame)
1345 self.signature(node, frame)
1348 def visit_CondExpr(self, node, frame):
1350 if node.expr2 is not None:
1351 return self.visit(node.expr2, frame)
1352 self.write('environment.undefined(%r)' % ('the inline if-'
1353 'expression on %s evaluated to false and '
1354 'no else section was defined.' % self.position(node)))
1356 if not have_condexpr:
1358 self.visit(node.test, frame)
1359 self.write(') and (')
1360 self.visit(node.expr1, frame)
1361 self.write(',) or (')
1363 self.write(',))[0]')
1366 self.visit(node.expr1, frame)
1368 self.visit(node.test, frame)
1369 self.write(' else ')
1373 def visit_Call(self, node, frame, forward_caller=False):
1374 if self.environment.sandboxed:
1375 self.write('environment.call(context, ')
1377 self.write('context.call(')
1378 self.visit(node.node, frame)
1379 extra_kwargs = forward_caller and {'caller': 'caller'} or None
1380 self.signature(node, frame, extra_kwargs)
1383 def visit_Keyword(self, node, frame):
1384 self.write(node.key + '=')
1385 self.visit(node.value, frame)
1387 # -- Unused nodes for extensions
1389 def visit_MarkSafe(self, node, frame):
1390 self.write('Markup(')
1391 self.visit(node.expr, frame)
1394 def visit_EnvironmentAttribute(self, node, frame):
1395 self.write('environment.' + node.name)
1397 def visit_ExtensionAttribute(self, node, frame):
1398 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
1400 def visit_ImportedName(self, node, frame):
1401 self.write(self.import_aliases[node.importname])
1403 def visit_InternalName(self, node, frame):
1404 self.write(node.name)
1406 def visit_ContextReference(self, node, frame):
1407 self.write('context')
1409 def visit_Continue(self, node, frame):
1410 self.writeline('continue', node)
1412 def visit_Break(self, node, frame):
1413 self.writeline('break', node)