1 # -*- coding: utf-8 -*-
6 Compiles nodes into python code.
8 :copyright: Copyright 2008 by Armin Ronacher.
13 from random import randrange
14 from keyword import iskeyword
15 from cStringIO import StringIO
16 from itertools import chain
17 from jinja2 import nodes
18 from jinja2.visitor import NodeVisitor, NodeTransformer
19 from jinja2.exceptions import TemplateAssertionError
20 from jinja2.runtime import concat
21 from jinja2.utils import Markup
36 exec '(0 if 0 else 0)'
43 def generate(node, environment, name, filename, stream=None):
44 """Generate the python source for a node tree."""
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
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 in ('store', 'param'):
249 self.identifiers.declared_locally.add(node.name)
250 elif node.ctx == 'load' and not \
251 self.identifiers.is_declared(node.name, self.hard_scope):
252 self.identifiers.undeclared.add(node.name)
254 def visit_Macro(self, node):
255 self.generic_visit(node)
256 self.identifiers.declared_locally.add(node.name)
258 def visit_Import(self, node):
259 self.generic_visit(node)
260 self.identifiers.declared_locally.add(node.target)
262 def visit_FromImport(self, node):
263 self.generic_visit(node)
264 for name in node.names:
265 if isinstance(name, tuple):
266 self.identifiers.declared_locally.add(name[1])
268 self.identifiers.declared_locally.add(name)
270 def visit_Assign(self, node):
271 """Visit assignments in the correct order."""
272 self.visit(node.node)
273 self.visit(node.target)
275 def visit_For(self, node):
276 """Visiting stops at for blocks. However the block sequence
277 is visited as part of the outer scope.
279 self.visit(node.iter)
281 def visit_CallBlock(self, node):
282 for child in node.iter_child_nodes(exclude=('body',)):
285 def visit_FilterBlock(self, node):
286 self.visit(node.filter)
288 def visit_Block(self, node):
289 """Stop visiting at blocks."""
292 class CompilerExit(Exception):
293 """Raised if the compiler encountered a situation where it just
294 doesn't make sense to further process the code. Any block that
295 raises such an exception is not further processed.
299 class CodeGenerator(NodeVisitor):
301 def __init__(self, environment, name, filename, stream=None):
304 self.environment = environment
306 self.filename = filename
309 # a registry for all blocks. Because blocks are moved out
310 # into the global python scope they are registered here
313 # the number of extends statements so far
314 self.extends_so_far = 0
316 # some templates have a rootlevel extends. In this case we
317 # can safely assume that we're a child template and do some
318 # more optimizations.
319 self.has_known_extends = False
321 # the current line number
324 # the debug information
326 self._write_debug_info = None
328 # the number of new lines before the next write()
331 # the line number of the last written statement
334 # true if nothing was written so far.
335 self._first_write = True
337 # used by the `temporary_identifier` method to get new
338 # unique, temporary identifier
339 self._last_identifier = 0
341 # the current indentation
342 self._indentation = 0
344 def temporary_identifier(self):
345 """Get a new unique identifier."""
346 self._last_identifier += 1
347 return 't%d' % self._last_identifier
351 self._indentation += 1
353 def outdent(self, step=1):
354 """Outdent by step."""
355 self._indentation -= step
357 def blockvisit(self, nodes, frame, force_generator=True):
358 """Visit a list of nodes as block in a frame. If the current frame
359 is no buffer a dummy ``if 0: yield None`` is written automatically
360 unless the force_generator parameter is set to False.
362 if frame.buffer is None and force_generator:
363 self.writeline('if 0: yield None')
366 self.visit(node, frame)
371 """Write a string into the output stream."""
373 if not self._first_write:
374 self.stream.write('\n' * self._new_lines)
375 self.code_lineno += self._new_lines
376 if self._write_debug_info is not None:
377 self.debug_info.append((self._write_debug_info,
379 self._write_debug_info = None
380 self._first_write = False
381 self.stream.write(' ' * self._indentation)
385 def writeline(self, x, node=None, extra=0):
386 """Combination of newline and write."""
387 self.newline(node, extra)
390 def newline(self, node=None, extra=0):
391 """Add one or more newlines before the next write."""
392 self._new_lines = max(self._new_lines, 1 + extra)
393 if node is not None and node.lineno != self._last_line:
394 self._write_debug_info = node.lineno
395 self._last_line = node.lineno
397 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
398 """Writes a function call to the stream for the current node.
399 Per default it will write a leading comma but this can be
400 disabled by setting have_comma to False. The extra keyword
401 arguments may not include python keywords otherwise a syntax
402 error could occour. The extra keyword arguments should be given
405 have_comma = have_comma and [True] or []
410 have_comma.append(True)
412 # if any of the given keyword arguments is a python keyword
413 # we have to make sure that no invalid call is created.
414 kwarg_workaround = False
415 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
417 kwarg_workaround = True
420 for arg in node.args:
422 self.visit(arg, frame)
424 if not kwarg_workaround:
425 for kwarg in node.kwargs:
427 self.visit(kwarg, frame)
428 if extra_kwargs is not None:
429 for key, value in extra_kwargs.iteritems():
431 self.write('%s=%s' % (key, value))
435 self.visit(node.dyn_args, frame)
439 if node.dyn_kwargs is not None:
440 self.write('**dict({')
443 for kwarg in node.kwargs:
444 self.write('%r: ' % kwarg.key)
445 self.visit(kwarg.value, frame)
447 if extra_kwargs is not None:
448 for key, value in extra_kwargs.iteritems():
449 self.write('%r: %s, ' % (key, value))
450 if node.dyn_kwargs is not None:
452 self.visit(node.dyn_kwargs, frame)
457 elif node.dyn_kwargs is not None:
460 self.visit(node.dyn_kwargs, frame)
462 def pull_locals(self, frame):
463 """Pull all the references identifiers into the local scope."""
464 for name in frame.identifiers.undeclared:
465 self.writeline('l_%s = context[%r]' % (name, name))
467 def pull_dependencies(self, nodes):
468 """Pull all the dependencies."""
469 visitor = DependencyFinderVisitor()
472 for name in visitor.filters:
473 self.writeline('f_%s = environment.filters[%r]' % (name, name))
474 for name in visitor.tests:
475 self.writeline('t_%s = environment.tests[%r]' % (name, name))
477 def collect_shadowed(self, frame):
478 """This function returns all the shadowed variables in a dict
479 in the form name: alias and will write the required assignments
480 into the current scope. No indentation takes place.
482 # make sure we "backup" overridden, local identifiers
483 # TODO: we should probably optimize this and check if the
484 # identifier is in use afterwards.
486 for name in frame.identifiers.find_shadowed():
487 aliases[name] = ident = self.temporary_identifier()
488 self.writeline('%s = l_%s' % (ident, name))
491 def function_scoping(self, node, frame, children=None):
492 """In Jinja a few statements require the help of anonymous
493 functions. Those are currently macros and call blocks and in
494 the future also recursive loops. As there is currently
495 technical limitation that doesn't allow reading and writing a
496 variable in a scope where the initial value is coming from an
497 outer scope, this function tries to fall back with a common
498 error message. Additionally the frame passed is modified so
499 that the argumetns are collected and callers are looked up.
501 This will return the modified frame.
503 # we have to iterate twice over it, make sure that works
505 children = node.iter_child_nodes()
506 children = list(children)
507 func_frame = frame.inner()
508 func_frame.inspect(children, hard_scope=True)
510 # variables that are undeclared (accessed before declaration) and
511 # declared locally *and* part of an outside scope raise a template
512 # assertion error. Reason: we can't generate reasonable code from
513 # it without aliasing all the variables. XXX: alias them ^^
514 overriden_closure_vars = (
515 func_frame.identifiers.undeclared &
516 func_frame.identifiers.declared &
517 (func_frame.identifiers.declared_locally |
518 func_frame.identifiers.declared_parameter)
520 if overriden_closure_vars:
521 vars = ', '.join(sorted(overriden_closure_vars))
522 raise TemplateAssertionError('It\'s not possible to set and '
523 'access variables derived from '
524 'an outer scope! (affects: %s' %
525 vars, node.lineno, self.name)
527 # remove variables from a closure from the frame's undeclared
529 func_frame.identifiers.undeclared -= (
530 func_frame.identifiers.undeclared &
531 func_frame.identifiers.declared
534 func_frame.accesses_kwargs = False
535 func_frame.accesses_varargs = False
536 func_frame.accesses_caller = False
537 func_frame.arguments = args = ['l_' + x.name for x in node.args]
539 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
541 if 'caller' in undeclared:
542 func_frame.accesses_caller = True
543 func_frame.identifiers.add_special('caller')
544 args.append('l_caller')
545 if 'kwargs' in undeclared:
546 func_frame.accesses_kwargs = True
547 func_frame.identifiers.add_special('kwargs')
548 args.append('l_kwargs')
549 if 'varargs' in undeclared:
550 func_frame.accesses_varargs = True
551 func_frame.identifiers.add_special('varargs')
552 args.append('l_varargs')
557 def visit_Template(self, node, frame=None):
558 assert frame is None, 'no root frame allowed'
559 from jinja2.runtime import __all__ as exported
560 self.writeline('from __future__ import division')
561 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
562 self.writeline('name = %r' % self.name)
564 # do we have an extends tag at all? If not, we can save some
565 # overhead by just not processing any inheritance code.
566 have_extends = node.find(nodes.Extends) is not None
569 for block in node.find_all(nodes.Block):
570 if block.name in self.blocks:
571 raise TemplateAssertionError('block %r defined twice' %
572 block.name, block.lineno,
574 self.blocks[block.name] = block
576 # generate the root render function.
577 self.writeline('def root(context, environment=environment):', extra=1)
581 frame.inspect(node.body)
582 frame.toplevel = frame.rootlevel = True
585 self.writeline('parent_template = None')
586 self.pull_locals(frame)
587 self.pull_dependencies(node.body)
588 if 'self' in find_undeclared(node.body, ('self',)):
589 frame.identifiers.add_special('self')
590 self.writeline('l_self = TemplateReference(context)')
591 self.blockvisit(node.body, frame)
594 # make sure that the parent root is called.
596 if not self.has_known_extends:
598 self.writeline('if parent_template is not None:')
600 self.writeline('for event in parent_template.'
601 'root_render_func(context):')
603 self.writeline('yield event')
604 self.outdent(2 + (not self.has_known_extends))
606 # at this point we now have the blocks collected and can visit them too.
607 for name, block in self.blocks.iteritems():
608 block_frame = Frame()
609 block_frame.inspect(block.body)
610 block_frame.block = name
611 self.writeline('def block_%s(context, environment=environment):'
614 undeclared = find_undeclared(block.body, ('self', 'super'))
615 if 'self' in undeclared:
616 block_frame.identifiers.add_special('self')
617 self.writeline('l_self = TemplateReference(context)')
618 if 'super' in undeclared:
619 block_frame.identifiers.add_special('super')
620 self.writeline('l_super = context.super(%r, '
621 'block_%s)' % (name, name))
622 self.pull_locals(block_frame)
623 self.pull_dependencies(block.body)
624 self.blockvisit(block.body, block_frame)
627 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
628 for x in self.blocks),
631 # add a function that returns the debug info
632 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
635 def visit_Block(self, node, frame):
636 """Call a block and register it for the template."""
639 # if we know that we are a child template, there is no need to
640 # check if we are one
641 if self.has_known_extends:
643 if self.extends_so_far > 0:
644 self.writeline('if parent_template is None:')
647 self.writeline('for event in context.blocks[%r][-1](context):' %
650 if frame.buffer is None:
651 self.writeline('yield event')
653 self.writeline('%s.append(event)' % frame.buffer)
656 def visit_Extends(self, node, frame):
657 """Calls the extender."""
658 if not frame.toplevel:
659 raise TemplateAssertionError('cannot use extend from a non '
660 'top-level scope', node.lineno,
663 # if the number of extends statements in general is zero so
664 # far, we don't have to add a check if something extended
665 # the template before this one.
666 if self.extends_so_far > 0:
668 # if we have a known extends we just add a template runtime
669 # error into the generated code. We could catch that at compile
670 # time too, but i welcome it not to confuse users by throwing the
671 # same error at different times just "because we can".
672 if not self.has_known_extends:
673 self.writeline('if parent_template is not None:')
675 self.writeline('raise TemplateRuntimeError(%r)' %
676 'extended multiple times')
678 # if we have a known extends already we don't need that code here
679 # as we know that the template execution will end here.
680 if self.has_known_extends:
684 self.writeline('parent_template = environment.get_template(', node, 1)
685 self.visit(node.template, frame)
686 self.write(', %r)' % self.name)
687 self.writeline('for name, parent_block in parent_template.'
688 'blocks.iteritems():')
690 self.writeline('context.blocks.setdefault(name, []).'
691 'insert(0, parent_block)')
694 # if this extends statement was in the root level we can take
695 # advantage of that information and simplify the generated code
696 # in the top level from this point onwards
697 self.has_known_extends = True
699 # and now we have one more
700 self.extends_so_far += 1
702 def visit_Include(self, node, frame):
703 """Handles includes."""
704 if node.with_context:
705 self.writeline('template = environment.get_template(', node)
706 self.visit(node.template, frame)
707 self.write(', %r)' % self.name)
708 self.writeline('for event in template.root_render_func('
709 'template.new_context(context.parent, True)):')
711 self.writeline('for event in environment.get_template(', node)
712 self.visit(node.template, frame)
713 self.write(', %r).module._TemplateModule__body_stream:' %
716 if frame.buffer is None:
717 self.writeline('yield event')
719 self.writeline('%s.append(event)' % frame.buffer)
722 def visit_Import(self, node, frame):
723 """Visit regular imports."""
724 self.writeline('l_%s = ' % node.target, node)
726 self.write('context.vars[%r] = ' % node.target)
727 self.write('environment.get_template(')
728 self.visit(node.template, frame)
729 self.write(', %r).' % self.name)
730 if node.with_context:
731 self.write('make_module(context.parent, True)')
734 if frame.toplevel and not node.target.startswith('__'):
735 self.writeline('context.exported_vars.discard(%r)' % node.target)
737 def visit_FromImport(self, node, frame):
738 """Visit named imports."""
740 self.write('included_template = environment.get_template(')
741 self.visit(node.template, frame)
742 self.write(', %r).' % self.name)
743 if node.with_context:
744 self.write('make_module(context.parent, True)')
747 for name in node.names:
748 if isinstance(name, tuple):
752 self.writeline('l_%s = getattr(included_template, '
753 '%r, missing)' % (alias, name))
754 self.writeline('if l_%s is missing:' % alias)
756 self.writeline('l_%s = environment.undefined(%r %% '
757 'included_template.name, '
758 'name=included_template.name)' %
759 (alias, 'the template %r does not export '
760 'the requested name ' + repr(name)))
763 self.writeline('context.vars[%r] = l_%s' % (alias, alias))
764 if not alias.startswith('__'):
765 self.writeline('context.exported_vars.discard(%r)' % alias)
767 def visit_For(self, node, frame):
768 loop_frame = frame.inner()
769 loop_frame.inspect(node.iter_child_nodes(exclude=('iter',)))
770 extended_loop = bool(node.else_) or \
771 'loop' in loop_frame.identifiers.undeclared
773 loop_frame.identifiers.add_special('loop')
775 aliases = self.collect_shadowed(loop_frame)
776 self.pull_locals(loop_frame)
778 self.writeline('l_loop = None')
781 self.writeline('for ')
782 self.visit(node.target, loop_frame)
783 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
785 # the expression pointing to the parent loop. We make the
786 # undefined a bit more debug friendly at the same time.
787 parent_loop = 'loop' in aliases and aliases['loop'] \
788 or "environment.undefined(%r, name='loop')" % "'loop' " \
789 'is undefined. "the filter section of a loop as well ' \
790 'as the else block doesn\'t have access to the ' \
791 "special 'loop' variable of the current loop. " \
792 "Because there is no parent loop it's undefined."
794 # if we have an extened loop and a node test, we filter in the
796 if extended_loop and node.test is not None:
798 self.visit(node.target, loop_frame)
800 self.visit(node.target, loop_frame)
802 self.visit(node.iter, loop_frame)
804 test_frame = loop_frame.copy()
805 self.writeline('l_loop = ' + parent_loop)
806 self.visit(node.test, test_frame)
810 self.visit(node.iter, loop_frame)
812 self.write(extended_loop and '):' or ':')
814 # tests in not extended loops become a continue
815 if not extended_loop and node.test is not None:
817 self.writeline('if ')
818 self.visit(node.test, loop_frame)
821 self.writeline('continue')
825 self.blockvisit(node.body, loop_frame, force_generator=True)
829 self.writeline('if l_loop is None:')
831 self.writeline('l_loop = ' + parent_loop)
832 self.blockvisit(node.else_, loop_frame, force_generator=False)
835 # reset the aliases if there are any.
836 for name, alias in aliases.iteritems():
837 self.writeline('l_%s = %s' % (name, alias))
839 def visit_If(self, node, frame):
840 if_frame = frame.soft()
841 self.writeline('if ', node)
842 self.visit(node.test, if_frame)
845 self.blockvisit(node.body, if_frame)
848 self.writeline('else:')
850 self.blockvisit(node.else_, if_frame)
853 def visit_Macro(self, node, frame):
854 macro_frame = self.function_scoping(node, frame)
855 args = macro_frame.arguments
856 self.writeline('def macro(%s):' % ', '.join(args), node)
857 macro_frame.buffer = buf = self.temporary_identifier()
859 self.pull_locals(macro_frame)
860 self.writeline('%s = []' % buf)
861 self.blockvisit(node.body, macro_frame)
862 if self.environment.autoescape:
863 self.writeline('return Markup(concat(%s))' % buf)
865 self.writeline("return concat(%s)" % buf)
869 if not node.name.startswith('__'):
870 self.write('context.exported_vars.add(%r)' % node.name)
871 self.writeline('context.vars[%r] = ' % node.name)
872 arg_tuple = ', '.join(repr(x.name) for x in node.args)
873 if len(node.args) == 1:
875 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
876 (node.name, node.name, arg_tuple))
877 for arg in node.defaults:
878 self.visit(arg, macro_frame)
880 self.write('), %s, %s, %s)' % (
881 macro_frame.accesses_kwargs and '1' or '0',
882 macro_frame.accesses_varargs and '1' or '0',
883 macro_frame.accesses_caller and '1' or '0'
886 def visit_CallBlock(self, node, frame):
887 call_frame = self.function_scoping(node, frame, node.iter_child_nodes
889 args = call_frame.arguments
890 self.writeline('def call(%s):' % ', '.join(args), node)
891 call_frame.buffer = buf = self.temporary_identifier()
893 self.pull_locals(call_frame)
894 self.writeline('%s = []' % buf)
895 self.blockvisit(node.body, call_frame)
896 if self.environment.autoescape:
897 self.writeline("return Markup(concat(%s))" % buf)
899 self.writeline('return concat(%s)' % buf)
901 arg_tuple = ', '.join(repr(x.name) for x in node.args)
902 if len(node.args) == 1:
904 self.writeline('caller = Macro(environment, call, None, (%s), (' %
906 for arg in node.defaults:
907 self.visit(arg, call_frame)
909 self.write('), %s, %s, 0)' % (
910 call_frame.accesses_kwargs and '1' or '0',
911 call_frame.accesses_varargs and '1' or '0'
913 if frame.buffer is None:
914 self.writeline('yield ', node)
916 self.writeline('%s.append(' % frame.buffer, node)
917 self.visit_Call(node.call, call_frame,
918 extra_kwargs={'caller': 'caller'})
919 if frame.buffer is not None:
922 def visit_FilterBlock(self, node, frame):
923 filter_frame = frame.inner()
924 filter_frame.inspect(node.iter_child_nodes())
926 aliases = self.collect_shadowed(filter_frame)
927 self.pull_locals(filter_frame)
928 filter_frame.buffer = buf = self.temporary_identifier()
930 self.writeline('%s = []' % buf, node)
931 for child in node.body:
932 self.visit(child, filter_frame)
934 if frame.buffer is None:
935 self.writeline('yield ', node)
937 self.writeline('%s.append(' % frame.buffer, node)
938 self.visit_Filter(node.filter, filter_frame, 'concat(%s)' % buf)
939 if frame.buffer is not None:
942 def visit_ExprStmt(self, node, frame):
944 self.visit(node.node, frame)
946 def visit_Output(self, node, frame):
947 # if we have a known extends statement, we don't output anything
948 if self.has_known_extends and frame.toplevel:
953 # if we are in the toplevel scope and there was already an extends
954 # statement we have to add a check that disables our yield(s) here
955 # so that they don't appear in the output.
956 outdent_later = False
957 if frame.toplevel and self.extends_so_far != 0:
958 self.writeline('if parent_template is None:')
962 # try to evaluate as many chunks as possible into a static
963 # string at compile time.
965 for child in node.nodes:
967 const = unicode(child.as_const())
971 if body and isinstance(body[-1], list):
972 body[-1].append(const)
976 # if we have less than 3 nodes or less than 6 and a buffer we
978 if len(body) < 3 or (frame.buffer is not None and len(body) < 6):
979 if frame.buffer is not None:
980 self.writeline('%s.extend((' % frame.buffer)
982 if isinstance(item, list):
983 val = repr(concat(item))
984 if frame.buffer is None:
985 self.writeline('yield ' + val)
987 self.write(val + ', ')
989 if frame.buffer is None:
990 self.writeline('yield ')
992 if self.environment.autoescape:
993 self.write('escape(')
995 self.write('unicode(')
996 if self.environment.finalize is not None:
997 self.write('environment.finalize(')
999 self.visit(item, frame)
1000 self.write(')' * close)
1001 if frame.buffer is not None:
1003 if frame.buffer is not None:
1006 # otherwise we create a format string as this is faster in that case
1011 if isinstance(item, list):
1012 format.append(concat(item).replace('%', '%%'))
1015 arguments.append(item)
1016 if frame.buffer is None:
1017 self.writeline('yield ')
1019 self.writeline('%s.append(' % frame.buffer)
1020 self.write(repr(concat(format)) + ' % (')
1023 for argument in arguments:
1024 self.newline(argument)
1026 if self.environment.autoescape:
1027 self.write('escape(')
1029 if self.environment.finalize is not None:
1030 self.write('environment.finalize(')
1032 self.visit(argument, frame)
1033 self.write(')' * close + ',')
1036 if frame.buffer is not None:
1042 def visit_Assign(self, node, frame):
1044 # toplevel assignments however go into the local namespace and
1045 # the current template's context. We create a copy of the frame
1046 # here and add a set so that the Name visitor can add the assigned
1049 assignment_frame = frame.copy()
1050 assignment_frame.assigned_names = set()
1052 assignment_frame = frame
1053 self.visit(node.target, assignment_frame)
1055 self.visit(node.node, frame)
1057 # make sure toplevel assignments are added to the context.
1059 for name in assignment_frame.assigned_names:
1060 self.writeline('context.vars[%r] = l_%s' % (name, name))
1061 if not name.startswith('__'):
1062 self.writeline('context.exported_vars.add(%r)' % name)
1064 def visit_Name(self, node, frame):
1065 if node.ctx == 'store' and frame.toplevel:
1066 frame.assigned_names.add(node.name)
1067 self.write('l_' + node.name)
1069 def visit_MarkSafe(self, node, frame):
1070 self.write('Markup(')
1071 self.visit(node.expr, frame)
1074 def visit_Const(self, node, frame):
1076 if isinstance(val, float):
1077 # XXX: add checks for infinity and nan
1078 self.write(str(val))
1080 self.write(repr(val))
1082 def visit_Tuple(self, node, frame):
1085 for idx, item in enumerate(node.items):
1088 self.visit(item, frame)
1089 self.write(idx == 0 and ',)' or ')')
1091 def visit_List(self, node, frame):
1093 for idx, item in enumerate(node.items):
1096 self.visit(item, frame)
1099 def visit_Dict(self, node, frame):
1101 for idx, item in enumerate(node.items):
1104 self.visit(item.key, frame)
1106 self.visit(item.value, frame)
1109 def binop(operator):
1110 def visitor(self, node, frame):
1112 self.visit(node.left, frame)
1113 self.write(' %s ' % operator)
1114 self.visit(node.right, frame)
1119 def visitor(self, node, frame):
1120 self.write('(' + operator)
1121 self.visit(node.node, frame)
1125 visit_Add = binop('+')
1126 visit_Sub = binop('-')
1127 visit_Mul = binop('*')
1128 visit_Div = binop('/')
1129 visit_FloorDiv = binop('//')
1130 visit_Pow = binop('**')
1131 visit_Mod = binop('%')
1132 visit_And = binop('and')
1133 visit_Or = binop('or')
1134 visit_Pos = uaop('+')
1135 visit_Neg = uaop('-')
1136 visit_Not = uaop('not ')
1139 def visit_Concat(self, node, frame):
1140 self.write('%s((' % self.environment.autoescape and
1141 'markup_join' or 'unicode_join')
1142 for arg in node.nodes:
1143 self.visit(arg, frame)
1147 def visit_Compare(self, node, frame):
1148 self.visit(node.expr, frame)
1150 self.visit(op, frame)
1152 def visit_Operand(self, node, frame):
1153 self.write(' %s ' % operators[node.op])
1154 self.visit(node.expr, frame)
1156 def visit_Subscript(self, node, frame):
1157 if isinstance(node.arg, nodes.Slice):
1158 self.visit(node.node, frame)
1160 self.visit(node.arg, frame)
1164 const = node.arg.as_const()
1166 except nodes.Impossible:
1168 self.write('environment.subscribe(')
1169 self.visit(node.node, frame)
1172 self.write(repr(const))
1174 self.visit(node.arg, frame)
1177 def visit_Slice(self, node, frame):
1178 if node.start is not None:
1179 self.visit(node.start, frame)
1181 if node.stop is not None:
1182 self.visit(node.stop, frame)
1183 if node.step is not None:
1185 self.visit(node.step, frame)
1187 def visit_Filter(self, node, frame, initial=None):
1188 self.write('f_%s(' % node.name)
1189 func = self.environment.filters.get(node.name)
1191 raise TemplateAssertionError('no filter named %r' % node.name,
1192 node.lineno, self.filename)
1193 if getattr(func, 'contextfilter', False):
1194 self.write('context, ')
1195 elif getattr(func, 'environmentfilter', False):
1196 self.write('environment, ')
1197 if isinstance(node.node, nodes.Filter):
1198 self.visit_Filter(node.node, frame, initial)
1199 elif node.node is None:
1202 self.visit(node.node, frame)
1203 self.signature(node, frame)
1206 def visit_Test(self, node, frame):
1207 self.write('t_%s(' % node.name)
1208 if node.name not in self.environment.tests:
1209 raise TemplateAssertionError('no test named %r' % node.name,
1210 node.lineno, self.filename)
1211 self.visit(node.node, frame)
1212 self.signature(node, frame)
1215 def visit_CondExpr(self, node, frame):
1216 if not have_condexpr:
1218 self.visit(node.test, frame)
1219 self.write(') and (')
1220 self.visit(node.expr1, frame)
1221 self.write(',) or (')
1222 self.visit(node.expr2, frame)
1223 self.write(',))[0]')
1226 self.visit(node.expr1, frame)
1228 self.visit(node.test, frame)
1229 self.write(' else ')
1230 self.visit(node.expr2, frame)
1233 def visit_Call(self, node, frame, extra_kwargs=None):
1234 if self.environment.sandboxed:
1235 self.write('environment.call(')
1236 self.visit(node.node, frame)
1237 self.write(self.environment.sandboxed and ', ' or '(')
1238 self.signature(node, frame, False, extra_kwargs)
1241 def visit_Keyword(self, node, frame):
1242 self.write(node.key + '=')
1243 self.visit(node.value, frame)