1 # -*- coding: utf-8 -*-
6 Compiles nodes into python code.
8 :copyright: Copyright 2008 by Armin Ronacher.
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
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
118 def find_shadowed(self, extra=()):
119 """Find all the shadowed names. extra is an iterable of variables
120 that may be defined with `add_special` which may occour scoped.
122 return (self.declared | self.outer_undeclared) & \
123 (self.declared_locally | self.declared_parameter) | \
124 set(x for x in extra if self.is_declared(x))
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 # in some dynamic inheritance situations the compiler needs to add
142 # write tests around output statements.
143 self.require_output_check = parent and parent.require_output_check
145 # inside some tags we are using a buffer rather than yield statements.
146 # this for example affects {% filter %} or {% macro %}. If a frame
147 # is buffered this variable points to the name of the list used as
151 # the name of the block we're in, otherwise None.
152 self.block = parent and parent.block or None
154 # the parent of this frame
157 if parent is not None:
158 self.identifiers.declared.update(
159 parent.identifiers.declared |
160 parent.identifiers.declared_locally |
161 parent.identifiers.declared_parameter |
162 parent.identifiers.undeclared
164 self.identifiers.outer_undeclared.update(
165 parent.identifiers.undeclared -
166 self.identifiers.declared
168 self.buffer = parent.buffer
171 """Create a copy of the current one."""
172 rv = object.__new__(self.__class__)
173 rv.__dict__.update(self.__dict__)
174 rv.identifiers = object.__new__(self.identifiers.__class__)
175 rv.identifiers.__dict__.update(self.identifiers.__dict__)
178 def inspect(self, nodes, hard_scope=False):
179 """Walk the node and check for identifiers. If the scope is hard (eg:
180 enforce on a python level) overrides from outer scopes are tracked
183 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
188 """Return an inner frame."""
192 """Return a soft frame. A soft frame may not be modified as
193 standalone thing as it shares the resources with the frame it
194 was created of, but it's not a rootlevel frame any longer.
203 class VisitorExit(RuntimeError):
204 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
207 class DependencyFinderVisitor(NodeVisitor):
208 """A visitor that collects filter and test calls."""
214 def visit_Filter(self, node):
215 self.generic_visit(node)
216 self.filters.add(node.name)
218 def visit_Test(self, node):
219 self.generic_visit(node)
220 self.tests.add(node.name)
222 def visit_Block(self, node):
223 """Stop visiting at blocks."""
226 class UndeclaredNameVisitor(NodeVisitor):
227 """A visitor that checks if a name is accessed without being
228 declared. This is different from the frame visitor as it will
229 not stop at closure frames.
232 def __init__(self, names):
233 self.names = set(names)
234 self.undeclared = set()
236 def visit_Name(self, node):
237 if node.ctx == 'load' and node.name in self.names:
238 self.undeclared.add(node.name)
239 if self.undeclared == self.names:
242 self.names.discard(node.name)
244 def visit_Block(self, node):
245 """Stop visiting a blocks."""
248 class FrameIdentifierVisitor(NodeVisitor):
249 """A visitor for `Frame.inspect`."""
251 def __init__(self, identifiers, hard_scope):
252 self.identifiers = identifiers
253 self.hard_scope = hard_scope
255 def visit_Name(self, node):
256 """All assignments to names go through this function."""
257 if node.ctx == 'store':
258 self.identifiers.declared_locally.add(node.name)
259 elif node.ctx == 'param':
260 self.identifiers.declared_parameter.add(node.name)
261 elif node.ctx == 'load' and not \
262 self.identifiers.is_declared(node.name, self.hard_scope):
263 self.identifiers.undeclared.add(node.name)
265 def visit_Macro(self, node):
266 self.identifiers.declared_locally.add(node.name)
268 def visit_Import(self, node):
269 self.generic_visit(node)
270 self.identifiers.declared_locally.add(node.target)
272 def visit_FromImport(self, node):
273 self.generic_visit(node)
274 for name in node.names:
275 if isinstance(name, tuple):
276 self.identifiers.declared_locally.add(name[1])
278 self.identifiers.declared_locally.add(name)
280 def visit_Assign(self, node):
281 """Visit assignments in the correct order."""
282 self.visit(node.node)
283 self.visit(node.target)
285 def visit_For(self, node):
286 """Visiting stops at for blocks. However the block sequence
287 is visited as part of the outer scope.
289 self.visit(node.iter)
291 def visit_CallBlock(self, node):
292 for child in node.iter_child_nodes(exclude=('body',)):
295 def visit_FilterBlock(self, node):
296 self.visit(node.filter)
298 def visit_Block(self, node):
299 """Stop visiting at blocks."""
302 class CompilerExit(Exception):
303 """Raised if the compiler encountered a situation where it just
304 doesn't make sense to further process the code. Any block that
305 raises such an exception is not further processed.
309 class CodeGenerator(NodeVisitor):
311 def __init__(self, environment, name, filename, stream=None):
314 self.environment = environment
316 self.filename = filename
319 # aliases for imports
320 self.import_aliases = {}
322 # a registry for all blocks. Because blocks are moved out
323 # into the global python scope they are registered here
326 # the number of extends statements so far
327 self.extends_so_far = 0
329 # some templates have a rootlevel extends. In this case we
330 # can safely assume that we're a child template and do some
331 # more optimizations.
332 self.has_known_extends = False
334 # the current line number
337 # registry of all filters and tests (global, not block local)
341 # the debug information
343 self._write_debug_info = None
345 # the number of new lines before the next write()
348 # the line number of the last written statement
351 # true if nothing was written so far.
352 self._first_write = True
354 # used by the `temporary_identifier` method to get new
355 # unique, temporary identifier
356 self._last_identifier = 0
358 # the current indentation
359 self._indentation = 0
361 # -- Various compilation helpers
363 def fail(self, msg, lineno):
364 """Fail with a `TemplateAssertionError`."""
365 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
367 def temporary_identifier(self):
368 """Get a new unique identifier."""
369 self._last_identifier += 1
370 return 't_%d' % self._last_identifier
372 def buffer(self, frame):
373 """Enable buffering for the frame from that point onwards."""
374 frame.buffer = self.temporary_identifier()
375 self.writeline('%s = []' % frame.buffer)
377 def return_buffer_contents(self, frame):
378 """Return the buffer contents of the frame."""
379 if self.environment.autoescape:
380 self.writeline('return Markup(concat(%s))' % frame.buffer)
382 self.writeline('return concat(%s)' % frame.buffer)
386 self._indentation += 1
388 def outdent(self, step=1):
389 """Outdent by step."""
390 self._indentation -= step
392 def start_write(self, frame, node=None):
393 """Yield or write into the frame buffer."""
394 if frame.buffer is None:
395 self.writeline('yield ', node)
397 self.writeline('%s.append(' % frame.buffer, node)
399 def end_write(self, frame):
400 """End the writing process started by `start_write`."""
401 if frame.buffer is not None:
404 def simple_write(self, s, frame, node=None):
405 """Simple shortcut for start_write + write + end_write."""
406 self.start_write(frame, node)
408 self.end_write(frame)
410 def blockvisit(self, nodes, frame):
411 """Visit a list of nodes as block in a frame. If the current frame
412 is no buffer a dummy ``if 0: yield None`` is written automatically
413 unless the force_generator parameter is set to False.
415 if frame.buffer is None:
416 self.writeline('if 0: yield None')
418 self.writeline('pass')
421 self.visit(node, frame)
426 """Write a string into the output stream."""
428 if not self._first_write:
429 self.stream.write('\n' * self._new_lines)
430 self.code_lineno += self._new_lines
431 if self._write_debug_info is not None:
432 self.debug_info.append((self._write_debug_info,
434 self._write_debug_info = None
435 self._first_write = False
436 self.stream.write(' ' * self._indentation)
440 def writeline(self, x, node=None, extra=0):
441 """Combination of newline and write."""
442 self.newline(node, extra)
445 def newline(self, node=None, extra=0):
446 """Add one or more newlines before the next write."""
447 self._new_lines = max(self._new_lines, 1 + extra)
448 if node is not None and node.lineno != self._last_line:
449 self._write_debug_info = node.lineno
450 self._last_line = node.lineno
452 def signature(self, node, frame, extra_kwargs=None):
453 """Writes a function call to the stream for the current node.
454 A leading comma is added automatically. The extra keyword
455 arguments may not include python keywords otherwise a syntax
456 error could occour. The extra keyword arguments should be given
459 # if any of the given keyword arguments is a python keyword
460 # we have to make sure that no invalid call is created.
461 kwarg_workaround = False
462 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
463 if is_python_keyword(kwarg):
464 kwarg_workaround = True
467 for arg in node.args:
469 self.visit(arg, frame)
471 if not kwarg_workaround:
472 for kwarg in node.kwargs:
474 self.visit(kwarg, frame)
475 if extra_kwargs is not None:
476 for key, value in extra_kwargs.iteritems():
477 self.write(', %s=%s' % (key, value))
480 self.visit(node.dyn_args, frame)
483 if node.dyn_kwargs is not None:
484 self.write(', **dict({')
487 for kwarg in node.kwargs:
488 self.write('%r: ' % kwarg.key)
489 self.visit(kwarg.value, frame)
491 if extra_kwargs is not None:
492 for key, value in extra_kwargs.iteritems():
493 self.write('%r: %s, ' % (key, value))
494 if node.dyn_kwargs is not None:
496 self.visit(node.dyn_kwargs, frame)
501 elif node.dyn_kwargs is not None:
503 self.visit(node.dyn_kwargs, frame)
505 def pull_locals(self, frame):
506 """Pull all the references identifiers into the local scope."""
507 for name in frame.identifiers.undeclared:
508 self.writeline('l_%s = context.resolve(%r)' % (name, name))
510 def pull_dependencies(self, nodes):
511 """Pull all the dependencies."""
512 visitor = DependencyFinderVisitor()
515 for dependency in 'filters', 'tests':
516 mapping = getattr(self, dependency)
517 for name in getattr(visitor, dependency):
518 if name not in mapping:
519 mapping[name] = self.temporary_identifier()
520 self.writeline('%s = environment.%s[%r]' %
521 (mapping[name], dependency, name))
523 def push_scope(self, frame, extra_vars=()):
524 """This function returns all the shadowed variables in a dict
525 in the form name: alias and will write the required assignments
526 into the current scope. No indentation takes place.
528 This also predefines locally declared variables from the loop
529 body because under some circumstances it may be the case that
531 `extra_vars` is passed to `Identifiers.find_shadowed`.
534 for name in frame.identifiers.find_shadowed(extra_vars):
535 aliases[name] = ident = self.temporary_identifier()
536 self.writeline('%s = l_%s' % (ident, name))
538 for name in frame.identifiers.declared_locally:
539 if name not in aliases:
540 to_declare.add('l_' + name)
542 self.writeline(' = '.join(to_declare) + ' = missing')
545 def pop_scope(self, aliases, frame):
546 """Restore all aliases and delete unused variables."""
547 for name, alias in aliases.iteritems():
548 self.writeline('l_%s = %s' % (name, alias))
550 for name in frame.identifiers.declared_locally:
551 if name not in aliases:
552 to_delete.add('l_' + name)
554 self.writeline('del ' + ', '.join(to_delete))
556 def function_scoping(self, node, frame, children=None,
558 """In Jinja a few statements require the help of anonymous
559 functions. Those are currently macros and call blocks and in
560 the future also recursive loops. As there is currently
561 technical limitation that doesn't allow reading and writing a
562 variable in a scope where the initial value is coming from an
563 outer scope, this function tries to fall back with a common
564 error message. Additionally the frame passed is modified so
565 that the argumetns are collected and callers are looked up.
567 This will return the modified frame.
569 # we have to iterate twice over it, make sure that works
571 children = node.iter_child_nodes()
572 children = list(children)
573 func_frame = frame.inner()
574 func_frame.inspect(children, hard_scope=True)
576 # variables that are undeclared (accessed before declaration) and
577 # declared locally *and* part of an outside scope raise a template
578 # assertion error. Reason: we can't generate reasonable code from
579 # it without aliasing all the variables. XXX: alias them ^^
580 overriden_closure_vars = (
581 func_frame.identifiers.undeclared &
582 func_frame.identifiers.declared &
583 (func_frame.identifiers.declared_locally |
584 func_frame.identifiers.declared_parameter)
586 if overriden_closure_vars:
587 self.fail('It\'s not possible to set and access variables '
588 'derived from an outer scope! (affects: %s' %
589 ', '.join(sorted(overriden_closure_vars)), node.lineno)
591 # remove variables from a closure from the frame's undeclared
593 func_frame.identifiers.undeclared -= (
594 func_frame.identifiers.undeclared &
595 func_frame.identifiers.declared
598 # no special variables for this scope, abort early
602 func_frame.accesses_kwargs = False
603 func_frame.accesses_varargs = False
604 func_frame.accesses_caller = False
605 func_frame.arguments = args = ['l_' + x.name for x in node.args]
607 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
609 if 'caller' in undeclared:
610 func_frame.accesses_caller = True
611 func_frame.identifiers.add_special('caller')
612 args.append('l_caller')
613 if 'kwargs' in undeclared:
614 func_frame.accesses_kwargs = True
615 func_frame.identifiers.add_special('kwargs')
616 args.append('l_kwargs')
617 if 'varargs' in undeclared:
618 func_frame.accesses_varargs = True
619 func_frame.identifiers.add_special('varargs')
620 args.append('l_varargs')
623 def macro_body(self, node, frame, children=None):
624 """Dump the function def of a macro or call block."""
625 frame = self.function_scoping(node, frame, children)
626 # macros are delayed, they never require output checks
627 frame.require_output_check = False
628 args = frame.arguments
629 self.writeline('def macro(%s):' % ', '.join(args), node)
632 self.pull_locals(frame)
633 self.blockvisit(node.body, frame)
634 self.return_buffer_contents(frame)
638 def macro_def(self, node, frame):
639 """Dump the macro definition for the def created by macro_body."""
640 arg_tuple = ', '.join(repr(x.name) for x in node.args)
641 name = getattr(node, 'name', None)
642 if len(node.args) == 1:
644 self.write('Macro(environment, macro, %r, (%s), (' %
646 for arg in node.defaults:
647 self.visit(arg, frame)
649 self.write('), %r, %r, %r)' % (
650 bool(frame.accesses_kwargs),
651 bool(frame.accesses_varargs),
652 bool(frame.accesses_caller)
655 def position(self, node):
656 """Return a human readable position for the node."""
657 rv = 'line %d' % node.lineno
658 if self.name is not None:
659 rv += ' in ' + repr(self.name)
662 # -- Statement Visitors
664 def visit_Template(self, node, frame=None):
665 assert frame is None, 'no root frame allowed'
666 from jinja2.runtime import __all__ as exported
667 self.writeline('from __future__ import division')
668 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
670 # do we have an extends tag at all? If not, we can save some
671 # overhead by just not processing any inheritance code.
672 have_extends = node.find(nodes.Extends) is not None
675 for block in node.find_all(nodes.Block):
676 if block.name in self.blocks:
677 self.fail('block %r defined twice' % block.name, block.lineno)
678 self.blocks[block.name] = block
680 # find all imports and import them
681 for import_ in node.find_all(nodes.ImportedName):
682 if import_.importname not in self.import_aliases:
683 imp = import_.importname
684 self.import_aliases[imp] = alias = self.temporary_identifier()
686 module, obj = imp.rsplit('.', 1)
687 self.writeline('from %s import %s as %s' %
688 (module, obj, alias))
690 self.writeline('import %s as %s' % (imp, alias))
693 self.writeline('name = %r' % self.name)
695 # generate the root render function.
696 self.writeline('def root(context, environment=environment):', extra=1)
700 frame.inspect(node.body)
701 frame.toplevel = frame.rootlevel = True
702 frame.require_output_check = have_extends and not self.has_known_extends
705 self.writeline('parent_template = None')
706 if 'self' in find_undeclared(node.body, ('self',)):
707 frame.identifiers.add_special('self')
708 self.writeline('l_self = TemplateReference(context)')
709 self.pull_locals(frame)
710 self.pull_dependencies(node.body)
711 self.blockvisit(node.body, frame)
714 # make sure that the parent root is called.
716 if not self.has_known_extends:
718 self.writeline('if parent_template is not None:')
720 self.writeline('for event in parent_template.'
721 'root_render_func(context):')
723 self.writeline('yield event')
724 self.outdent(2 + (not self.has_known_extends))
726 # at this point we now have the blocks collected and can visit them too.
727 for name, block in self.blocks.iteritems():
728 block_frame = Frame()
729 block_frame.inspect(block.body)
730 block_frame.block = name
731 self.writeline('def block_%s(context, environment=environment):'
734 undeclared = find_undeclared(block.body, ('self', 'super'))
735 if 'self' in undeclared:
736 block_frame.identifiers.add_special('self')
737 self.writeline('l_self = TemplateReference(context)')
738 if 'super' in undeclared:
739 block_frame.identifiers.add_special('super')
740 self.writeline('l_super = context.super(%r, '
741 'block_%s)' % (name, name))
742 self.pull_locals(block_frame)
743 self.pull_dependencies(block.body)
744 self.blockvisit(block.body, block_frame)
747 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
748 for x in self.blocks),
751 # add a function that returns the debug info
752 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
755 def visit_Block(self, node, frame):
756 """Call a block and register it for the template."""
759 # if we know that we are a child template, there is no need to
760 # check if we are one
761 if self.has_known_extends:
763 if self.extends_so_far > 0:
764 self.writeline('if parent_template is None:')
767 self.writeline('for event in context.blocks[%r][0](context):' %
770 self.simple_write('event', frame)
773 def visit_Extends(self, node, frame):
774 """Calls the extender."""
775 if not frame.toplevel:
776 self.fail('cannot use extend from a non top-level scope',
779 # if the number of extends statements in general is zero so
780 # far, we don't have to add a check if something extended
781 # the template before this one.
782 if self.extends_so_far > 0:
784 # if we have a known extends we just add a template runtime
785 # error into the generated code. We could catch that at compile
786 # time too, but i welcome it not to confuse users by throwing the
787 # same error at different times just "because we can".
788 if not self.has_known_extends:
789 self.writeline('if parent_template is not None:')
791 self.writeline('raise TemplateRuntimeError(%r)' %
792 'extended multiple times')
795 # if we have a known extends already we don't need that code here
796 # as we know that the template execution will end here.
797 if self.has_known_extends:
800 self.writeline('parent_template = environment.get_template(', node)
801 self.visit(node.template, frame)
802 self.write(', %r)' % self.name)
803 self.writeline('for name, parent_block in parent_template.'
804 'blocks.iteritems():')
806 self.writeline('context.blocks.setdefault(name, []).'
807 'append(parent_block)')
810 # if this extends statement was in the root level we can take
811 # advantage of that information and simplify the generated code
812 # in the top level from this point onwards
814 self.has_known_extends = True
816 # and now we have one more
817 self.extends_so_far += 1
819 def visit_Include(self, node, frame):
820 """Handles includes."""
821 if node.with_context:
822 self.writeline('template = environment.get_template(', node)
823 self.visit(node.template, frame)
824 self.write(', %r)' % self.name)
825 self.writeline('for event in template.root_render_func('
826 'template.new_context(context.parent, True, '
829 self.writeline('for event in environment.get_template(', node)
830 self.visit(node.template, frame)
831 self.write(', %r).module._body_stream:' %
834 self.simple_write('event', frame)
837 def visit_Import(self, node, frame):
838 """Visit regular imports."""
839 self.writeline('l_%s = ' % node.target, node)
841 self.write('context.vars[%r] = ' % node.target)
842 self.write('environment.get_template(')
843 self.visit(node.template, frame)
844 self.write(', %r).' % self.name)
845 if node.with_context:
846 self.write('make_module(context.parent, True, locals())')
849 if frame.toplevel and not node.target.startswith('_'):
850 self.writeline('context.exported_vars.discard(%r)' % node.target)
852 def visit_FromImport(self, node, frame):
853 """Visit named imports."""
855 self.write('included_template = environment.get_template(')
856 self.visit(node.template, frame)
857 self.write(', %r).' % self.name)
858 if node.with_context:
859 self.write('make_module(context.parent, True)')
865 for name in node.names:
866 if isinstance(name, tuple):
870 self.writeline('l_%s = getattr(included_template, '
871 '%r, missing)' % (alias, name))
872 self.writeline('if l_%s is missing:' % alias)
874 self.writeline('l_%s = environment.undefined(%r %% '
875 'included_template.__name__, '
877 (alias, 'the template %%r (imported on %s) does '
878 'not export the requested name %s' % (
884 var_names.append(alias)
885 if not alias.startswith('_'):
886 discarded_names.append(alias)
889 if len(var_names) == 1:
891 self.writeline('context.vars[%r] = l_%s' % (name, name))
893 self.writeline('context.vars.update({%s})' % ', '.join(
894 '%r: l_%s' % (name, name) for name in var_names
897 if len(discarded_names) == 1:
898 self.writeline('context.exported_vars.discard(%r)' %
901 self.writeline('context.exported_vars.difference_'
902 'update((%s))' % ', '.join(map(repr, discarded_names)))
904 def visit_For(self, node, frame):
905 # when calculating the nodes for the inner frame we have to exclude
906 # the iterator contents from it
907 children = node.iter_child_nodes(exclude=('iter',))
909 loop_frame = self.function_scoping(node, frame, children,
912 loop_frame = frame.inner()
913 loop_frame.inspect(children)
915 # try to figure out if we have an extended loop. An extended loop
916 # is necessary if the loop is in recursive mode if the special loop
917 # variable is accessed in the body.
918 extended_loop = node.recursive or 'loop' in \
919 find_undeclared(node.iter_child_nodes(
920 only=('body',)), ('loop',))
922 # if we don't have an recursive loop we have to find the shadowed
923 # variables at that point. Because loops can be nested but the loop
924 # variable is a special one we have to enforce aliasing for it.
925 if not node.recursive:
926 aliases = self.push_scope(loop_frame, ('loop',))
928 # otherwise we set up a buffer and add a function def
930 self.writeline('def loop(reciter, loop_render_func):', node)
932 self.buffer(loop_frame)
935 # make sure the loop variable is a special one and raise a template
936 # assertion error if a loop tries to write to loop
938 loop_frame.identifiers.add_special('loop')
939 for name in node.find_all(nodes.Name):
940 if name.ctx == 'store' and name.name == 'loop':
941 self.fail('Can\'t assign to special loop variable '
942 'in for-loop target', name.lineno)
944 self.pull_locals(loop_frame)
946 iteration_indicator = self.temporary_identifier()
947 self.writeline('%s = 1' % iteration_indicator)
949 # Create a fake parent loop if the else or test section of a
950 # loop is accessing the special loop variable and no parent loop
952 if 'loop' not in aliases and 'loop' in find_undeclared(
953 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
954 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
955 ("'loop' is undefined. the filter section of a loop as well "
956 "as the else block doesn't have access to the special 'loop'"
957 " variable of the current loop. Because there is no parent "
958 "loop it's undefined. Happened in loop on %s" %
959 self.position(node)))
961 self.writeline('for ', node)
962 self.visit(node.target, loop_frame)
963 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
965 # if we have an extened loop and a node test, we filter in the
967 if extended_loop and node.test is not None:
969 self.visit(node.target, loop_frame)
971 self.visit(node.target, loop_frame)
974 self.write('reciter')
976 self.visit(node.iter, loop_frame)
978 test_frame = loop_frame.copy()
979 self.visit(node.test, test_frame)
983 self.write('reciter')
985 self.visit(node.iter, loop_frame)
988 self.write(', recurse=loop_render_func):')
990 self.write(extended_loop and '):' or ':')
992 # tests in not extended loops become a continue
993 if not extended_loop and node.test is not None:
995 self.writeline('if not ')
996 self.visit(node.test, loop_frame)
999 self.writeline('continue')
1003 self.blockvisit(node.body, loop_frame)
1005 self.writeline('%s = 0' % iteration_indicator)
1009 self.writeline('if %s:' % iteration_indicator)
1011 self.blockvisit(node.else_, loop_frame)
1014 # reset the aliases if there are any.
1015 if not node.recursive:
1016 self.pop_scope(aliases, loop_frame)
1018 # if the node was recursive we have to return the buffer contents
1019 # and start the iteration code
1021 self.return_buffer_contents(loop_frame)
1023 self.start_write(frame, node)
1025 self.visit(node.iter, frame)
1026 self.write(', loop)')
1027 self.end_write(frame)
1029 def visit_If(self, node, frame):
1030 if_frame = frame.soft()
1031 self.writeline('if ', node)
1032 self.visit(node.test, if_frame)
1035 self.blockvisit(node.body, if_frame)
1038 self.writeline('else:')
1040 self.blockvisit(node.else_, if_frame)
1043 def visit_Macro(self, node, frame):
1044 macro_frame = self.macro_body(node, frame)
1047 if not node.name.startswith('_'):
1048 self.write('context.exported_vars.add(%r)' % node.name)
1049 self.writeline('context.vars[%r] = ' % node.name)
1050 self.write('l_%s = ' % node.name)
1051 self.macro_def(node, macro_frame)
1053 def visit_CallBlock(self, node, frame):
1054 children = node.iter_child_nodes(exclude=('call',))
1055 call_frame = self.macro_body(node, frame, children)
1056 self.writeline('caller = ')
1057 self.macro_def(node, call_frame)
1058 self.start_write(frame, node)
1059 self.visit_Call(node.call, call_frame, forward_caller=True)
1060 self.end_write(frame)
1062 def visit_FilterBlock(self, node, frame):
1063 filter_frame = frame.inner()
1064 filter_frame.inspect(node.iter_child_nodes())
1065 aliases = self.push_scope(filter_frame)
1066 self.pull_locals(filter_frame)
1067 self.buffer(filter_frame)
1068 self.blockvisit(node.body, filter_frame)
1069 self.start_write(frame, node)
1070 self.visit_Filter(node.filter, filter_frame)
1071 self.end_write(frame)
1072 self.pop_scope(aliases, filter_frame)
1074 def visit_ExprStmt(self, node, frame):
1076 self.visit(node.node, frame)
1078 def visit_Output(self, node, frame):
1079 # if we have a known extends statement, we don't output anything
1080 # if we are in a require_output_check section
1081 if self.has_known_extends and frame.require_output_check:
1084 if self.environment.finalize:
1085 finalize = lambda x: unicode(self.environment.finalize(x))
1091 # if we are inside a frame that requires output checking, we do so
1092 outdent_later = False
1093 if frame.require_output_check:
1094 self.writeline('if parent_template is None:')
1096 outdent_later = True
1098 # try to evaluate as many chunks as possible into a static
1099 # string at compile time.
1101 for child in node.nodes:
1103 const = child.as_const()
1104 except nodes.Impossible:
1108 if self.environment.autoescape:
1109 if hasattr(const, '__html__'):
1110 const = const.__html__()
1112 const = escape(const)
1113 const = finalize(const)
1115 # if something goes wrong here we evaluate the node
1116 # at runtime for easier debugging
1119 if body and isinstance(body[-1], list):
1120 body[-1].append(const)
1122 body.append([const])
1124 # if we have less than 3 nodes or a buffer we yield or extend/append
1125 if len(body) < 3 or frame.buffer is not None:
1126 if frame.buffer is not None:
1127 # for one item we append, for more we extend
1129 self.writeline('%s.append(' % frame.buffer)
1131 self.writeline('%s.extend((' % frame.buffer)
1134 if isinstance(item, list):
1135 val = repr(concat(item))
1136 if frame.buffer is None:
1137 self.writeline('yield ' + val)
1139 self.writeline(val + ', ')
1141 if frame.buffer is None:
1142 self.writeline('yield ', item)
1146 if self.environment.autoescape:
1147 self.write('escape(')
1149 self.write('unicode(')
1150 if self.environment.finalize is not None:
1151 self.write('environment.finalize(')
1153 self.visit(item, frame)
1154 self.write(')' * close)
1155 if frame.buffer is not None:
1157 if frame.buffer is not None:
1158 # close the open parentheses
1160 self.writeline(len(body) == 1 and ')' or '))')
1162 # otherwise we create a format string as this is faster in that case
1167 if isinstance(item, list):
1168 format.append(concat(item).replace('%', '%%'))
1171 arguments.append(item)
1172 self.writeline('yield ')
1173 self.write(repr(concat(format)) + ' % (')
1176 for argument in arguments:
1177 self.newline(argument)
1179 if self.environment.autoescape:
1180 self.write('escape(')
1182 if self.environment.finalize is not None:
1183 self.write('environment.finalize(')
1185 self.visit(argument, frame)
1186 self.write(')' * close + ', ')
1193 def visit_Assign(self, node, frame):
1195 # toplevel assignments however go into the local namespace and
1196 # the current template's context. We create a copy of the frame
1197 # here and add a set so that the Name visitor can add the assigned
1200 assignment_frame = frame.copy()
1201 assignment_frame.assigned_names = set()
1203 assignment_frame = frame
1204 self.visit(node.target, assignment_frame)
1206 self.visit(node.node, frame)
1208 # make sure toplevel assignments are added to the context.
1210 public_names = [x for x in assignment_frame.assigned_names
1211 if not x.startswith('_')]
1212 if len(assignment_frame.assigned_names) == 1:
1213 name = iter(assignment_frame.assigned_names).next()
1214 self.writeline('context.vars[%r] = l_%s' % (name, name))
1216 self.writeline('context.vars.update({')
1217 for idx, name in enumerate(assignment_frame.assigned_names):
1220 self.write('%r: l_%s' % (name, name))
1223 if len(public_names) == 1:
1224 self.writeline('context.exported_vars.add(%r)' %
1227 self.writeline('context.exported_vars.update((%s))' %
1228 ', '.join(map(repr, public_names)))
1230 # -- Expression Visitors
1232 def visit_Name(self, node, frame):
1233 if node.ctx == 'store' and frame.toplevel:
1234 frame.assigned_names.add(node.name)
1235 self.write('l_' + node.name)
1237 def visit_Const(self, node, frame):
1239 if isinstance(val, float):
1240 self.write(str(val))
1242 self.write(repr(val))
1244 def visit_TemplateData(self, node, frame):
1245 self.write(repr(node.as_const()))
1247 def visit_Tuple(self, node, frame):
1250 for idx, item in enumerate(node.items):
1253 self.visit(item, frame)
1254 self.write(idx == 0 and ',)' or ')')
1256 def visit_List(self, node, frame):
1258 for idx, item in enumerate(node.items):
1261 self.visit(item, frame)
1264 def visit_Dict(self, node, frame):
1266 for idx, item in enumerate(node.items):
1269 self.visit(item.key, frame)
1271 self.visit(item.value, frame)
1274 def binop(operator):
1275 def visitor(self, node, frame):
1277 self.visit(node.left, frame)
1278 self.write(' %s ' % operator)
1279 self.visit(node.right, frame)
1284 def visitor(self, node, frame):
1285 self.write('(' + operator)
1286 self.visit(node.node, frame)
1290 visit_Add = binop('+')
1291 visit_Sub = binop('-')
1292 visit_Mul = binop('*')
1293 visit_Div = binop('/')
1294 visit_FloorDiv = binop('//')
1295 visit_Pow = binop('**')
1296 visit_Mod = binop('%')
1297 visit_And = binop('and')
1298 visit_Or = binop('or')
1299 visit_Pos = uaop('+')
1300 visit_Neg = uaop('-')
1301 visit_Not = uaop('not ')
1304 def visit_Concat(self, node, frame):
1305 self.write('%s((' % (self.environment.autoescape and
1306 'markup_join' or 'unicode_join'))
1307 for arg in node.nodes:
1308 self.visit(arg, frame)
1312 def visit_Compare(self, node, frame):
1313 self.visit(node.expr, frame)
1315 self.visit(op, frame)
1317 def visit_Operand(self, node, frame):
1318 self.write(' %s ' % operators[node.op])
1319 self.visit(node.expr, frame)
1321 def visit_Getattr(self, node, frame):
1322 self.write('environment.getattr(')
1323 self.visit(node.node, frame)
1324 self.write(', %r)' % node.attr)
1326 def visit_Getitem(self, node, frame):
1327 # slices bypass the environment getitem method.
1328 if isinstance(node.arg, nodes.Slice):
1329 self.visit(node.node, frame)
1331 self.visit(node.arg, frame)
1334 self.write('environment.getitem(')
1335 self.visit(node.node, frame)
1337 self.visit(node.arg, frame)
1340 def visit_Slice(self, node, frame):
1341 if node.start is not None:
1342 self.visit(node.start, frame)
1344 if node.stop is not None:
1345 self.visit(node.stop, frame)
1346 if node.step is not None:
1348 self.visit(node.step, frame)
1350 def visit_Filter(self, node, frame):
1351 self.write(self.filters[node.name] + '(')
1352 func = self.environment.filters.get(node.name)
1354 self.fail('no filter named %r' % node.name, node.lineno)
1355 if getattr(func, 'contextfilter', False):
1356 self.write('context, ')
1357 elif getattr(func, 'environmentfilter', False):
1358 self.write('environment, ')
1360 # if the filter node is None we are inside a filter block
1361 # and want to write to the current buffer
1362 if node.node is not None:
1363 self.visit(node.node, frame)
1364 elif self.environment.autoescape:
1365 self.write('Markup(concat(%s))' % frame.buffer)
1367 self.write('concat(%s)' % frame.buffer)
1368 self.signature(node, frame)
1371 def visit_Test(self, node, frame):
1372 self.write(self.tests[node.name] + '(')
1373 if node.name not in self.environment.tests:
1374 self.fail('no test named %r' % node.name, node.lineno)
1375 self.visit(node.node, frame)
1376 self.signature(node, frame)
1379 def visit_CondExpr(self, node, frame):
1381 if node.expr2 is not None:
1382 return self.visit(node.expr2, frame)
1383 self.write('environment.undefined(%r)' % ('the inline if-'
1384 'expression on %s evaluated to false and '
1385 'no else section was defined.' % self.position(node)))
1387 if not have_condexpr:
1389 self.visit(node.test, frame)
1390 self.write(') and (')
1391 self.visit(node.expr1, frame)
1392 self.write(',) or (')
1394 self.write(',))[0]')
1397 self.visit(node.expr1, frame)
1399 self.visit(node.test, frame)
1400 self.write(' else ')
1404 def visit_Call(self, node, frame, forward_caller=False):
1405 if self.environment.sandboxed:
1406 self.write('environment.call(context, ')
1408 self.write('context.call(')
1409 self.visit(node.node, frame)
1410 extra_kwargs = forward_caller and {'caller': 'caller'} or None
1411 self.signature(node, frame, extra_kwargs)
1414 def visit_Keyword(self, node, frame):
1415 self.write(node.key + '=')
1416 self.visit(node.value, frame)
1418 # -- Unused nodes for extensions
1420 def visit_MarkSafe(self, node, frame):
1421 self.write('Markup(')
1422 self.visit(node.expr, frame)
1425 def visit_EnvironmentAttribute(self, node, frame):
1426 self.write('environment.' + node.name)
1428 def visit_ExtensionAttribute(self, node, frame):
1429 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
1431 def visit_ImportedName(self, node, frame):
1432 self.write(self.import_aliases[node.importname])
1434 def visit_InternalName(self, node, frame):
1435 self.write(node.name)
1437 def visit_ContextReference(self, node, frame):
1438 self.write('context')
1440 def visit_Continue(self, node, frame):
1441 self.writeline('continue', node)
1443 def visit_Break(self, node, frame):
1444 self.writeline('break', node)