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
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')
45 generator = CodeGenerator(environment, name, filename, stream)
48 return generator.stream.getvalue()
51 def has_safe_repr(value):
52 """Does the node have a safe representation?"""
53 if value is None or value is NotImplemented or value is Ellipsis:
55 if isinstance(value, (bool, int, long, float, complex, basestring,
58 if isinstance(value, (tuple, list, set, frozenset)):
60 if not has_safe_repr(item):
63 elif isinstance(value, dict):
64 for key, value in value.iteritems():
65 if not has_safe_repr(key):
67 if not has_safe_repr(value):
73 def find_undeclared(nodes, names):
74 """Check if the names passed are accessed undeclared. The return value
75 is a set of all the undeclared names from the sequence of names found.
77 visitor = UndeclaredNameVisitor(names)
83 return visitor.undeclared
86 class Identifiers(object):
87 """Tracks the status of identifiers in frames."""
90 # variables that are known to be declared (probably from outer
91 # frames or because they are special for the frame)
94 # undeclared variables from outer scopes
95 self.outer_undeclared = set()
97 # names that are accessed without being explicitly declared by
98 # this one or any of the outer scopes. Names can appear both in
99 # declared and undeclared.
100 self.undeclared = set()
102 # names that are declared locally
103 self.declared_locally = set()
105 # names that are declared by parameters
106 self.declared_parameter = set()
108 def add_special(self, name):
109 """Register a special name like `loop`."""
110 self.undeclared.discard(name)
111 self.declared.add(name)
113 def is_declared(self, name, local_only=False):
114 """Check if a name is declared in this or an outer scope."""
115 if name in self.declared_locally or name in self.declared_parameter:
119 return name in self.declared
121 def find_shadowed(self):
122 """Find all the shadowed names."""
123 return (self.declared | self.outer_undeclared) & \
124 (self.declared_locally | self.declared_parameter)
128 """Holds compile time information for us."""
130 def __init__(self, parent=None):
131 self.identifiers = Identifiers()
133 # a toplevel frame is the root + soft frames such as if conditions.
134 self.toplevel = False
136 # the root frame is basically just the outermost frame, so no if
137 # conditions. This information is used to optimize inheritance
139 self.rootlevel = False
141 # inside some tags we are using a buffer rather than yield statements.
142 # this for example affects {% filter %} or {% macro %}. If a frame
143 # is buffered this variable points to the name of the list used as
147 # the name of the block we're in, otherwise None.
148 self.block = parent and parent.block or None
150 # the parent of this frame
153 if parent is not None:
154 self.identifiers.declared.update(
155 parent.identifiers.declared |
156 parent.identifiers.declared_locally |
157 parent.identifiers.declared_parameter |
158 parent.identifiers.undeclared
160 self.identifiers.outer_undeclared.update(
161 parent.identifiers.undeclared -
162 self.identifiers.declared
164 self.buffer = parent.buffer
167 """Create a copy of the current one."""
169 rv.identifiers = copy(self.identifiers)
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)
182 """Return an inner frame."""
186 """Return a soft frame. A soft frame may not be modified as
187 standalone thing as it shares the resources with the frame it
188 was created of, but it's not a rootlevel frame any longer.
195 class VisitorExit(RuntimeError):
196 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
199 class DependencyFinderVisitor(NodeVisitor):
200 """A visitor that collects filter and test calls."""
206 def visit_Filter(self, node):
207 self.generic_visit(node)
208 self.filters.add(node.name)
210 def visit_Test(self, node):
211 self.generic_visit(node)
212 self.tests.add(node.name)
214 def visit_Block(self, node):
215 """Stop visiting at blocks."""
218 class UndeclaredNameVisitor(NodeVisitor):
219 """A visitor that checks if a name is accessed without being
220 declared. This is different from the frame visitor as it will
221 not stop at closure frames.
224 def __init__(self, names):
225 self.names = set(names)
226 self.undeclared = set()
228 def visit_Name(self, node):
229 if node.ctx == 'load' and node.name in self.names:
230 self.undeclared.add(node.name)
231 if self.undeclared == self.names:
234 self.names.discard(node.name)
236 def visit_Block(self, node):
237 """Stop visiting a blocks."""
240 class FrameIdentifierVisitor(NodeVisitor):
241 """A visitor for `Frame.inspect`."""
243 def __init__(self, identifiers, hard_scope):
244 self.identifiers = identifiers
245 self.hard_scope = hard_scope
247 def visit_Name(self, node):
248 """All assignments to names go through this function."""
249 if node.ctx == 'store':
250 self.identifiers.declared_locally.add(node.name)
251 elif node.ctx == 'param':
252 self.identifiers.declared_parameter.add(node.name)
253 elif node.ctx == 'load' and not \
254 self.identifiers.is_declared(node.name, self.hard_scope):
255 self.identifiers.undeclared.add(node.name)
257 def visit_Macro(self, node):
258 self.identifiers.declared_locally.add(node.name)
260 def visit_Import(self, node):
261 self.generic_visit(node)
262 self.identifiers.declared_locally.add(node.target)
264 def visit_FromImport(self, node):
265 self.generic_visit(node)
266 for name in node.names:
267 if isinstance(name, tuple):
268 self.identifiers.declared_locally.add(name[1])
270 self.identifiers.declared_locally.add(name)
272 def visit_Assign(self, node):
273 """Visit assignments in the correct order."""
274 self.visit(node.node)
275 self.visit(node.target)
277 def visit_For(self, node):
278 """Visiting stops at for blocks. However the block sequence
279 is visited as part of the outer scope.
281 self.visit(node.iter)
283 def visit_CallBlock(self, node):
284 for child in node.iter_child_nodes(exclude=('body',)):
287 def visit_FilterBlock(self, node):
288 self.visit(node.filter)
290 def visit_Block(self, node):
291 """Stop visiting at blocks."""
294 class CompilerExit(Exception):
295 """Raised if the compiler encountered a situation where it just
296 doesn't make sense to further process the code. Any block that
297 raises such an exception is not further processed.
301 class CodeGenerator(NodeVisitor):
303 def __init__(self, environment, name, filename, stream=None):
306 self.environment = environment
308 self.filename = filename
311 # aliases for imports
312 self.import_aliases = {}
314 # a registry for all blocks. Because blocks are moved out
315 # into the global python scope they are registered here
318 # the number of extends statements so far
319 self.extends_so_far = 0
321 # some templates have a rootlevel extends. In this case we
322 # can safely assume that we're a child template and do some
323 # more optimizations.
324 self.has_known_extends = False
326 # the current line number
329 # registry of all filters and tests (global, not block local)
333 # the debug information
335 self._write_debug_info = None
337 # the number of new lines before the next write()
340 # the line number of the last written statement
343 # true if nothing was written so far.
344 self._first_write = True
346 # used by the `temporary_identifier` method to get new
347 # unique, temporary identifier
348 self._last_identifier = 0
350 # the current indentation
351 self._indentation = 0
353 # -- Various compilation helpers
355 def fail(self, msg, lineno):
356 """Fail with a `TemplateAssertionError`."""
357 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
359 def temporary_identifier(self):
360 """Get a new unique identifier."""
361 self._last_identifier += 1
362 return 't_%d' % self._last_identifier
364 def buffer(self, frame):
365 """Enable buffering for the frame from that point onwards."""
366 frame.buffer = self.temporary_identifier()
367 self.writeline('%s = []' % frame.buffer)
369 def return_buffer_contents(self, frame):
370 """Return the buffer contents of the frame."""
371 if self.environment.autoescape:
372 self.writeline('return Markup(concat(%s))' % frame.buffer)
374 self.writeline('return concat(%s)' % frame.buffer)
378 self._indentation += 1
380 def outdent(self, step=1):
381 """Outdent by step."""
382 self._indentation -= step
384 def start_write(self, frame, node=None):
385 """Yield or write into the frame buffer."""
386 if frame.buffer is None:
387 self.writeline('yield ', node)
389 self.writeline('%s.append(' % frame.buffer, node)
391 def end_write(self, frame):
392 """End the writing process started by `start_write`."""
393 if frame.buffer is not None:
396 def simple_write(self, s, frame, node=None):
397 """Simple shortcut for start_write + write + end_write."""
398 self.start_write(frame, node)
400 self.end_write(frame)
402 def blockvisit(self, nodes, frame, force_generator=True):
403 """Visit a list of nodes as block in a frame. If the current frame
404 is no buffer a dummy ``if 0: yield None`` is written automatically
405 unless the force_generator parameter is set to False.
407 if frame.buffer is None and force_generator:
408 self.writeline('if 0: yield None')
411 self.visit(node, frame)
416 """Write a string into the output stream."""
418 if not self._first_write:
419 self.stream.write('\n' * self._new_lines)
420 self.code_lineno += self._new_lines
421 if self._write_debug_info is not None:
422 self.debug_info.append((self._write_debug_info,
424 self._write_debug_info = None
425 self._first_write = False
426 self.stream.write(' ' * self._indentation)
430 def writeline(self, x, node=None, extra=0):
431 """Combination of newline and write."""
432 self.newline(node, extra)
435 def newline(self, node=None, extra=0):
436 """Add one or more newlines before the next write."""
437 self._new_lines = max(self._new_lines, 1 + extra)
438 if node is not None and node.lineno != self._last_line:
439 self._write_debug_info = node.lineno
440 self._last_line = node.lineno
442 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
443 """Writes a function call to the stream for the current node.
444 Per default it will write a leading comma but this can be
445 disabled by setting have_comma to False. The extra keyword
446 arguments may not include python keywords otherwise a syntax
447 error could occour. The extra keyword arguments should be given
450 have_comma = have_comma and [True] or []
455 have_comma.append(True)
457 # if any of the given keyword arguments is a python keyword
458 # we have to make sure that no invalid call is created.
459 kwarg_workaround = False
460 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
462 kwarg_workaround = True
465 for arg in node.args:
467 self.visit(arg, frame)
469 if not kwarg_workaround:
470 for kwarg in node.kwargs:
472 self.visit(kwarg, frame)
473 if extra_kwargs is not None:
474 for key, value in extra_kwargs.iteritems():
476 self.write('%s=%s' % (key, value))
480 self.visit(node.dyn_args, frame)
484 if node.dyn_kwargs is not None:
485 self.write('**dict({')
488 for kwarg in node.kwargs:
489 self.write('%r: ' % kwarg.key)
490 self.visit(kwarg.value, frame)
492 if extra_kwargs is not None:
493 for key, value in extra_kwargs.iteritems():
494 self.write('%r: %s, ' % (key, value))
495 if node.dyn_kwargs is not None:
497 self.visit(node.dyn_kwargs, frame)
502 elif node.dyn_kwargs is not None:
505 self.visit(node.dyn_kwargs, frame)
507 def pull_locals(self, frame):
508 """Pull all the references identifiers into the local scope."""
509 for name in frame.identifiers.undeclared:
510 self.writeline('l_%s = context.resolve(%r)' % (name, name))
512 def pull_dependencies(self, nodes):
513 """Pull all the dependencies."""
514 visitor = DependencyFinderVisitor()
517 for dependency in 'filters', 'tests':
518 mapping = getattr(self, dependency)
519 for name in getattr(visitor, dependency):
520 if name not in mapping:
521 mapping[name] = self.temporary_identifier()
522 self.writeline('%s = environment.%s[%r]' %
523 (mapping[name], dependency, name))
525 def collect_shadowed(self, frame):
526 """This function returns all the shadowed variables in a dict
527 in the form name: alias and will write the required assignments
528 into the current scope. No indentation takes place.
531 for name in frame.identifiers.find_shadowed():
532 aliases[name] = ident = self.temporary_identifier()
533 self.writeline('%s = l_%s' % (ident, name))
536 def function_scoping(self, node, frame, children=None,
538 """In Jinja a few statements require the help of anonymous
539 functions. Those are currently macros and call blocks and in
540 the future also recursive loops. As there is currently
541 technical limitation that doesn't allow reading and writing a
542 variable in a scope where the initial value is coming from an
543 outer scope, this function tries to fall back with a common
544 error message. Additionally the frame passed is modified so
545 that the argumetns are collected and callers are looked up.
547 This will return the modified frame.
549 # we have to iterate twice over it, make sure that works
551 children = node.iter_child_nodes()
552 children = list(children)
553 func_frame = frame.inner()
554 func_frame.inspect(children, hard_scope=True)
556 # variables that are undeclared (accessed before declaration) and
557 # declared locally *and* part of an outside scope raise a template
558 # assertion error. Reason: we can't generate reasonable code from
559 # it without aliasing all the variables. XXX: alias them ^^
560 overriden_closure_vars = (
561 func_frame.identifiers.undeclared &
562 func_frame.identifiers.declared &
563 (func_frame.identifiers.declared_locally |
564 func_frame.identifiers.declared_parameter)
566 if overriden_closure_vars:
567 self.fail('It\'s not possible to set and access variables '
568 'derived from an outer scope! (affects: %s' %
569 ', '.join(sorted(overriden_closure_vars)), node.lineno)
571 # remove variables from a closure from the frame's undeclared
573 func_frame.identifiers.undeclared -= (
574 func_frame.identifiers.undeclared &
575 func_frame.identifiers.declared
578 # no special variables for this scope, abort early
582 func_frame.accesses_kwargs = False
583 func_frame.accesses_varargs = False
584 func_frame.accesses_caller = False
585 func_frame.arguments = args = ['l_' + x.name for x in node.args]
587 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
589 if 'caller' in undeclared:
590 func_frame.accesses_caller = True
591 func_frame.identifiers.add_special('caller')
592 args.append('l_caller')
593 if 'kwargs' in undeclared:
594 func_frame.accesses_kwargs = True
595 func_frame.identifiers.add_special('kwargs')
596 args.append('l_kwargs')
597 if 'varargs' in undeclared:
598 func_frame.accesses_varargs = True
599 func_frame.identifiers.add_special('varargs')
600 args.append('l_varargs')
603 def macro_body(self, node, frame, children=None):
604 """Dump the function def of a macro or call block."""
605 frame = self.function_scoping(node, frame, children)
606 args = frame.arguments
607 self.writeline('def macro(%s):' % ', '.join(args), node)
610 self.pull_locals(frame)
611 self.blockvisit(node.body, frame)
612 self.return_buffer_contents(frame)
616 def macro_def(self, node, frame):
617 """Dump the macro definition for the def created by macro_body."""
618 arg_tuple = ', '.join(repr(x.name) for x in node.args)
619 name = getattr(node, 'name', None)
620 if len(node.args) == 1:
622 self.write('Macro(environment, macro, %r, (%s), (' %
624 for arg in node.defaults:
625 self.visit(arg, frame)
627 self.write('), %r, %r, %r)' % (
628 bool(frame.accesses_kwargs),
629 bool(frame.accesses_varargs),
630 bool(frame.accesses_caller)
633 # -- Statement Visitors
635 def visit_Template(self, node, frame=None):
636 assert frame is None, 'no root frame allowed'
637 from jinja2.runtime import __all__ as exported
638 self.writeline('from __future__ import division')
639 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
641 # do we have an extends tag at all? If not, we can save some
642 # overhead by just not processing any inheritance code.
643 have_extends = node.find(nodes.Extends) is not None
646 for block in node.find_all(nodes.Block):
647 if block.name in self.blocks:
648 self.fail('block %r defined twice' % block.name, block.lineno)
649 self.blocks[block.name] = block
651 # find all imports and import them
652 for import_ in node.find_all(nodes.ImportedName):
653 if import_.importname not in self.import_aliases:
654 imp = import_.importname
655 self.import_aliases[imp] = alias = self.temporary_identifier()
657 module, obj = imp.rsplit('.', 1)
658 self.writeline('from %s import %s as %s' %
659 (module, obj, alias))
661 self.writeline('import %s as %s' % (imp, alias))
664 self.writeline('name = %r' % self.name)
666 # generate the root render function.
667 self.writeline('def root(context, environment=environment):', extra=1)
671 frame.inspect(node.body)
672 frame.toplevel = frame.rootlevel = True
675 self.writeline('parent_template = None')
676 self.pull_locals(frame)
677 self.pull_dependencies(node.body)
678 if 'self' in find_undeclared(node.body, ('self',)):
679 frame.identifiers.add_special('self')
680 self.writeline('l_self = TemplateReference(context)')
681 self.blockvisit(node.body, frame)
684 # make sure that the parent root is called.
686 if not self.has_known_extends:
688 self.writeline('if parent_template is not None:')
690 self.writeline('for event in parent_template.'
691 '_root_render_func(context):')
693 self.writeline('yield event')
694 self.outdent(2 + (not self.has_known_extends))
696 # at this point we now have the blocks collected and can visit them too.
697 for name, block in self.blocks.iteritems():
698 block_frame = Frame()
699 block_frame.inspect(block.body)
700 block_frame.block = name
701 self.writeline('def block_%s(context, environment=environment):'
704 undeclared = find_undeclared(block.body, ('self', 'super'))
705 if 'self' in undeclared:
706 block_frame.identifiers.add_special('self')
707 self.writeline('l_self = TemplateReference(context)')
708 if 'super' in undeclared:
709 block_frame.identifiers.add_special('super')
710 self.writeline('l_super = context.super(%r, '
711 'block_%s)' % (name, name))
712 self.pull_locals(block_frame)
713 self.pull_dependencies(block.body)
714 self.blockvisit(block.body, block_frame)
717 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
718 for x in self.blocks),
721 # add a function that returns the debug info
722 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
725 def visit_Block(self, node, frame):
726 """Call a block and register it for the template."""
729 # if we know that we are a child template, there is no need to
730 # check if we are one
731 if self.has_known_extends:
733 if self.extends_so_far > 0:
734 self.writeline('if parent_template is None:')
737 self.writeline('for event in context.blocks[%r][0](context):' %
740 self.simple_write('event', frame)
743 def visit_Extends(self, node, frame):
744 """Calls the extender."""
745 if not frame.toplevel:
746 self.fail('cannot use extend from a non top-level scope',
749 # if the number of extends statements in general is zero so
750 # far, we don't have to add a check if something extended
751 # the template before this one.
752 if self.extends_so_far > 0:
754 # if we have a known extends we just add a template runtime
755 # error into the generated code. We could catch that at compile
756 # time too, but i welcome it not to confuse users by throwing the
757 # same error at different times just "because we can".
758 if not self.has_known_extends:
759 self.writeline('if parent_template is not None:')
761 self.writeline('raise TemplateRuntimeError(%r)' %
762 'extended multiple times')
764 # if we have a known extends already we don't need that code here
765 # as we know that the template execution will end here.
766 if self.has_known_extends:
770 self.writeline('parent_template = environment.get_template(', node)
771 self.visit(node.template, frame)
772 self.write(', %r)' % self.name)
773 self.writeline('for name, parent_block in parent_template.'
774 'blocks.iteritems():')
776 self.writeline('context.blocks.setdefault(name, []).'
777 'append(parent_block)')
780 # if this extends statement was in the root level we can take
781 # advantage of that information and simplify the generated code
782 # in the top level from this point onwards
784 self.has_known_extends = True
786 # and now we have one more
787 self.extends_so_far += 1
789 def visit_Include(self, node, frame):
790 """Handles includes."""
791 if node.with_context:
792 self.writeline('template = environment.get_template(', node)
793 self.visit(node.template, frame)
794 self.write(', %r)' % self.name)
795 self.writeline('for event in template._root_render_func('
796 'template.new_context(context.parent, True)):')
798 self.writeline('for event in environment.get_template(', node)
799 self.visit(node.template, frame)
800 self.write(', %r).module._body_stream:' %
803 self.simple_write('event', frame)
806 def visit_Import(self, node, frame):
807 """Visit regular imports."""
808 self.writeline('l_%s = ' % node.target, node)
810 self.write('context.vars[%r] = ' % node.target)
811 self.write('environment.get_template(')
812 self.visit(node.template, frame)
813 self.write(', %r).' % self.name)
814 if node.with_context:
815 self.write('make_module(context.parent, True)')
818 if frame.toplevel and not node.target.startswith('_'):
819 self.writeline('context.exported_vars.discard(%r)' % node.target)
821 def visit_FromImport(self, node, frame):
822 """Visit named imports."""
824 self.write('included_template = environment.get_template(')
825 self.visit(node.template, frame)
826 self.write(', %r).' % self.name)
827 if node.with_context:
828 self.write('make_module(context.parent, True)')
834 for name in node.names:
835 if isinstance(name, tuple):
839 self.writeline('l_%s = getattr(included_template, '
840 '%r, missing)' % (alias, name))
841 self.writeline('if l_%s is missing:' % alias)
843 self.writeline('l_%s = environment.undefined(%r %% '
844 'included_template.__name__, '
846 (alias, 'the template %r does not export '
847 'the requested name ' + repr(name), name))
850 var_names.append(alias)
851 if not alias.startswith('_'):
852 discarded_names.append(alias)
855 if len(var_names) == 1:
857 self.writeline('context.vars[%r] = l_%s' % (name, name))
859 self.writeline('context.vars.update({%s})' % ', '.join(
860 '%r: l_%s' % (name, name) for name in var_names
863 if len(discarded_names) == 1:
864 self.writeline('context.exported_vars.discard(%r)' %
867 self.writeline('context.exported_vars.difference_'
868 'update((%s))' % ', '.join(map(repr, discarded_names)))
870 def visit_For(self, node, frame):
871 # when calculating the nodes for the inner frame we have to exclude
872 # the iterator contents from it
873 children = list(node.iter_child_nodes(exclude=('iter',)))
876 loop_frame = self.function_scoping(node, frame, children,
879 loop_frame = frame.inner()
880 loop_frame.inspect(children)
882 undeclared = find_undeclared(children, ('loop',))
883 extended_loop = node.recursive or node.else_ or 'loop' in undeclared
885 loop_frame.identifiers.add_special('loop')
887 # if we don't have an recursive loop we have to find the shadowed
888 # variables at that point
889 if not node.recursive:
890 aliases = self.collect_shadowed(loop_frame)
892 # otherwise we set up a buffer and add a function def
894 self.writeline('def loop(reciter, loop_render_func):', node)
896 self.buffer(loop_frame)
899 self.pull_locals(loop_frame)
901 self.writeline('l_loop = None')
904 self.writeline('for ')
905 self.visit(node.target, loop_frame)
906 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
908 # the expression pointing to the parent loop. We make the
909 # undefined a bit more debug friendly at the same time.
910 parent_loop = 'loop' in aliases and aliases['loop'] \
911 or "environment.undefined(%r, name='loop')" % "'loop' " \
912 'is undefined. "the filter section of a loop as well ' \
913 'as the else block doesn\'t have access to the ' \
914 "special 'loop' variable of the current loop. " \
915 "Because there is no parent loop it's undefined."
917 # if we have an extened loop and a node test, we filter in the
919 if extended_loop and node.test is not None:
921 self.visit(node.target, loop_frame)
923 self.visit(node.target, loop_frame)
926 self.write('reciter')
928 self.visit(node.iter, loop_frame)
930 test_frame = loop_frame.copy()
931 self.writeline('l_loop = ' + parent_loop)
932 self.visit(node.test, test_frame)
936 self.write('reciter')
938 self.visit(node.iter, loop_frame)
941 self.write(', recurse=loop_render_func):')
943 self.write(extended_loop and '):' or ':')
945 # tests in not extended loops become a continue
946 if not extended_loop and node.test is not None:
948 self.writeline('if not ')
949 self.visit(node.test, loop_frame)
952 self.writeline('continue')
956 self.blockvisit(node.body, loop_frame, force_generator=True)
960 self.writeline('if l_loop is None:')
962 self.writeline('l_loop = ' + parent_loop)
963 self.blockvisit(node.else_, loop_frame, force_generator=False)
966 # reset the aliases if there are any.
967 for name, alias in aliases.iteritems():
968 self.writeline('l_%s = %s' % (name, alias))
970 # if the node was recursive we have to return the buffer contents
971 # and start the iteration code
973 self.return_buffer_contents(loop_frame)
975 self.start_write(frame, node)
977 self.visit(node.iter, frame)
978 self.write(', loop)')
979 self.end_write(frame)
981 def visit_If(self, node, frame):
982 if_frame = frame.soft()
983 self.writeline('if ', node)
984 self.visit(node.test, if_frame)
987 self.blockvisit(node.body, if_frame)
990 self.writeline('else:')
992 self.blockvisit(node.else_, if_frame)
995 def visit_Macro(self, node, frame):
996 macro_frame = self.macro_body(node, frame)
999 if not node.name.startswith('_'):
1000 self.write('context.exported_vars.add(%r)' % node.name)
1001 self.writeline('context.vars[%r] = ' % node.name)
1002 self.write('l_%s = ' % node.name)
1003 self.macro_def(node, macro_frame)
1005 def visit_CallBlock(self, node, frame):
1006 call_frame = self.macro_body(node, frame, node.iter_child_nodes
1007 (exclude=('call',)))
1008 self.writeline('caller = ')
1009 self.macro_def(node, call_frame)
1010 self.start_write(frame, node)
1011 self.visit_Call(node.call, call_frame,
1012 extra_kwargs={'caller': 'caller'})
1013 self.end_write(frame)
1015 def visit_FilterBlock(self, node, frame):
1016 filter_frame = frame.inner()
1017 filter_frame.inspect(node.iter_child_nodes())
1019 aliases = self.collect_shadowed(filter_frame)
1020 self.pull_locals(filter_frame)
1021 self.buffer(filter_frame)
1023 for child in node.body:
1024 self.visit(child, filter_frame)
1026 self.start_write(frame, node)
1027 self.visit_Filter(node.filter, filter_frame, 'concat(%s)'
1028 % filter_frame.buffer)
1029 self.end_write(frame)
1031 def visit_ExprStmt(self, node, frame):
1033 self.visit(node.node, frame)
1035 def visit_Output(self, node, frame):
1036 # if we have a known extends statement, we don't output anything
1037 if self.has_known_extends and frame.toplevel:
1042 # if we are in the toplevel scope and there was already an extends
1043 # statement we have to add a check that disables our yield(s) here
1044 # so that they don't appear in the output.
1045 outdent_later = False
1046 if frame.toplevel and self.extends_so_far != 0:
1047 self.writeline('if parent_template is None:')
1049 outdent_later = True
1051 # try to evaluate as many chunks as possible into a static
1052 # string at compile time.
1054 for child in node.nodes:
1056 const = unicode(child.as_const())
1060 if body and isinstance(body[-1], list):
1061 body[-1].append(const)
1063 body.append([const])
1065 # if we have less than 3 nodes or a buffer we yield or extend/append
1066 if len(body) < 3 or frame.buffer is not None:
1067 if frame.buffer is not None:
1068 # for one item we append, for more we extend
1070 self.writeline('%s.append(' % frame.buffer)
1072 self.writeline('%s.extend((' % frame.buffer)
1075 if isinstance(item, list):
1076 val = repr(concat(item))
1077 if frame.buffer is None:
1078 self.writeline('yield ' + val)
1080 self.writeline(val + ', ')
1082 if frame.buffer is None:
1083 self.writeline('yield ', item)
1087 if self.environment.autoescape:
1088 self.write('escape(')
1090 self.write('unicode(')
1091 if self.environment.finalize is not None:
1092 self.write('environment.finalize(')
1094 self.visit(item, frame)
1095 self.write(')' * close)
1096 if frame.buffer is not None:
1098 if frame.buffer is not None:
1099 # close the open parentheses
1101 self.writeline(len(body) == 1 and ')' or '))')
1103 # otherwise we create a format string as this is faster in that case
1108 if isinstance(item, list):
1109 format.append(concat(item).replace('%', '%%'))
1112 arguments.append(item)
1113 self.writeline('yield ')
1114 self.write(repr(concat(format)) + ' % (')
1117 for argument in arguments:
1118 self.newline(argument)
1120 if self.environment.autoescape:
1121 self.write('escape(')
1123 if self.environment.finalize is not None:
1124 self.write('environment.finalize(')
1126 self.visit(argument, frame)
1127 self.write(')' * close + ', ')
1134 def visit_Assign(self, node, frame):
1136 # toplevel assignments however go into the local namespace and
1137 # the current template's context. We create a copy of the frame
1138 # here and add a set so that the Name visitor can add the assigned
1141 assignment_frame = frame.copy()
1142 assignment_frame.assigned_names = set()
1144 assignment_frame = frame
1145 self.visit(node.target, assignment_frame)
1147 self.visit(node.node, frame)
1149 # make sure toplevel assignments are added to the context.
1151 public_names = [x for x in assignment_frame.assigned_names
1152 if not x.startswith('_')]
1153 if len(assignment_frame.assigned_names) == 1:
1154 name = iter(assignment_frame.assigned_names).next()
1155 self.writeline('context.vars[%r] = l_%s' % (name, name))
1157 self.writeline('context.vars.update({')
1158 for idx, name in enumerate(assignment_frame.assigned_names):
1161 self.write('%r: l_%s' % (name, name))
1164 if len(public_names) == 1:
1165 self.writeline('context.exported_vars.add(%r)' %
1168 self.writeline('context.exported_vars.update((%s))' %
1169 ', '.join(map(repr, public_names)))
1171 # -- Expression Visitors
1173 def visit_Name(self, node, frame):
1174 if node.ctx == 'store' and frame.toplevel:
1175 frame.assigned_names.add(node.name)
1176 self.write('l_' + node.name)
1178 def visit_Const(self, node, frame):
1180 if isinstance(val, float):
1181 self.write(str(val))
1183 self.write(repr(val))
1185 def visit_Tuple(self, node, frame):
1188 for idx, item in enumerate(node.items):
1191 self.visit(item, frame)
1192 self.write(idx == 0 and ',)' or ')')
1194 def visit_List(self, node, frame):
1196 for idx, item in enumerate(node.items):
1199 self.visit(item, frame)
1202 def visit_Dict(self, node, frame):
1204 for idx, item in enumerate(node.items):
1207 self.visit(item.key, frame)
1209 self.visit(item.value, frame)
1212 def binop(operator):
1213 def visitor(self, node, frame):
1215 self.visit(node.left, frame)
1216 self.write(' %s ' % operator)
1217 self.visit(node.right, frame)
1222 def visitor(self, node, frame):
1223 self.write('(' + operator)
1224 self.visit(node.node, frame)
1228 visit_Add = binop('+')
1229 visit_Sub = binop('-')
1230 visit_Mul = binop('*')
1231 visit_Div = binop('/')
1232 visit_FloorDiv = binop('//')
1233 visit_Pow = binop('**')
1234 visit_Mod = binop('%')
1235 visit_And = binop('and')
1236 visit_Or = binop('or')
1237 visit_Pos = uaop('+')
1238 visit_Neg = uaop('-')
1239 visit_Not = uaop('not ')
1242 def visit_Concat(self, node, frame):
1243 self.write('%s((' % (self.environment.autoescape and
1244 'markup_join' or 'unicode_join'))
1245 for arg in node.nodes:
1246 self.visit(arg, frame)
1250 def visit_Compare(self, node, frame):
1251 self.visit(node.expr, frame)
1253 self.visit(op, frame)
1255 def visit_Operand(self, node, frame):
1256 self.write(' %s ' % operators[node.op])
1257 self.visit(node.expr, frame)
1259 def visit_Subscript(self, node, frame):
1260 # slices or integer subscriptions bypass the subscribe
1261 # method if we can determine that at compile time.
1262 if isinstance(node.arg, nodes.Slice) or \
1263 (isinstance(node.arg, nodes.Const) and
1264 isinstance(node.arg.value, (int, long))):
1265 self.visit(node.node, frame)
1267 self.visit(node.arg, frame)
1270 self.write('environment.subscribe(')
1271 self.visit(node.node, frame)
1273 self.visit(node.arg, frame)
1276 def visit_Slice(self, node, frame):
1277 if node.start is not None:
1278 self.visit(node.start, frame)
1280 if node.stop is not None:
1281 self.visit(node.stop, frame)
1282 if node.step is not None:
1284 self.visit(node.step, frame)
1286 def visit_Filter(self, node, frame, initial=None):
1287 self.write(self.filters[node.name] + '(')
1288 func = self.environment.filters.get(node.name)
1290 self.fail('no filter named %r' % node.name, node.lineno)
1291 if getattr(func, 'contextfilter', False):
1292 self.write('context, ')
1293 elif getattr(func, 'environmentfilter', False):
1294 self.write('environment, ')
1295 if isinstance(node.node, nodes.Filter):
1296 self.visit_Filter(node.node, frame, initial)
1297 elif node.node is None:
1300 self.visit(node.node, frame)
1301 self.signature(node, frame)
1304 def visit_Test(self, node, frame):
1305 self.write(self.tests[node.name] + '(')
1306 if node.name not in self.environment.tests:
1307 self.fail('no test named %r' % node.name, node.lineno)
1308 self.visit(node.node, frame)
1309 self.signature(node, frame)
1312 def visit_CondExpr(self, node, frame):
1313 if not have_condexpr:
1315 self.visit(node.test, frame)
1316 self.write(') and (')
1317 self.visit(node.expr1, frame)
1318 self.write(',) or (')
1319 self.visit(node.expr2, frame)
1320 self.write(',))[0]')
1323 self.visit(node.expr1, frame)
1325 self.visit(node.test, frame)
1326 self.write(' else ')
1327 self.visit(node.expr2, frame)
1330 def visit_Call(self, node, frame, extra_kwargs=None):
1331 if self.environment.sandboxed:
1332 self.write('environment.call(')
1333 self.visit(node.node, frame)
1334 self.write(self.environment.sandboxed and ', ' or '(')
1335 self.signature(node, frame, False, extra_kwargs)
1338 def visit_Keyword(self, node, frame):
1339 self.write(node.key + '=')
1340 self.visit(node.value, frame)
1342 # -- Unused nodes for extensions
1344 def visit_MarkSafe(self, node, frame):
1345 self.write('Markup(')
1346 self.visit(node.expr, frame)
1349 def visit_EnvironmentAttribute(self, node, frame):
1350 self.write('environment.' + node.name)
1352 def visit_ExtensionAttribute(self, node, frame):
1353 self.write('environment.extensions[%r].%s' % (node.identifier, node.attr))
1355 def visit_ImportedName(self, node, frame):
1356 self.write(self.import_aliases[node.importname])
1358 def visit_InternalName(self, node, frame):
1359 self.write(node.name)
1361 def visit_Continue(self, node, frame):
1362 self.writeline('continue', node)
1364 def visit_Break(self, node, frame):
1365 self.writeline('break', node)