blob: 8541cba7640a65a6763ed2879d46854c3221cd19 [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 Ronacher8efc5222008-04-08 14:47:40 +020011from copy import copy
Armin Ronachere791c2a2008-04-07 18:39:54 +020012from random import randrange
Armin Ronacher2feed1d2008-04-26 16:26:52 +020013from keyword import iskeyword
Armin Ronachere791c2a2008-04-07 18:39:54 +020014from cStringIO import StringIO
Armin Ronacher2feed1d2008-04-26 16:26:52 +020015from itertools import chain
Armin Ronachere791c2a2008-04-07 18:39:54 +020016from jinja2 import nodes
17from jinja2.visitor import NodeVisitor, NodeTransformer
18from jinja2.exceptions import TemplateAssertionError
Armin Ronacherde6bf712008-04-26 01:44:14 +020019from jinja2.runtime import StaticLoopContext, concat
Armin Ronacher5236d8c2008-04-17 11:23:16 +020020from jinja2.utils import Markup
Armin Ronachere791c2a2008-04-07 18:39:54 +020021
22
23operators = {
24 'eq': '==',
25 'ne': '!=',
26 'gt': '>',
27 'gteq': '>=',
28 'lt': '<',
29 'lteq': '<=',
30 'in': 'in',
31 'notin': 'not in'
32}
33
34
Armin Ronacher3d8b7842008-04-13 13:16:50 +020035try:
36 exec '(0 if 0 else 0)'
37except SyntaxError:
38 have_condexpr = False
39else:
40 have_condexpr = True
41
42
Armin Ronacher8e8d0712008-04-16 23:10:49 +020043def generate(node, environment, name, filename, stream=None):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020044 """Generate the python source for a node tree."""
Armin Ronacher8e8d0712008-04-16 23:10:49 +020045 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020046 generator.visit(node)
47 if stream is None:
48 return generator.stream.getvalue()
49
50
Armin Ronacher4dfc9752008-04-09 15:03:29 +020051def has_safe_repr(value):
52 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020053 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020054 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020055 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher5236d8c2008-04-17 11:23:16 +020056 xrange, StaticLoopContext, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020057 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020058 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020059 for item in value:
60 if not has_safe_repr(item):
61 return False
62 return True
63 elif isinstance(value, dict):
64 for key, value in value.iteritems():
65 if not has_safe_repr(key):
66 return False
67 if not has_safe_repr(value):
68 return False
69 return True
70 return False
71
72
Armin Ronachere791c2a2008-04-07 18:39:54 +020073class Identifiers(object):
74 """Tracks the status of identifiers in frames."""
75
76 def __init__(self):
77 # variables that are known to be declared (probably from outer
78 # frames or because they are special for the frame)
79 self.declared = set()
80
Armin Ronacher10f3ba22008-04-18 11:30:37 +020081 # undeclared variables from outer scopes
82 self.outer_undeclared = set()
83
Armin Ronachere791c2a2008-04-07 18:39:54 +020084 # names that are accessed without being explicitly declared by
85 # this one or any of the outer scopes. Names can appear both in
86 # declared and undeclared.
87 self.undeclared = set()
88
89 # names that are declared locally
90 self.declared_locally = set()
91
92 # names that are declared by parameters
93 self.declared_parameter = set()
94
Armin Ronacherf059ec12008-04-11 22:21:00 +020095 # filters/tests that are referenced
Armin Ronacherd4c64f72008-04-11 17:15:29 +020096 self.filters = set()
Armin Ronacherf059ec12008-04-11 22:21:00 +020097 self.tests = set()
Christoph Hack65642a52008-04-08 14:46:56 +020098
Armin Ronachere791c2a2008-04-07 18:39:54 +020099 def add_special(self, name):
100 """Register a special name like `loop`."""
101 self.undeclared.discard(name)
102 self.declared.add(name)
103
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200104 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200105 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200106 if name in self.declared_locally or name in self.declared_parameter:
107 return True
108 if local_only:
109 return False
110 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200111
112 def find_shadowed(self):
113 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200114 return (self.declared | self.outer_undeclared) & \
115 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200116
117
118class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200119 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200120
121 def __init__(self, parent=None):
122 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200123
Armin Ronacher75cfb862008-04-11 13:47:22 +0200124 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200125 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200126
Armin Ronacher75cfb862008-04-11 13:47:22 +0200127 # the root frame is basically just the outermost frame, so no if
128 # conditions. This information is used to optimize inheritance
129 # situations.
130 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200131
132 # inside some tags we are using a buffer rather than yield statements.
133 # this for example affects {% filter %} or {% macro %}. If a frame
134 # is buffered this variable points to the name of the list used as
135 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200136 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200137
138 # if a frame has name_overrides, all read access to a name in this
139 # dict is redirected to a string expression.
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200140 self.name_overrides = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200141
142 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200143 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200144
145 # the parent of this frame
146 self.parent = parent
147
Armin Ronachere791c2a2008-04-07 18:39:54 +0200148 if parent is not None:
149 self.identifiers.declared.update(
150 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200151 parent.identifiers.declared_locally |
152 parent.identifiers.declared_parameter
153 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200154 self.identifiers.outer_undeclared.update(
155 parent.identifiers.undeclared -
156 self.identifiers.declared
157 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200158 self.buffer = parent.buffer
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200159 self.name_overrides = parent.name_overrides.copy()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200160
Armin Ronacher8efc5222008-04-08 14:47:40 +0200161 def copy(self):
162 """Create a copy of the current one."""
163 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200164 rv.identifiers = copy(self.identifiers)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200165 rv.name_overrides = self.name_overrides.copy()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200166 return rv
167
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200168 def inspect(self, nodes, with_depenencies=False, hard_scope=False):
169 """Walk the node and check for identifiers. If the scope is hard (eg:
170 enforce on a python level) overrides from outer scopes are tracked
171 differently.
172
173 Per default filters and tests (dependencies) are not tracked. That's
174 the case because filters and tests are absolutely immutable and so we
175 can savely use them in closures too. The `Template` and `Block`
176 visitor visits the frame with dependencies to collect them.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200177 """
178 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200179 for node in nodes:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200180 visitor.visit(node, True, with_depenencies)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200181
182 def inner(self):
183 """Return an inner frame."""
184 return Frame(self)
185
Armin Ronacher75cfb862008-04-11 13:47:22 +0200186 def soft(self):
187 """Return a soft frame. A soft frame may not be modified as
188 standalone thing as it shares the resources with the frame it
189 was created of, but it's not a rootlevel frame any longer.
190 """
191 rv = copy(self)
192 rv.rootlevel = False
193 return rv
194
Armin Ronachere791c2a2008-04-07 18:39:54 +0200195
196class FrameIdentifierVisitor(NodeVisitor):
197 """A visitor for `Frame.inspect`."""
198
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200199 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200200 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200201 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200202
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200203 def visit_Name(self, node, visit_ident, visit_deps):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200204 """All assignments to names go through this function."""
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200205 if visit_ident:
206 if node.ctx in ('store', 'param'):
207 self.identifiers.declared_locally.add(node.name)
208 elif node.ctx == 'load' and not \
209 self.identifiers.is_declared(node.name, self.hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200210 self.identifiers.undeclared.add(node.name)
211
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200212 def visit_Filter(self, node, visit_ident, visit_deps):
213 if visit_deps:
214 self.generic_visit(node, visit_ident, True)
215 self.identifiers.filters.add(node.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200216
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200217 def visit_Test(self, node, visit_ident, visit_deps):
218 if visit_deps:
219 self.generic_visit(node, visit_ident, True)
220 self.identifiers.tests.add(node.name)
Christoph Hack65642a52008-04-08 14:46:56 +0200221
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200222 def visit_Macro(self, node, visit_ident, visit_deps):
223 if visit_ident:
224 self.identifiers.declared_locally.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200225
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200226 def visit_Import(self, node, visit_ident, visit_deps):
227 if visit_ident:
228 self.generic_visit(node, True, visit_deps)
229 self.identifiers.declared_locally.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200230
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200231 def visit_FromImport(self, node, visit_ident, visit_deps):
232 if visit_ident:
233 self.generic_visit(node, True, visit_deps)
234 for name in node.names:
235 if isinstance(name, tuple):
236 self.identifiers.declared_locally.add(name[1])
237 else:
238 self.identifiers.declared_locally.add(name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200239
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200240 def visit_Assign(self, node, visit_ident, visit_deps):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200241 """Visit assignments in the correct order."""
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200242 self.visit(node.node, visit_ident, visit_deps)
243 self.visit(node.target, visit_ident, visit_deps)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200244
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200245 def visit_For(self, node, visit_ident, visit_deps):
246 """Visiting stops at for blocks. However the block sequence
247 is visited as part of the outer scope.
248 """
249 if visit_ident:
250 self.visit(node.iter, True, visit_deps)
251 if visit_deps:
252 for child in node.iter_child_nodes(exclude=('iter',)):
253 self.visit(child, False, True)
254
255 def ident_stop(self, node, visit_ident, visit_deps):
256 if visit_deps:
257 self.generic_visit(node, False, True)
258 visit_CallBlock = visit_FilterBlock = ident_stop
259 visit_Block = lambda s, n, a, b: None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200260
261
Armin Ronacher75cfb862008-04-11 13:47:22 +0200262class CompilerExit(Exception):
263 """Raised if the compiler encountered a situation where it just
264 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200265 raises such an exception is not further processed.
266 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200267
268
Armin Ronachere791c2a2008-04-07 18:39:54 +0200269class CodeGenerator(NodeVisitor):
270
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200271 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200272 if stream is None:
273 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200274 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200275 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200276 self.filename = filename
277 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200278
279 # a registry for all blocks. Because blocks are moved out
280 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200281 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200282
283 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200284 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200285
286 # some templates have a rootlevel extends. In this case we
287 # can safely assume that we're a child template and do some
288 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200289 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200290
Armin Ronacherba3757b2008-04-16 19:43:16 +0200291 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200292 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200293
294 # the debug information
295 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200296 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200297
Armin Ronacherfed44b52008-04-13 19:42:53 +0200298 # the number of new lines before the next write()
299 self._new_lines = 0
300
301 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200302 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200303
304 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200305 self._first_write = True
306
Armin Ronacherfed44b52008-04-13 19:42:53 +0200307 # used by the `temporary_identifier` method to get new
308 # unique, temporary identifier
309 self._last_identifier = 0
310
311 # the current indentation
312 self._indentation = 0
313
Armin Ronachere791c2a2008-04-07 18:39:54 +0200314 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200315 """Get a new unique identifier."""
316 self._last_identifier += 1
317 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200318
319 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200320 """Indent by one."""
321 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200322
Armin Ronacher8efc5222008-04-08 14:47:40 +0200323 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200324 """Outdent by step."""
325 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200326
Armin Ronacher625215e2008-04-13 16:31:08 +0200327 def blockvisit(self, nodes, frame, indent=True, force_generator=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200328 """Visit a list of nodes as block in a frame. Per default the
329 code is indented, but this can be disabled by setting the indent
330 parameter to False. If the current frame is no buffer a dummy
331 ``if 0: yield None`` is written automatically unless the
332 force_generator parameter is set to False.
333 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200334 if indent:
335 self.indent()
336 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200337 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200338 try:
339 for node in nodes:
340 self.visit(node, frame)
341 except CompilerExit:
342 pass
Armin Ronacher625215e2008-04-13 16:31:08 +0200343 if indent:
344 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200345
346 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200347 """Write a string into the output stream."""
348 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200349 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200350 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200351 self.code_lineno += self._new_lines
352 if self._write_debug_info is not None:
353 self.debug_info.append((self._write_debug_info,
354 self.code_lineno))
355 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200356 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200357 self.stream.write(' ' * self._indentation)
358 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200359 self.stream.write(x)
360
361 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200362 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200363 self.newline(node, extra)
364 self.write(x)
365
366 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200367 """Add one or more newlines before the next write."""
368 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200369 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200370 self._write_debug_info = node.lineno
371 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200372
Armin Ronacher71082072008-04-12 14:19:36 +0200373 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200374 """Writes a function call to the stream for the current node.
375 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200376 disabled by setting have_comma to False. The extra keyword
377 arguments may not include python keywords otherwise a syntax
378 error could occour. The extra keyword arguments should be given
379 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200380 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200381 have_comma = have_comma and [True] or []
382 def touch_comma():
383 if have_comma:
384 self.write(', ')
385 else:
386 have_comma.append(True)
387
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200388 # if any of the given keyword arguments is a python keyword
389 # we have to make sure that no invalid call is created.
390 kwarg_workaround = False
391 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
392 if iskeyword(kwarg):
393 kwarg_workaround = True
394 break
395
Armin Ronacher8efc5222008-04-08 14:47:40 +0200396 for arg in node.args:
397 touch_comma()
398 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200399
400 if not kwarg_workaround:
401 for kwarg in node.kwargs:
402 touch_comma()
403 self.visit(kwarg, frame)
404 if extra_kwargs is not None:
405 for key, value in extra_kwargs.iteritems():
406 touch_comma()
407 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200408 if node.dyn_args:
409 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200410 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200411 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200412
413 if kwarg_workaround:
414 touch_comma()
415 if node.dyn_kwargs is not None:
416 self.write('**dict({')
417 else:
418 self.write('**{')
419 for kwarg in node.kwargs:
420 self.write('%r: ' % kwarg.key)
421 self.visit(kwarg.value, frame)
422 self.write(', ')
423 if extra_kwargs is not None:
424 for key, value in extra_kwargs.iteritems():
425 touch_comma()
426 self.write('%r: %s, ' % (key, value))
427 if node.dyn_kwargs is not None:
428 self.write('}, **')
429 self.visit(node.dyn_kwargs, frame)
430 self.write(')')
431 else:
432 self.write('}')
433
434 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200435 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200436 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200437 self.visit(node.dyn_kwargs, frame)
438
Armin Ronacher625215e2008-04-13 16:31:08 +0200439 def pull_locals(self, frame, indent=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200440 """Pull all the references identifiers into the local scope.
441 This affects regular names, filters and tests. If indent is
442 set to False, no automatic indentation will take place.
443 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200444 if indent:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200445 self.indent()
446 for name in frame.identifiers.undeclared:
447 self.writeline('l_%s = context[%r]' % (name, name))
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200448 for name in frame.identifiers.filters:
449 self.writeline('f_%s = environment.filters[%r]' % (name, name))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200450 for name in frame.identifiers.tests:
451 self.writeline('t_%s = environment.tests[%r]' % (name, name))
Armin Ronacher625215e2008-04-13 16:31:08 +0200452 if indent:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200453 self.outdent()
454
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200455 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200456 """This function returns all the shadowed variables in a dict
457 in the form name: alias and will write the required assignments
458 into the current scope. No indentation takes place.
459 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200460 # make sure we "backup" overridden, local identifiers
461 # TODO: we should probably optimize this and check if the
462 # identifier is in use afterwards.
463 aliases = {}
464 for name in frame.identifiers.find_shadowed():
465 aliases[name] = ident = self.temporary_identifier()
466 self.writeline('%s = l_%s' % (ident, name))
467 return aliases
468
Armin Ronacher71082072008-04-12 14:19:36 +0200469 def function_scoping(self, node, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200470 """In Jinja a few statements require the help of anonymous
471 functions. Those are currently macros and call blocks and in
472 the future also recursive loops. As there is currently
473 technical limitation that doesn't allow reading and writing a
474 variable in a scope where the initial value is coming from an
475 outer scope, this function tries to fall back with a common
476 error message. Additionally the frame passed is modified so
477 that the argumetns are collected and callers are looked up.
478
479 This will return the modified frame.
480 """
Armin Ronacher71082072008-04-12 14:19:36 +0200481 func_frame = frame.inner()
482 func_frame.inspect(node.iter_child_nodes(), hard_scope=True)
483
484 # variables that are undeclared (accessed before declaration) and
485 # declared locally *and* part of an outside scope raise a template
486 # assertion error. Reason: we can't generate reasonable code from
487 # it without aliasing all the variables. XXX: alias them ^^
488 overriden_closure_vars = (
489 func_frame.identifiers.undeclared &
490 func_frame.identifiers.declared &
491 (func_frame.identifiers.declared_locally |
492 func_frame.identifiers.declared_parameter)
493 )
494 if overriden_closure_vars:
495 vars = ', '.join(sorted(overriden_closure_vars))
496 raise TemplateAssertionError('It\'s not possible to set and '
497 'access variables derived from '
498 'an outer scope! (affects: %s' %
Armin Ronacher68f77672008-04-17 11:50:39 +0200499 vars, node.lineno, self.name)
Armin Ronacher71082072008-04-12 14:19:36 +0200500
501 # remove variables from a closure from the frame's undeclared
502 # identifiers.
503 func_frame.identifiers.undeclared -= (
504 func_frame.identifiers.undeclared &
505 func_frame.identifiers.declared
506 )
507
Armin Ronacher963f97d2008-04-25 11:44:59 +0200508 func_frame.accesses_kwargs = False
509 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200510 func_frame.accesses_caller = False
511 func_frame.arguments = args = ['l_' + x.name for x in node.args]
512
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200513 if 'caller' in func_frame.identifiers.undeclared:
514 func_frame.accesses_caller = True
515 func_frame.identifiers.add_special('caller')
516 args.append('l_caller')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200517 if 'kwargs' in func_frame.identifiers.undeclared:
518 func_frame.accesses_kwargs = True
519 func_frame.identifiers.add_special('kwargs')
520 args.append('l_kwargs')
521 if 'varargs' in func_frame.identifiers.undeclared:
522 func_frame.accesses_varargs = True
523 func_frame.identifiers.add_special('varargs')
524 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200525 return func_frame
526
Armin Ronachere791c2a2008-04-07 18:39:54 +0200527 # -- Visitors
528
529 def visit_Template(self, node, frame=None):
530 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200531 from jinja2.runtime import __all__ as exported
532 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200533 self.writeline('name = %r' % self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200534
Armin Ronacher75cfb862008-04-11 13:47:22 +0200535 # do we have an extends tag at all? If not, we can save some
536 # overhead by just not processing any inheritance code.
537 have_extends = node.find(nodes.Extends) is not None
538
Armin Ronacher8edbe492008-04-10 20:43:43 +0200539 # find all blocks
540 for block in node.find_all(nodes.Block):
541 if block.name in self.blocks:
542 raise TemplateAssertionError('block %r defined twice' %
543 block.name, block.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200544 self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200545 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200546
Armin Ronacher8efc5222008-04-08 14:47:40 +0200547 # generate the root render function.
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200548 self.writeline('def root(context, environment=environment'
549 '):', 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 Ronacher0611e492008-04-25 23:44:14 +0200681 self.write('context[%r] = ' % node.target)
682 self.write('environment.get_template(')
683 self.visit(node.template, frame)
684 self.write(', %r).include(context)' % self.name)
685
686 def visit_FromImport(self, node, frame):
687 """Visit named imports."""
688 self.newline(node)
689 self.write('included_template = environment.get_template(')
690 self.visit(node.template, frame)
691 self.write(', %r).include(context)' % self.name)
692 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200693 if isinstance(name, tuple):
694 name, alias = name
695 else:
696 alias = name
Armin Ronacher0611e492008-04-25 23:44:14 +0200697 self.writeline('l_%s = getattr(included_template, '
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200698 '%r, missing)' % (alias, name))
699 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200700 self.indent()
701 self.writeline('l_%s = environment.undefined(%r %% '
702 'included_template.name)' %
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200703 (alias, 'the template %r does not export '
Armin Ronacher0611e492008-04-25 23:44:14 +0200704 'the requested name ' + repr(name)))
705 self.outdent()
706 if frame.toplevel:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200707 self.writeline('context[%r] = l_%s' % (alias, alias))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200708
Armin Ronachere791c2a2008-04-07 18:39:54 +0200709 def visit_For(self, node, frame):
710 loop_frame = frame.inner()
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200711 loop_frame.inspect(node.iter_child_nodes(exclude=('iter',)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200712 extended_loop = bool(node.else_) or \
713 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200714 if extended_loop:
715 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200716
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200717 aliases = self.collect_shadowed(loop_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200718 self.pull_locals(loop_frame, indent=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200719 if node.else_:
720 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200721
722 self.newline(node)
723 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200724 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200725 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200726
727 # the expression pointing to the parent loop. We make the
728 # undefined a bit more debug friendly at the same time.
729 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200730 or "environment.undefined(%r)" % "'loop' is undefined. " \
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200731 'the filter section of a loop as well as the ' \
732 'else block doesn\'t have access to the special ' \
733 "'loop' variable of the current loop. Because " \
734 'there is no parent loop it\'s undefined.'
735
736 # if we have an extened loop and a node test, we filter in the
737 # "outer frame".
738 if extended_loop and node.test is not None:
739 self.write('(')
740 self.visit(node.target, loop_frame)
741 self.write(' for ')
742 self.visit(node.target, loop_frame)
743 self.write(' in ')
744 self.visit(node.iter, loop_frame)
745 self.write(' if (')
746 test_frame = loop_frame.copy()
747 test_frame.name_overrides['loop'] = parent_loop
748 self.visit(node.test, test_frame)
749 self.write('))')
750
751 else:
752 self.visit(node.iter, loop_frame)
753
Armin Ronachere791c2a2008-04-07 18:39:54 +0200754 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200755
756 # tests in not extended loops become a continue
757 if not extended_loop and node.test is not None:
758 self.indent()
759 self.writeline('if ')
760 self.visit(node.test)
761 self.write(':')
762 self.indent()
763 self.writeline('continue')
764 self.outdent(2)
765
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200766 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200767
768 if node.else_:
769 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200770 self.indent()
771 self.writeline('l_loop = ' + parent_loop)
772 self.outdent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200773 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200774
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200775 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200776 for name, alias in aliases.iteritems():
Armin Ronacher8efc5222008-04-08 14:47:40 +0200777 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200778
779 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200780 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200781 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200782 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200783 self.write(':')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200784 self.blockvisit(node.body, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200785 if node.else_:
786 self.writeline('else:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200787 self.blockvisit(node.else_, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200788
Armin Ronacher8efc5222008-04-08 14:47:40 +0200789 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200790 macro_frame = self.function_scoping(node, frame)
791 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200792 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200793 macro_frame.buffer = buf = self.temporary_identifier()
794 self.indent()
795 self.pull_locals(macro_frame, indent=False)
796 self.writeline('%s = []' % buf)
797 self.blockvisit(node.body, macro_frame, indent=False)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200798 self.writeline("return Markup(concat(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200799 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200800 self.newline()
801 if frame.toplevel:
802 self.write('context[%r] = ' % node.name)
803 arg_tuple = ', '.join(repr(x.name) for x in node.args)
804 if len(node.args) == 1:
805 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200806 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
807 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200808 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200809 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200810 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200811 self.write('), %s, %s, %s)' % (
812 macro_frame.accesses_kwargs and '1' or '0',
813 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200814 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200815 ))
816
817 def visit_CallBlock(self, node, frame):
818 call_frame = self.function_scoping(node, frame)
819 args = call_frame.arguments
820 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200821 call_frame.buffer = buf = self.temporary_identifier()
822 self.indent()
823 self.pull_locals(call_frame, indent=False)
824 self.writeline('%s = []' % buf)
825 self.blockvisit(node.body, call_frame, indent=False)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200826 self.writeline("return Markup(concat(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200827 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200828 arg_tuple = ', '.join(repr(x.name) for x in node.args)
829 if len(node.args) == 1:
830 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200831 self.writeline('caller = Macro(environment, call, None, (%s), (' %
832 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200833 for arg in node.defaults:
834 self.visit(arg)
835 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200836 self.write('), %s, %s, 0)' % (
837 call_frame.accesses_kwargs and '1' or '0',
838 call_frame.accesses_varargs and '1' or '0'
839 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200840 if frame.buffer is None:
841 self.writeline('yield ', node)
842 else:
843 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200844 self.visit_Call(node.call, call_frame,
845 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200846 if frame.buffer is not None:
847 self.write(')')
848
849 def visit_FilterBlock(self, node, frame):
850 filter_frame = frame.inner()
851 filter_frame.inspect(node.iter_child_nodes())
852
853 aliases = self.collect_shadowed(filter_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200854 self.pull_locals(filter_frame, indent=False)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200855 filter_frame.buffer = buf = self.temporary_identifier()
856
857 self.writeline('%s = []' % buf, node)
858 for child in node.body:
859 self.visit(child, filter_frame)
860
861 if frame.buffer is None:
862 self.writeline('yield ', node)
863 else:
864 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200865 self.visit_Filter(node.filter, filter_frame, 'concat(%s)' % buf)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200866 if frame.buffer is not None:
867 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200868
Armin Ronachere791c2a2008-04-07 18:39:54 +0200869 def visit_ExprStmt(self, node, frame):
870 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +0200871 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200872
873 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200874 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +0200875 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200876 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200877
Armin Ronacher75cfb862008-04-11 13:47:22 +0200878 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200879 if self.environment.finalize is unicode:
880 finalizer = 'unicode'
Armin Ronacherf059ec12008-04-11 22:21:00 +0200881 have_finalizer = False
Armin Ronacher8edbe492008-04-10 20:43:43 +0200882 else:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200883 finalizer = 'environment.finalize'
884 have_finalizer = True
Armin Ronacher8edbe492008-04-10 20:43:43 +0200885
Armin Ronacher7fb38972008-04-11 13:54:28 +0200886 # if we are in the toplevel scope and there was already an extends
887 # statement we have to add a check that disables our yield(s) here
888 # so that they don't appear in the output.
889 outdent_later = False
890 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200891 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200892 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200893 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +0200894
Armin Ronachere791c2a2008-04-07 18:39:54 +0200895 # try to evaluate as many chunks as possible into a static
896 # string at compile time.
897 body = []
898 for child in node.nodes:
899 try:
900 const = unicode(child.as_const())
901 except:
902 body.append(child)
903 continue
904 if body and isinstance(body[-1], list):
905 body[-1].append(const)
906 else:
907 body.append([const])
908
909 # if we have less than 3 nodes we just yield them
910 if len(body) < 3:
911 for item in body:
912 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +0200913 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200914 if frame.buffer is None:
915 self.writeline('yield ' + val)
916 else:
917 self.writeline('%s.append(%s)' % (frame.buffer, val))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200918 else:
919 self.newline(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200920 if frame.buffer is None:
921 self.write('yield ')
922 else:
923 self.write('%s.append(' % frame.buffer)
924 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200925 self.visit(item, frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200926 self.write(')' * (1 + (frame.buffer is not None)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200927
928 # otherwise we create a format string as this is faster in that case
929 else:
930 format = []
931 arguments = []
932 for item in body:
933 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +0200934 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200935 else:
936 format.append('%s')
937 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200938 if frame.buffer is None:
939 self.writeline('yield ')
940 else:
941 self.writeline('%s.append(' % frame.buffer)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200942 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200943 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200944 self.indent()
945 for argument in arguments:
946 self.newline(argument)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200947 if have_finalizer:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200948 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200949 self.visit(argument, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200950 if have_finalizer:
Armin Ronacher8edbe492008-04-10 20:43:43 +0200951 self.write(')')
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200952 self.write(',')
953 self.outdent()
954 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200955 if frame.buffer is not None:
956 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200957
Armin Ronacher7fb38972008-04-11 13:54:28 +0200958 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200959 self.outdent()
960
Armin Ronacher8efc5222008-04-08 14:47:40 +0200961 def visit_Assign(self, node, frame):
962 self.newline(node)
963 # toplevel assignments however go into the local namespace and
964 # the current template's context. We create a copy of the frame
965 # here and add a set so that the Name visitor can add the assigned
966 # names here.
967 if frame.toplevel:
968 assignment_frame = frame.copy()
969 assignment_frame.assigned_names = set()
970 else:
971 assignment_frame = frame
972 self.visit(node.target, assignment_frame)
973 self.write(' = ')
974 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200975
976 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200977 if frame.toplevel:
978 for name in assignment_frame.assigned_names:
979 self.writeline('context[%r] = l_%s' % (name, name))
980
Armin Ronachere791c2a2008-04-07 18:39:54 +0200981 def visit_Name(self, node, frame):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200982 if node.ctx == 'store':
983 if frame.toplevel:
984 frame.assigned_names.add(node.name)
985 frame.name_overrides.pop(node.name, None)
986 elif node.ctx == 'load':
987 if node.name in frame.name_overrides:
988 self.write(frame.name_overrides[node.name])
989 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200990 self.write('l_' + node.name)
991
992 def visit_Const(self, node, frame):
993 val = node.value
994 if isinstance(val, float):
995 # XXX: add checks for infinity and nan
996 self.write(str(val))
997 else:
998 self.write(repr(val))
999
Armin Ronacher8efc5222008-04-08 14:47:40 +02001000 def visit_Tuple(self, node, frame):
1001 self.write('(')
1002 idx = -1
1003 for idx, item in enumerate(node.items):
1004 if idx:
1005 self.write(', ')
1006 self.visit(item, frame)
1007 self.write(idx == 0 and ',)' or ')')
1008
Armin Ronacher8edbe492008-04-10 20:43:43 +02001009 def visit_List(self, node, frame):
1010 self.write('[')
1011 for idx, item in enumerate(node.items):
1012 if idx:
1013 self.write(', ')
1014 self.visit(item, frame)
1015 self.write(']')
1016
1017 def visit_Dict(self, node, frame):
1018 self.write('{')
1019 for idx, item in enumerate(node.items):
1020 if idx:
1021 self.write(', ')
1022 self.visit(item.key, frame)
1023 self.write(': ')
1024 self.visit(item.value, frame)
1025 self.write('}')
1026
Armin Ronachere791c2a2008-04-07 18:39:54 +02001027 def binop(operator):
1028 def visitor(self, node, frame):
1029 self.write('(')
1030 self.visit(node.left, frame)
1031 self.write(' %s ' % operator)
1032 self.visit(node.right, frame)
1033 self.write(')')
1034 return visitor
1035
1036 def uaop(operator):
1037 def visitor(self, node, frame):
1038 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001039 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001040 self.write(')')
1041 return visitor
1042
1043 visit_Add = binop('+')
1044 visit_Sub = binop('-')
1045 visit_Mul = binop('*')
1046 visit_Div = binop('/')
1047 visit_FloorDiv = binop('//')
1048 visit_Pow = binop('**')
1049 visit_Mod = binop('%')
1050 visit_And = binop('and')
1051 visit_Or = binop('or')
1052 visit_Pos = uaop('+')
1053 visit_Neg = uaop('-')
1054 visit_Not = uaop('not ')
1055 del binop, uaop
1056
1057 def visit_Compare(self, node, frame):
1058 self.visit(node.expr, frame)
1059 for op in node.ops:
1060 self.visit(op, frame)
1061
1062 def visit_Operand(self, node, frame):
1063 self.write(' %s ' % operators[node.op])
1064 self.visit(node.expr, frame)
1065
1066 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001067 if isinstance(node.arg, nodes.Slice):
1068 self.visit(node.node, frame)
1069 self.write('[')
1070 self.visit(node.arg, frame)
1071 self.write(']')
1072 return
1073 try:
1074 const = node.arg.as_const()
1075 have_const = True
1076 except nodes.Impossible:
1077 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001078 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001079 self.visit(node.node, frame)
1080 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001081 if have_const:
1082 self.write(repr(const))
1083 else:
1084 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001085 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001086
1087 def visit_Slice(self, node, frame):
1088 if node.start is not None:
1089 self.visit(node.start, frame)
1090 self.write(':')
1091 if node.stop is not None:
1092 self.visit(node.stop, frame)
1093 if node.step is not None:
1094 self.write(':')
1095 self.visit(node.step, frame)
1096
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001097 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001098 self.write('f_%s(' % node.name)
Christoph Hack80909862008-04-14 01:35:10 +02001099 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001100 if func is None:
1101 raise TemplateAssertionError('no filter named %r' % node.name,
1102 node.lineno, self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001103 if getattr(func, 'contextfilter', False):
1104 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001105 elif getattr(func, 'environmentfilter', False):
1106 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001107 if isinstance(node.node, nodes.Filter):
1108 self.visit_Filter(node.node, frame, initial)
1109 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001110 self.write(initial)
1111 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001112 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001113 self.signature(node, frame)
1114 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001115
1116 def visit_Test(self, node, frame):
Armin Ronacherf059ec12008-04-11 22:21:00 +02001117 self.write('t_%s(' % node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001118 if node.name not in self.environment.tests:
1119 raise TemplateAssertionError('no test named %r' % node.name,
1120 node.lineno, self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001121 self.visit(node.node, frame)
1122 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001123 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001124
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001125 def visit_CondExpr(self, node, frame):
1126 if not have_condexpr:
1127 self.write('((')
1128 self.visit(node.test, frame)
1129 self.write(') and (')
1130 self.visit(node.expr1, frame)
1131 self.write(',) or (')
1132 self.visit(node.expr2, frame)
1133 self.write(',))[0]')
1134 else:
1135 self.write('(')
1136 self.visit(node.expr1, frame)
1137 self.write(' if ')
1138 self.visit(node.test, frame)
1139 self.write(' else ')
1140 self.visit(node.expr2, frame)
1141 self.write(')')
1142
Armin Ronacher71082072008-04-12 14:19:36 +02001143 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001144 if self.environment.sandboxed:
1145 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001146 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001147 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001148 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001149 self.write(')')
1150
1151 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001152 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001153 self.visit(node.value, frame)