blob: a1ffdecab65837cf9e8b3a0faed18edefae38f6c [file] [log] [blame]
Armin Ronachere791c2a2008-04-07 18:39:54 +02001# -*- coding: utf-8 -*-
2"""
3 jinja2.compiler
4 ~~~~~~~~~~~~~~~
5
6 Compiles nodes into python code.
7
8 :copyright: Copyright 2008 by Armin Ronacher.
9 :license: GNU GPL.
10"""
Armin Ronacher32a910f2008-04-26 23:21:03 +020011from time import time
Armin Ronacher8efc5222008-04-08 14:47:40 +020012from copy import copy
Armin Ronachere791c2a2008-04-07 18:39:54 +020013from random import randrange
Armin Ronacher2feed1d2008-04-26 16:26:52 +020014from keyword import iskeyword
Armin Ronachere791c2a2008-04-07 18:39:54 +020015from cStringIO import StringIO
Armin Ronacher2feed1d2008-04-26 16:26:52 +020016from itertools import chain
Armin Ronachere791c2a2008-04-07 18:39:54 +020017from jinja2 import nodes
18from jinja2.visitor import NodeVisitor, NodeTransformer
19from jinja2.exceptions import TemplateAssertionError
Armin Ronacher32a910f2008-04-26 23:21:03 +020020from jinja2.runtime import concat
Armin Ronacher5236d8c2008-04-17 11:23:16 +020021from jinja2.utils import Markup
Armin Ronachere791c2a2008-04-07 18:39:54 +020022
23
24operators = {
25 'eq': '==',
26 'ne': '!=',
27 'gt': '>',
28 'gteq': '>=',
29 'lt': '<',
30 'lteq': '<=',
31 'in': 'in',
32 'notin': 'not in'
33}
34
35
Armin Ronacher3d8b7842008-04-13 13:16:50 +020036try:
37 exec '(0 if 0 else 0)'
38except SyntaxError:
39 have_condexpr = False
40else:
41 have_condexpr = True
42
43
Armin Ronacher8e8d0712008-04-16 23:10:49 +020044def generate(node, environment, name, filename, stream=None):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020045 """Generate the python source for a node tree."""
Armin Ronacher8e8d0712008-04-16 23:10:49 +020046 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020047 generator.visit(node)
48 if stream is None:
49 return generator.stream.getvalue()
50
51
Armin Ronacher4dfc9752008-04-09 15:03:29 +020052def has_safe_repr(value):
53 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020054 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020055 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020056 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher32a910f2008-04-26 23:21:03 +020057 xrange, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020058 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020059 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020060 for item in value:
61 if not has_safe_repr(item):
62 return False
63 return True
64 elif isinstance(value, dict):
65 for key, value in value.iteritems():
66 if not has_safe_repr(key):
67 return False
68 if not has_safe_repr(value):
69 return False
70 return True
71 return False
72
73
Armin Ronachere791c2a2008-04-07 18:39:54 +020074class Identifiers(object):
75 """Tracks the status of identifiers in frames."""
76
77 def __init__(self):
78 # variables that are known to be declared (probably from outer
79 # frames or because they are special for the frame)
80 self.declared = set()
81
Armin Ronacher10f3ba22008-04-18 11:30:37 +020082 # undeclared variables from outer scopes
83 self.outer_undeclared = set()
84
Armin Ronachere791c2a2008-04-07 18:39:54 +020085 # names that are accessed without being explicitly declared by
86 # this one or any of the outer scopes. Names can appear both in
87 # declared and undeclared.
88 self.undeclared = set()
89
90 # names that are declared locally
91 self.declared_locally = set()
92
93 # names that are declared by parameters
94 self.declared_parameter = set()
95
Armin Ronacherf059ec12008-04-11 22:21:00 +020096 # filters/tests that are referenced
Armin Ronacherd4c64f72008-04-11 17:15:29 +020097 self.filters = set()
Armin Ronacherf059ec12008-04-11 22:21:00 +020098 self.tests = set()
Christoph Hack65642a52008-04-08 14:46:56 +020099
Armin Ronachere791c2a2008-04-07 18:39:54 +0200100 def add_special(self, name):
101 """Register a special name like `loop`."""
102 self.undeclared.discard(name)
103 self.declared.add(name)
104
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200105 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200106 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200107 if name in self.declared_locally or name in self.declared_parameter:
108 return True
109 if local_only:
110 return False
111 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200112
113 def find_shadowed(self):
114 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200115 return (self.declared | self.outer_undeclared) & \
116 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200117
118
119class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200120 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200121
122 def __init__(self, parent=None):
123 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200124
Armin Ronacher75cfb862008-04-11 13:47:22 +0200125 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200126 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200127
Armin Ronacher75cfb862008-04-11 13:47:22 +0200128 # the root frame is basically just the outermost frame, so no if
129 # conditions. This information is used to optimize inheritance
130 # situations.
131 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200132
133 # inside some tags we are using a buffer rather than yield statements.
134 # this for example affects {% filter %} or {% macro %}. If a frame
135 # is buffered this variable points to the name of the list used as
136 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200137 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200138
139 # if a frame has name_overrides, all read access to a name in this
140 # dict is redirected to a string expression.
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200141 self.name_overrides = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200142
143 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200144 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200145
146 # the parent of this frame
147 self.parent = parent
148
Armin Ronachere791c2a2008-04-07 18:39:54 +0200149 if parent is not None:
150 self.identifiers.declared.update(
151 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200152 parent.identifiers.declared_locally |
153 parent.identifiers.declared_parameter
154 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200155 self.identifiers.outer_undeclared.update(
156 parent.identifiers.undeclared -
157 self.identifiers.declared
158 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200159 self.buffer = parent.buffer
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200160 self.name_overrides = parent.name_overrides.copy()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200161
Armin Ronacher8efc5222008-04-08 14:47:40 +0200162 def copy(self):
163 """Create a copy of the current one."""
164 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200165 rv.identifiers = copy(self.identifiers)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200166 rv.name_overrides = self.name_overrides.copy()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200167 return rv
168
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200169 def inspect(self, nodes, with_depenencies=False, hard_scope=False):
170 """Walk the node and check for identifiers. If the scope is hard (eg:
171 enforce on a python level) overrides from outer scopes are tracked
172 differently.
173
174 Per default filters and tests (dependencies) are not tracked. That's
175 the case because filters and tests are absolutely immutable and so we
176 can savely use them in closures too. The `Template` and `Block`
177 visitor visits the frame with dependencies to collect them.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200178 """
179 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200180 for node in nodes:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200181 visitor.visit(node, True, with_depenencies)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200182
183 def inner(self):
184 """Return an inner frame."""
185 return Frame(self)
186
Armin Ronacher75cfb862008-04-11 13:47:22 +0200187 def soft(self):
188 """Return a soft frame. A soft frame may not be modified as
189 standalone thing as it shares the resources with the frame it
190 was created of, but it's not a rootlevel frame any longer.
191 """
192 rv = copy(self)
193 rv.rootlevel = False
194 return rv
195
Armin Ronachere791c2a2008-04-07 18:39:54 +0200196
197class FrameIdentifierVisitor(NodeVisitor):
198 """A visitor for `Frame.inspect`."""
199
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200200 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200201 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200202 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200203
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200204 def visit_Name(self, node, visit_ident, visit_deps):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200205 """All assignments to names go through this function."""
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200206 if visit_ident:
207 if node.ctx in ('store', 'param'):
208 self.identifiers.declared_locally.add(node.name)
209 elif node.ctx == 'load' and not \
210 self.identifiers.is_declared(node.name, self.hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200211 self.identifiers.undeclared.add(node.name)
212
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200213 def visit_Filter(self, node, visit_ident, visit_deps):
214 if visit_deps:
215 self.generic_visit(node, visit_ident, True)
216 self.identifiers.filters.add(node.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200217
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200218 def visit_Test(self, node, visit_ident, visit_deps):
219 if visit_deps:
220 self.generic_visit(node, visit_ident, True)
221 self.identifiers.tests.add(node.name)
Christoph Hack65642a52008-04-08 14:46:56 +0200222
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200223 def visit_Macro(self, node, visit_ident, visit_deps):
224 if visit_ident:
225 self.identifiers.declared_locally.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200226
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200227 def visit_Import(self, node, visit_ident, visit_deps):
228 if visit_ident:
229 self.generic_visit(node, True, visit_deps)
230 self.identifiers.declared_locally.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200231
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200232 def visit_FromImport(self, node, visit_ident, visit_deps):
233 if visit_ident:
234 self.generic_visit(node, True, visit_deps)
235 for name in node.names:
236 if isinstance(name, tuple):
237 self.identifiers.declared_locally.add(name[1])
238 else:
239 self.identifiers.declared_locally.add(name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200240
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200241 def visit_Assign(self, node, visit_ident, visit_deps):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200242 """Visit assignments in the correct order."""
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200243 self.visit(node.node, visit_ident, visit_deps)
244 self.visit(node.target, visit_ident, visit_deps)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200245
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200246 def visit_For(self, node, visit_ident, visit_deps):
247 """Visiting stops at for blocks. However the block sequence
248 is visited as part of the outer scope.
249 """
250 if visit_ident:
251 self.visit(node.iter, True, visit_deps)
252 if visit_deps:
253 for child in node.iter_child_nodes(exclude=('iter',)):
254 self.visit(child, False, True)
255
256 def ident_stop(self, node, visit_ident, visit_deps):
257 if visit_deps:
258 self.generic_visit(node, False, True)
259 visit_CallBlock = visit_FilterBlock = ident_stop
260 visit_Block = lambda s, n, a, b: None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200261
262
Armin Ronacher75cfb862008-04-11 13:47:22 +0200263class CompilerExit(Exception):
264 """Raised if the compiler encountered a situation where it just
265 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200266 raises such an exception is not further processed.
267 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200268
269
Armin Ronachere791c2a2008-04-07 18:39:54 +0200270class CodeGenerator(NodeVisitor):
271
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200272 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200273 if stream is None:
274 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200275 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200276 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200277 self.filename = filename
278 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200279
280 # a registry for all blocks. Because blocks are moved out
281 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200282 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200283
284 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200285 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200286
287 # some templates have a rootlevel extends. In this case we
288 # can safely assume that we're a child template and do some
289 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200290 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200291
Armin Ronacherba3757b2008-04-16 19:43:16 +0200292 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200293 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200294
295 # the debug information
296 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200297 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200298
Armin Ronacherfed44b52008-04-13 19:42:53 +0200299 # the number of new lines before the next write()
300 self._new_lines = 0
301
302 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200303 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200304
305 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200306 self._first_write = True
307
Armin Ronacherfed44b52008-04-13 19:42:53 +0200308 # used by the `temporary_identifier` method to get new
309 # unique, temporary identifier
310 self._last_identifier = 0
311
312 # the current indentation
313 self._indentation = 0
314
Armin Ronachere791c2a2008-04-07 18:39:54 +0200315 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200316 """Get a new unique identifier."""
317 self._last_identifier += 1
318 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200319
320 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200321 """Indent by one."""
322 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200323
Armin Ronacher8efc5222008-04-08 14:47:40 +0200324 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200325 """Outdent by step."""
326 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200327
Armin Ronacher625215e2008-04-13 16:31:08 +0200328 def blockvisit(self, nodes, frame, indent=True, force_generator=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200329 """Visit a list of nodes as block in a frame. Per default the
330 code is indented, but this can be disabled by setting the indent
331 parameter to False. If the current frame is no buffer a dummy
332 ``if 0: yield None`` is written automatically unless the
333 force_generator parameter is set to False.
334 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200335 if indent:
336 self.indent()
337 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200338 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200339 try:
340 for node in nodes:
341 self.visit(node, frame)
342 except CompilerExit:
343 pass
Armin Ronacher625215e2008-04-13 16:31:08 +0200344 if indent:
345 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200346
347 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200348 """Write a string into the output stream."""
349 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200350 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200351 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200352 self.code_lineno += self._new_lines
353 if self._write_debug_info is not None:
354 self.debug_info.append((self._write_debug_info,
355 self.code_lineno))
356 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200357 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200358 self.stream.write(' ' * self._indentation)
359 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200360 self.stream.write(x)
361
362 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200363 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200364 self.newline(node, extra)
365 self.write(x)
366
367 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200368 """Add one or more newlines before the next write."""
369 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200370 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200371 self._write_debug_info = node.lineno
372 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200373
Armin Ronacher71082072008-04-12 14:19:36 +0200374 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200375 """Writes a function call to the stream for the current node.
376 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200377 disabled by setting have_comma to False. The extra keyword
378 arguments may not include python keywords otherwise a syntax
379 error could occour. The extra keyword arguments should be given
380 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200381 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200382 have_comma = have_comma and [True] or []
383 def touch_comma():
384 if have_comma:
385 self.write(', ')
386 else:
387 have_comma.append(True)
388
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200389 # if any of the given keyword arguments is a python keyword
390 # we have to make sure that no invalid call is created.
391 kwarg_workaround = False
392 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
393 if iskeyword(kwarg):
394 kwarg_workaround = True
395 break
396
Armin Ronacher8efc5222008-04-08 14:47:40 +0200397 for arg in node.args:
398 touch_comma()
399 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200400
401 if not kwarg_workaround:
402 for kwarg in node.kwargs:
403 touch_comma()
404 self.visit(kwarg, frame)
405 if extra_kwargs is not None:
406 for key, value in extra_kwargs.iteritems():
407 touch_comma()
408 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200409 if node.dyn_args:
410 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200411 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200412 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200413
414 if kwarg_workaround:
415 touch_comma()
416 if node.dyn_kwargs is not None:
417 self.write('**dict({')
418 else:
419 self.write('**{')
420 for kwarg in node.kwargs:
421 self.write('%r: ' % kwarg.key)
422 self.visit(kwarg.value, frame)
423 self.write(', ')
424 if extra_kwargs is not None:
425 for key, value in extra_kwargs.iteritems():
426 touch_comma()
427 self.write('%r: %s, ' % (key, value))
428 if node.dyn_kwargs is not None:
429 self.write('}, **')
430 self.visit(node.dyn_kwargs, frame)
431 self.write(')')
432 else:
433 self.write('}')
434
435 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200436 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200437 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200438 self.visit(node.dyn_kwargs, frame)
439
Armin Ronacher625215e2008-04-13 16:31:08 +0200440 def pull_locals(self, frame, indent=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200441 """Pull all the references identifiers into the local scope.
442 This affects regular names, filters and tests. If indent is
443 set to False, no automatic indentation will take place.
444 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200445 if indent:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200446 self.indent()
447 for name in frame.identifiers.undeclared:
448 self.writeline('l_%s = context[%r]' % (name, name))
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200449 for name in frame.identifiers.filters:
450 self.writeline('f_%s = environment.filters[%r]' % (name, name))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200451 for name in frame.identifiers.tests:
452 self.writeline('t_%s = environment.tests[%r]' % (name, name))
Armin Ronacher625215e2008-04-13 16:31:08 +0200453 if indent:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200454 self.outdent()
455
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200456 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200457 """This function returns all the shadowed variables in a dict
458 in the form name: alias and will write the required assignments
459 into the current scope. No indentation takes place.
460 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200461 # make sure we "backup" overridden, local identifiers
462 # TODO: we should probably optimize this and check if the
463 # identifier is in use afterwards.
464 aliases = {}
465 for name in frame.identifiers.find_shadowed():
466 aliases[name] = ident = self.temporary_identifier()
467 self.writeline('%s = l_%s' % (ident, name))
468 return aliases
469
Armin Ronacher71082072008-04-12 14:19:36 +0200470 def function_scoping(self, node, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200471 """In Jinja a few statements require the help of anonymous
472 functions. Those are currently macros and call blocks and in
473 the future also recursive loops. As there is currently
474 technical limitation that doesn't allow reading and writing a
475 variable in a scope where the initial value is coming from an
476 outer scope, this function tries to fall back with a common
477 error message. Additionally the frame passed is modified so
478 that the argumetns are collected and callers are looked up.
479
480 This will return the modified frame.
481 """
Armin Ronacher71082072008-04-12 14:19:36 +0200482 func_frame = frame.inner()
483 func_frame.inspect(node.iter_child_nodes(), hard_scope=True)
484
485 # variables that are undeclared (accessed before declaration) and
486 # declared locally *and* part of an outside scope raise a template
487 # assertion error. Reason: we can't generate reasonable code from
488 # it without aliasing all the variables. XXX: alias them ^^
489 overriden_closure_vars = (
490 func_frame.identifiers.undeclared &
491 func_frame.identifiers.declared &
492 (func_frame.identifiers.declared_locally |
493 func_frame.identifiers.declared_parameter)
494 )
495 if overriden_closure_vars:
496 vars = ', '.join(sorted(overriden_closure_vars))
497 raise TemplateAssertionError('It\'s not possible to set and '
498 'access variables derived from '
499 'an outer scope! (affects: %s' %
Armin Ronacher68f77672008-04-17 11:50:39 +0200500 vars, node.lineno, self.name)
Armin Ronacher71082072008-04-12 14:19:36 +0200501
502 # remove variables from a closure from the frame's undeclared
503 # identifiers.
504 func_frame.identifiers.undeclared -= (
505 func_frame.identifiers.undeclared &
506 func_frame.identifiers.declared
507 )
508
Armin Ronacher963f97d2008-04-25 11:44:59 +0200509 func_frame.accesses_kwargs = False
510 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200511 func_frame.accesses_caller = False
512 func_frame.arguments = args = ['l_' + x.name for x in node.args]
513
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200514 if 'caller' in func_frame.identifiers.undeclared:
515 func_frame.accesses_caller = True
516 func_frame.identifiers.add_special('caller')
517 args.append('l_caller')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200518 if 'kwargs' in func_frame.identifiers.undeclared:
519 func_frame.accesses_kwargs = True
520 func_frame.identifiers.add_special('kwargs')
521 args.append('l_kwargs')
522 if 'varargs' in func_frame.identifiers.undeclared:
523 func_frame.accesses_varargs = True
524 func_frame.identifiers.add_special('varargs')
525 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200526 return func_frame
527
Armin Ronachere791c2a2008-04-07 18:39:54 +0200528 # -- Visitors
529
530 def visit_Template(self, node, frame=None):
531 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200532 from jinja2.runtime import __all__ as exported
533 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200534 self.writeline('name = %r' % self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200535
Armin Ronacher75cfb862008-04-11 13:47:22 +0200536 # do we have an extends tag at all? If not, we can save some
537 # overhead by just not processing any inheritance code.
538 have_extends = node.find(nodes.Extends) is not None
539
Armin Ronacher8edbe492008-04-10 20:43:43 +0200540 # find all blocks
541 for block in node.find_all(nodes.Block):
542 if block.name in self.blocks:
543 raise TemplateAssertionError('block %r defined twice' %
544 block.name, block.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200545 self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200546 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200547
Armin Ronacher8efc5222008-04-08 14:47:40 +0200548 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200549 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200550 if have_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200551 self.indent()
552 self.writeline('parent_template = None')
553 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200554
555 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200556 frame = Frame()
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200557 frame.inspect(node.body, with_depenencies=True)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200558 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200559 self.indent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200560 self.pull_locals(frame, indent=False)
Armin Ronacher625215e2008-04-13 16:31:08 +0200561 self.blockvisit(node.body, frame, indent=False)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200562 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200563
Armin Ronacher8efc5222008-04-08 14:47:40 +0200564 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200565 if have_extends:
566 if not self.has_known_extends:
567 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200568 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200569 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200570 self.writeline('for event in parent_template.'
571 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200572 self.indent()
573 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200574 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200575
576 # at this point we now have the blocks collected and can visit them too.
577 for name, block in self.blocks.iteritems():
578 block_frame = Frame()
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200579 block_frame.inspect(block.body, with_depenencies=True)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200580 block_frame.block = name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200581 block_frame.identifiers.add_special('super')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200582 block_frame.name_overrides['super'] = 'context.super(%r, ' \
583 'block_%s)' % (name, name)
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200584 self.writeline('def block_%s(context, environment=environment):'
585 % name, block, 1)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200586 self.pull_locals(block_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200587 self.blockvisit(block.body, block_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200588
Armin Ronacher75cfb862008-04-11 13:47:22 +0200589 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200590 for x in self.blocks),
591 extra=1)
592
593 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200594 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
595 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200596
Armin Ronachere791c2a2008-04-07 18:39:54 +0200597 def visit_Block(self, node, frame):
598 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200599 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200600 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200601 # if we know that we are a child template, there is no need to
602 # check if we are one
603 if self.has_known_extends:
604 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200605 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200606 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200607 self.indent()
608 level += 1
609 self.writeline('for event in context.blocks[%r][-1](context):' % node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200610 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200611 if frame.buffer is None:
612 self.writeline('yield event')
613 else:
614 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200615 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200616
617 def visit_Extends(self, node, frame):
618 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200619 if not frame.toplevel:
620 raise TemplateAssertionError('cannot use extend from a non '
621 'top-level scope', node.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200622 self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200623
Armin Ronacher7fb38972008-04-11 13:54:28 +0200624 # if the number of extends statements in general is zero so
625 # far, we don't have to add a check if something extended
626 # the template before this one.
627 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200628
Armin Ronacher7fb38972008-04-11 13:54:28 +0200629 # if we have a known extends we just add a template runtime
630 # error into the generated code. We could catch that at compile
631 # time too, but i welcome it not to confuse users by throwing the
632 # same error at different times just "because we can".
633 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200634 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200635 self.indent()
636 self.writeline('raise TemplateRuntimeError(%r)' %
637 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200638
Armin Ronacher7fb38972008-04-11 13:54:28 +0200639 # if we have a known extends already we don't need that code here
640 # as we know that the template execution will end here.
641 if self.has_known_extends:
642 raise CompilerExit()
643 self.outdent()
644
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200645 self.writeline('parent_template = environment.get_template(', node, 1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200646 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200647 self.write(', %r)' % self.name)
648 self.writeline('for name, parent_block in parent_template.'
649 'blocks.iteritems():')
650 self.indent()
651 self.writeline('context.blocks.setdefault(name, []).'
652 'insert(0, parent_block)')
653 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200654
655 # if this extends statement was in the root level we can take
656 # advantage of that information and simplify the generated code
657 # in the top level from this point onwards
658 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200659
Armin Ronacher7fb38972008-04-11 13:54:28 +0200660 # and now we have one more
661 self.extends_so_far += 1
662
Armin Ronacherf059ec12008-04-11 22:21:00 +0200663 def visit_Include(self, node, frame):
664 """Handles includes."""
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200665 self.writeline('included_template = environment.get_template(', node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200666 self.visit(node.template, frame)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200667 self.write(', %r)' % self.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200668 self.writeline('for event in included_template.root_render_func('
669 'included_template.new_context(context.get_root())):')
Armin Ronacherf059ec12008-04-11 22:21:00 +0200670 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200671 if frame.buffer is None:
672 self.writeline('yield event')
673 else:
674 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200675 self.outdent()
676
Armin Ronacher0611e492008-04-25 23:44:14 +0200677 def visit_Import(self, node, frame):
678 """Visit regular imports."""
679 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200680 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200681 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200682 self.write('environment.get_template(')
683 self.visit(node.template, frame)
684 self.write(', %r).include(context)' % self.name)
Armin Ronacher53042292008-04-26 18:30:19 +0200685 if frame.toplevel:
686 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200687
688 def visit_FromImport(self, node, frame):
689 """Visit named imports."""
690 self.newline(node)
691 self.write('included_template = environment.get_template(')
692 self.visit(node.template, frame)
693 self.write(', %r).include(context)' % self.name)
694 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200695 if isinstance(name, tuple):
696 name, alias = name
697 else:
698 alias = name
Armin Ronacher0611e492008-04-25 23:44:14 +0200699 self.writeline('l_%s = getattr(included_template, '
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200700 '%r, missing)' % (alias, name))
701 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200702 self.indent()
703 self.writeline('l_%s = environment.undefined(%r %% '
704 'included_template.name)' %
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200705 (alias, 'the template %r does not export '
Armin Ronacher0611e492008-04-25 23:44:14 +0200706 'the requested name ' + repr(name)))
707 self.outdent()
708 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200709 self.writeline('context.vars[%r] = l_%s' % (alias, alias))
710 self.writeline('context.exported_vars.discard(%r)' % alias)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200711
Armin Ronachere791c2a2008-04-07 18:39:54 +0200712 def visit_For(self, node, frame):
713 loop_frame = frame.inner()
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200714 loop_frame.inspect(node.iter_child_nodes(exclude=('iter',)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200715 extended_loop = bool(node.else_) or \
716 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200717 if extended_loop:
718 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200719
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200720 aliases = self.collect_shadowed(loop_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200721 self.pull_locals(loop_frame, indent=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200722 if node.else_:
723 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200724
725 self.newline(node)
726 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200727 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200728 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200729
730 # the expression pointing to the parent loop. We make the
731 # undefined a bit more debug friendly at the same time.
732 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200733 or "environment.undefined(%r)" % "'loop' is undefined. " \
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200734 'the filter section of a loop as well as the ' \
735 'else block doesn\'t have access to the special ' \
736 "'loop' variable of the current loop. Because " \
737 'there is no parent loop it\'s undefined.'
738
739 # if we have an extened loop and a node test, we filter in the
740 # "outer frame".
741 if extended_loop and node.test is not None:
742 self.write('(')
743 self.visit(node.target, loop_frame)
744 self.write(' for ')
745 self.visit(node.target, loop_frame)
746 self.write(' in ')
747 self.visit(node.iter, loop_frame)
748 self.write(' if (')
749 test_frame = loop_frame.copy()
750 test_frame.name_overrides['loop'] = parent_loop
751 self.visit(node.test, test_frame)
752 self.write('))')
753
754 else:
755 self.visit(node.iter, loop_frame)
756
Armin Ronachere791c2a2008-04-07 18:39:54 +0200757 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200758
759 # tests in not extended loops become a continue
760 if not extended_loop and node.test is not None:
761 self.indent()
762 self.writeline('if ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200763 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200764 self.write(':')
765 self.indent()
766 self.writeline('continue')
767 self.outdent(2)
768
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200769 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200770
771 if node.else_:
772 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200773 self.indent()
774 self.writeline('l_loop = ' + parent_loop)
775 self.outdent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200776 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200777
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200778 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200779 for name, alias in aliases.iteritems():
Armin Ronacher8efc5222008-04-08 14:47:40 +0200780 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200781
782 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200783 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200784 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200785 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200786 self.write(':')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200787 self.blockvisit(node.body, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200788 if node.else_:
789 self.writeline('else:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200790 self.blockvisit(node.else_, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200791
Armin Ronacher8efc5222008-04-08 14:47:40 +0200792 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200793 macro_frame = self.function_scoping(node, frame)
794 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200795 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200796 macro_frame.buffer = buf = self.temporary_identifier()
797 self.indent()
798 self.pull_locals(macro_frame, indent=False)
799 self.writeline('%s = []' % buf)
800 self.blockvisit(node.body, macro_frame, indent=False)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200801 self.writeline("return Markup(concat(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200802 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200803 self.newline()
804 if frame.toplevel:
Armin Ronacher32a910f2008-04-26 23:21:03 +0200805 self.write('context.exported_vars.add(%r)' % node.name)
806 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200807 arg_tuple = ', '.join(repr(x.name) for x in node.args)
808 if len(node.args) == 1:
809 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200810 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
811 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200812 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200813 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200814 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200815 self.write('), %s, %s, %s)' % (
816 macro_frame.accesses_kwargs and '1' or '0',
817 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200818 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200819 ))
820
821 def visit_CallBlock(self, node, frame):
822 call_frame = self.function_scoping(node, frame)
823 args = call_frame.arguments
824 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200825 call_frame.buffer = buf = self.temporary_identifier()
826 self.indent()
827 self.pull_locals(call_frame, indent=False)
828 self.writeline('%s = []' % buf)
829 self.blockvisit(node.body, call_frame, indent=False)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200830 self.writeline("return Markup(concat(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200831 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200832 arg_tuple = ', '.join(repr(x.name) for x in node.args)
833 if len(node.args) == 1:
834 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200835 self.writeline('caller = Macro(environment, call, None, (%s), (' %
836 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200837 for arg in node.defaults:
838 self.visit(arg)
839 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200840 self.write('), %s, %s, 0)' % (
841 call_frame.accesses_kwargs and '1' or '0',
842 call_frame.accesses_varargs and '1' or '0'
843 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200844 if frame.buffer is None:
845 self.writeline('yield ', node)
846 else:
847 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200848 self.visit_Call(node.call, call_frame,
849 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200850 if frame.buffer is not None:
851 self.write(')')
852
853 def visit_FilterBlock(self, node, frame):
854 filter_frame = frame.inner()
855 filter_frame.inspect(node.iter_child_nodes())
856
857 aliases = self.collect_shadowed(filter_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200858 self.pull_locals(filter_frame, indent=False)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200859 filter_frame.buffer = buf = self.temporary_identifier()
860
861 self.writeline('%s = []' % buf, node)
862 for child in node.body:
863 self.visit(child, filter_frame)
864
865 if frame.buffer is None:
866 self.writeline('yield ', node)
867 else:
868 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200869 self.visit_Filter(node.filter, filter_frame, 'concat(%s)' % buf)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200870 if frame.buffer is not None:
871 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200872
Armin Ronachere791c2a2008-04-07 18:39:54 +0200873 def visit_ExprStmt(self, node, frame):
874 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +0200875 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200876
877 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200878 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +0200879 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200880 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200881
Armin Ronacher75cfb862008-04-11 13:47:22 +0200882 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200883 if self.environment.finalize is unicode:
884 finalizer = 'unicode'
Armin Ronacherf059ec12008-04-11 22:21:00 +0200885 have_finalizer = False
Armin Ronacher8edbe492008-04-10 20:43:43 +0200886 else:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200887 finalizer = 'environment.finalize'
888 have_finalizer = True
Armin Ronacher8edbe492008-04-10 20:43:43 +0200889
Armin Ronacher7fb38972008-04-11 13:54:28 +0200890 # if we are in the toplevel scope and there was already an extends
891 # statement we have to add a check that disables our yield(s) here
892 # so that they don't appear in the output.
893 outdent_later = False
894 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200895 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200896 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200897 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +0200898
Armin Ronachere791c2a2008-04-07 18:39:54 +0200899 # try to evaluate as many chunks as possible into a static
900 # string at compile time.
901 body = []
902 for child in node.nodes:
903 try:
904 const = unicode(child.as_const())
905 except:
906 body.append(child)
907 continue
908 if body and isinstance(body[-1], list):
909 body[-1].append(const)
910 else:
911 body.append([const])
912
Armin Ronacher32a910f2008-04-26 23:21:03 +0200913 # if we have less than 3 nodes or less than 6 and a buffer we
914 # yield or extend
915 if len(body) < 3 or (frame.buffer is not None and len(body) < 6):
916 if frame.buffer is not None:
917 self.writeline('%s.extend((' % frame.buffer)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200918 for item in body:
919 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +0200920 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200921 if frame.buffer is None:
922 self.writeline('yield ' + val)
923 else:
Armin Ronacher32a910f2008-04-26 23:21:03 +0200924 self.write(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200925 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200926 if frame.buffer is None:
Armin Ronacher32a910f2008-04-26 23:21:03 +0200927 self.writeline('yield ')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200928 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200929 self.visit(item, frame)
Armin Ronacher32a910f2008-04-26 23:21:03 +0200930 self.write(')')
931 if frame.buffer is not None:
932 self.write(', ')
933 if frame.buffer is not None:
934 self.write('))')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200935
936 # otherwise we create a format string as this is faster in that case
937 else:
938 format = []
939 arguments = []
940 for item in body:
941 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +0200942 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200943 else:
944 format.append('%s')
945 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200946 if frame.buffer is None:
947 self.writeline('yield ')
948 else:
949 self.writeline('%s.append(' % frame.buffer)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200950 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200951 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200952 self.indent()
953 for argument in arguments:
954 self.newline(argument)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200955 if have_finalizer:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200956 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200957 self.visit(argument, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200958 if have_finalizer:
Armin Ronacher8edbe492008-04-10 20:43:43 +0200959 self.write(')')
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200960 self.write(',')
961 self.outdent()
962 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200963 if frame.buffer is not None:
964 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200965
Armin Ronacher7fb38972008-04-11 13:54:28 +0200966 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200967 self.outdent()
968
Armin Ronacher8efc5222008-04-08 14:47:40 +0200969 def visit_Assign(self, node, frame):
970 self.newline(node)
971 # toplevel assignments however go into the local namespace and
972 # the current template's context. We create a copy of the frame
973 # here and add a set so that the Name visitor can add the assigned
974 # names here.
975 if frame.toplevel:
976 assignment_frame = frame.copy()
977 assignment_frame.assigned_names = set()
978 else:
979 assignment_frame = frame
980 self.visit(node.target, assignment_frame)
981 self.write(' = ')
982 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200983
984 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200985 if frame.toplevel:
986 for name in assignment_frame.assigned_names:
Armin Ronacher32a910f2008-04-26 23:21:03 +0200987 self.writeline('context.vars[%r] = l_%s' % (name, name))
988 self.writeline('context.exported_vars.add(%r)' % name)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200989
Armin Ronachere791c2a2008-04-07 18:39:54 +0200990 def visit_Name(self, node, frame):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200991 if node.ctx == 'store':
992 if frame.toplevel:
993 frame.assigned_names.add(node.name)
994 frame.name_overrides.pop(node.name, None)
995 elif node.ctx == 'load':
996 if node.name in frame.name_overrides:
997 self.write(frame.name_overrides[node.name])
998 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200999 self.write('l_' + node.name)
1000
1001 def visit_Const(self, node, frame):
1002 val = node.value
1003 if isinstance(val, float):
1004 # XXX: add checks for infinity and nan
1005 self.write(str(val))
1006 else:
1007 self.write(repr(val))
1008
Armin Ronacher8efc5222008-04-08 14:47:40 +02001009 def visit_Tuple(self, node, frame):
1010 self.write('(')
1011 idx = -1
1012 for idx, item in enumerate(node.items):
1013 if idx:
1014 self.write(', ')
1015 self.visit(item, frame)
1016 self.write(idx == 0 and ',)' or ')')
1017
Armin Ronacher8edbe492008-04-10 20:43:43 +02001018 def visit_List(self, node, frame):
1019 self.write('[')
1020 for idx, item in enumerate(node.items):
1021 if idx:
1022 self.write(', ')
1023 self.visit(item, frame)
1024 self.write(']')
1025
1026 def visit_Dict(self, node, frame):
1027 self.write('{')
1028 for idx, item in enumerate(node.items):
1029 if idx:
1030 self.write(', ')
1031 self.visit(item.key, frame)
1032 self.write(': ')
1033 self.visit(item.value, frame)
1034 self.write('}')
1035
Armin Ronachere791c2a2008-04-07 18:39:54 +02001036 def binop(operator):
1037 def visitor(self, node, frame):
1038 self.write('(')
1039 self.visit(node.left, frame)
1040 self.write(' %s ' % operator)
1041 self.visit(node.right, frame)
1042 self.write(')')
1043 return visitor
1044
1045 def uaop(operator):
1046 def visitor(self, node, frame):
1047 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001048 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001049 self.write(')')
1050 return visitor
1051
1052 visit_Add = binop('+')
1053 visit_Sub = binop('-')
1054 visit_Mul = binop('*')
1055 visit_Div = binop('/')
1056 visit_FloorDiv = binop('//')
1057 visit_Pow = binop('**')
1058 visit_Mod = binop('%')
1059 visit_And = binop('and')
1060 visit_Or = binop('or')
1061 visit_Pos = uaop('+')
1062 visit_Neg = uaop('-')
1063 visit_Not = uaop('not ')
1064 del binop, uaop
1065
1066 def visit_Compare(self, node, frame):
1067 self.visit(node.expr, frame)
1068 for op in node.ops:
1069 self.visit(op, frame)
1070
1071 def visit_Operand(self, node, frame):
1072 self.write(' %s ' % operators[node.op])
1073 self.visit(node.expr, frame)
1074
1075 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001076 if isinstance(node.arg, nodes.Slice):
1077 self.visit(node.node, frame)
1078 self.write('[')
1079 self.visit(node.arg, frame)
1080 self.write(']')
1081 return
1082 try:
1083 const = node.arg.as_const()
1084 have_const = True
1085 except nodes.Impossible:
1086 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001087 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001088 self.visit(node.node, frame)
1089 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001090 if have_const:
1091 self.write(repr(const))
1092 else:
1093 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001094 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001095
1096 def visit_Slice(self, node, frame):
1097 if node.start is not None:
1098 self.visit(node.start, frame)
1099 self.write(':')
1100 if node.stop is not None:
1101 self.visit(node.stop, frame)
1102 if node.step is not None:
1103 self.write(':')
1104 self.visit(node.step, frame)
1105
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001106 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001107 self.write('f_%s(' % node.name)
Christoph Hack80909862008-04-14 01:35:10 +02001108 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001109 if func is None:
1110 raise TemplateAssertionError('no filter named %r' % node.name,
1111 node.lineno, self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001112 if getattr(func, 'contextfilter', False):
1113 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001114 elif getattr(func, 'environmentfilter', False):
1115 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001116 if isinstance(node.node, nodes.Filter):
1117 self.visit_Filter(node.node, frame, initial)
1118 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001119 self.write(initial)
1120 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001121 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001122 self.signature(node, frame)
1123 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001124
1125 def visit_Test(self, node, frame):
Armin Ronacherf059ec12008-04-11 22:21:00 +02001126 self.write('t_%s(' % node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001127 if node.name not in self.environment.tests:
1128 raise TemplateAssertionError('no test named %r' % node.name,
1129 node.lineno, self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001130 self.visit(node.node, frame)
1131 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001132 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001133
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001134 def visit_CondExpr(self, node, frame):
1135 if not have_condexpr:
1136 self.write('((')
1137 self.visit(node.test, frame)
1138 self.write(') and (')
1139 self.visit(node.expr1, frame)
1140 self.write(',) or (')
1141 self.visit(node.expr2, frame)
1142 self.write(',))[0]')
1143 else:
1144 self.write('(')
1145 self.visit(node.expr1, frame)
1146 self.write(' if ')
1147 self.visit(node.test, frame)
1148 self.write(' else ')
1149 self.visit(node.expr2, frame)
1150 self.write(')')
1151
Armin Ronacher71082072008-04-12 14:19:36 +02001152 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001153 if self.environment.sandboxed:
1154 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001155 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001156 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001157 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001158 self.write(')')
1159
1160 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001161 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001162 self.visit(node.value, frame)