blob: 8282bc6c58a0e6c4dc89e4cc9413afb7a8f37461 [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 Ronachere791c2a2008-04-07 18:39:54 +020013from cStringIO import StringIO
14from jinja2 import nodes
15from jinja2.visitor import NodeVisitor, NodeTransformer
16from jinja2.exceptions import TemplateAssertionError
Armin Ronacher4dfc9752008-04-09 15:03:29 +020017from jinja2.runtime import StaticLoopContext
Armin Ronacher5236d8c2008-04-17 11:23:16 +020018from jinja2.utils import Markup
Armin Ronachere791c2a2008-04-07 18:39:54 +020019
20
21operators = {
22 'eq': '==',
23 'ne': '!=',
24 'gt': '>',
25 'gteq': '>=',
26 'lt': '<',
27 'lteq': '<=',
28 'in': 'in',
29 'notin': 'not in'
30}
31
32
Armin Ronacher3d8b7842008-04-13 13:16:50 +020033try:
34 exec '(0 if 0 else 0)'
35except SyntaxError:
36 have_condexpr = False
37else:
38 have_condexpr = True
39
40
Armin Ronacher8e8d0712008-04-16 23:10:49 +020041def generate(node, environment, name, filename, stream=None):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020042 """Generate the python source for a node tree."""
Armin Ronacher8e8d0712008-04-16 23:10:49 +020043 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020044 generator.visit(node)
45 if stream is None:
46 return generator.stream.getvalue()
47
48
Armin Ronacher4dfc9752008-04-09 15:03:29 +020049def has_safe_repr(value):
50 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020051 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020052 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020053 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher5236d8c2008-04-17 11:23:16 +020054 xrange, StaticLoopContext, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020055 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020056 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020057 for item in value:
58 if not has_safe_repr(item):
59 return False
60 return True
61 elif isinstance(value, dict):
62 for key, value in value.iteritems():
63 if not has_safe_repr(key):
64 return False
65 if not has_safe_repr(value):
66 return False
67 return True
68 return False
69
70
Armin Ronachere791c2a2008-04-07 18:39:54 +020071class Identifiers(object):
72 """Tracks the status of identifiers in frames."""
73
74 def __init__(self):
75 # variables that are known to be declared (probably from outer
76 # frames or because they are special for the frame)
77 self.declared = set()
78
Armin Ronacher10f3ba22008-04-18 11:30:37 +020079 # undeclared variables from outer scopes
80 self.outer_undeclared = set()
81
Armin Ronachere791c2a2008-04-07 18:39:54 +020082 # names that are accessed without being explicitly declared by
83 # this one or any of the outer scopes. Names can appear both in
84 # declared and undeclared.
85 self.undeclared = set()
86
87 # names that are declared locally
88 self.declared_locally = set()
89
90 # names that are declared by parameters
91 self.declared_parameter = set()
92
Armin Ronacherf059ec12008-04-11 22:21:00 +020093 # filters/tests that are referenced
Armin Ronacherd4c64f72008-04-11 17:15:29 +020094 self.filters = set()
Armin Ronacherf059ec12008-04-11 22:21:00 +020095 self.tests = set()
Christoph Hack65642a52008-04-08 14:46:56 +020096
Armin Ronachere791c2a2008-04-07 18:39:54 +020097 def add_special(self, name):
98 """Register a special name like `loop`."""
99 self.undeclared.discard(name)
100 self.declared.add(name)
101
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200102 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200103 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200104 if name in self.declared_locally or name in self.declared_parameter:
105 return True
106 if local_only:
107 return False
108 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200109
110 def find_shadowed(self):
111 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200112 return (self.declared | self.outer_undeclared) & \
113 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200114
115
116class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200117 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200118
119 def __init__(self, parent=None):
120 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200121
Armin Ronacher75cfb862008-04-11 13:47:22 +0200122 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200123 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200124
Armin Ronacher75cfb862008-04-11 13:47:22 +0200125 # the root frame is basically just the outermost frame, so no if
126 # conditions. This information is used to optimize inheritance
127 # situations.
128 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200129
130 # inside some tags we are using a buffer rather than yield statements.
131 # this for example affects {% filter %} or {% macro %}. If a frame
132 # is buffered this variable points to the name of the list used as
133 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200134 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200135
136 # if a frame has name_overrides, all read access to a name in this
137 # dict is redirected to a string expression.
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200138 self.name_overrides = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200139
140 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200141 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200142
143 # the parent of this frame
144 self.parent = parent
145
Armin Ronachere791c2a2008-04-07 18:39:54 +0200146 if parent is not None:
147 self.identifiers.declared.update(
148 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200149 parent.identifiers.declared_locally |
150 parent.identifiers.declared_parameter
151 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200152 self.identifiers.outer_undeclared.update(
153 parent.identifiers.undeclared -
154 self.identifiers.declared
155 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200156 self.buffer = parent.buffer
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200157 self.name_overrides = parent.name_overrides.copy()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200158
Armin Ronacher8efc5222008-04-08 14:47:40 +0200159 def copy(self):
160 """Create a copy of the current one."""
161 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200162 rv.identifiers = copy(self.identifiers)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200163 rv.name_overrides = self.name_overrides.copy()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200164 return rv
165
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200166 def inspect(self, nodes, hard_scope=False):
167 """Walk the node and check for identifiers. If the scope
168 is hard (eg: enforce on a python level) overrides from outer
169 scopes are tracked differently.
170 """
171 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200172 for node in nodes:
173 visitor.visit(node)
174
175 def inner(self):
176 """Return an inner frame."""
177 return Frame(self)
178
Armin Ronacher75cfb862008-04-11 13:47:22 +0200179 def soft(self):
180 """Return a soft frame. A soft frame may not be modified as
181 standalone thing as it shares the resources with the frame it
182 was created of, but it's not a rootlevel frame any longer.
183 """
184 rv = copy(self)
185 rv.rootlevel = False
186 return rv
187
Armin Ronachere791c2a2008-04-07 18:39:54 +0200188
189class FrameIdentifierVisitor(NodeVisitor):
190 """A visitor for `Frame.inspect`."""
191
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200192 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200193 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200194 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200195
196 def visit_Name(self, node):
197 """All assignments to names go through this function."""
198 if node.ctx in ('store', 'param'):
199 self.identifiers.declared_locally.add(node.name)
200 elif node.ctx == 'load':
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200201 if not self.identifiers.is_declared(node.name, self.hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200202 self.identifiers.undeclared.add(node.name)
203
Armin Ronacherd55ab532008-04-09 16:13:39 +0200204 def visit_Filter(self, node):
Armin Ronacher449167d2008-04-11 17:55:05 +0200205 self.generic_visit(node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200206 self.identifiers.filters.add(node.name)
207
208 def visit_Test(self, node):
209 self.generic_visit(node)
210 self.identifiers.tests.add(node.name)
Christoph Hack65642a52008-04-08 14:46:56 +0200211
Armin Ronachere791c2a2008-04-07 18:39:54 +0200212 def visit_Macro(self, node):
213 """Macros set local."""
214 self.identifiers.declared_locally.add(node.name)
215
Armin Ronacherf059ec12008-04-11 22:21:00 +0200216 def visit_Include(self, node):
217 """Some includes set local."""
218 self.generic_visit(node)
219 if node.target is not None:
220 self.identifiers.declared_locally.add(node.target)
221
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200222 def visit_Assign(self, node):
223 """Visit assignments in the correct order."""
224 self.visit(node.node)
225 self.visit(node.target)
226
Armin Ronachere791c2a2008-04-07 18:39:54 +0200227 # stop traversing at instructions that have their own scope.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200228 visit_Block = visit_CallBlock = visit_FilterBlock = \
Armin Ronachere791c2a2008-04-07 18:39:54 +0200229 visit_For = lambda s, n: None
230
231
Armin Ronacher75cfb862008-04-11 13:47:22 +0200232class CompilerExit(Exception):
233 """Raised if the compiler encountered a situation where it just
234 doesn't make sense to further process the code. Any block that
235 raises such an exception is not further processed."""
236
237
Armin Ronachere791c2a2008-04-07 18:39:54 +0200238class CodeGenerator(NodeVisitor):
239
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200240 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200241 if stream is None:
242 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200243 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200244 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200245 self.filename = filename
246 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200247
248 # a registry for all blocks. Because blocks are moved out
249 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200250 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200251
252 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200253 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200254
255 # some templates have a rootlevel extends. In this case we
256 # can safely assume that we're a child template and do some
257 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200258 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200259
Armin Ronacherba3757b2008-04-16 19:43:16 +0200260 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200261 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200262
263 # the debug information
264 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200265 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200266
Armin Ronacherfed44b52008-04-13 19:42:53 +0200267 # the number of new lines before the next write()
268 self._new_lines = 0
269
270 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200271 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200272
273 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200274 self._first_write = True
275
Armin Ronacherfed44b52008-04-13 19:42:53 +0200276 # used by the `temporary_identifier` method to get new
277 # unique, temporary identifier
278 self._last_identifier = 0
279
280 # the current indentation
281 self._indentation = 0
282
Armin Ronachere791c2a2008-04-07 18:39:54 +0200283 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200284 """Get a new unique identifier."""
285 self._last_identifier += 1
286 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200287
288 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200289 """Indent by one."""
290 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200291
Armin Ronacher8efc5222008-04-08 14:47:40 +0200292 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200293 """Outdent by step."""
294 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200295
Armin Ronacher625215e2008-04-13 16:31:08 +0200296 def blockvisit(self, nodes, frame, indent=True, force_generator=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200297 """Visit a list of nodes as block in a frame. Per default the
298 code is indented, but this can be disabled by setting the indent
299 parameter to False. If the current frame is no buffer a dummy
300 ``if 0: yield None`` is written automatically unless the
301 force_generator parameter is set to False.
302 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200303 if indent:
304 self.indent()
305 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200306 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200307 try:
308 for node in nodes:
309 self.visit(node, frame)
310 except CompilerExit:
311 pass
Armin Ronacher625215e2008-04-13 16:31:08 +0200312 if indent:
313 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200314
315 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200316 """Write a string into the output stream."""
317 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200318 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200319 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200320 self.code_lineno += self._new_lines
321 if self._write_debug_info is not None:
322 self.debug_info.append((self._write_debug_info,
323 self.code_lineno))
324 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200325 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200326 self.stream.write(' ' * self._indentation)
327 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200328 self.stream.write(x)
329
330 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200331 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200332 self.newline(node, extra)
333 self.write(x)
334
335 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200336 """Add one or more newlines before the next write."""
337 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200338 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200339 self._write_debug_info = node.lineno
340 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200341
Armin Ronacher71082072008-04-12 14:19:36 +0200342 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200343 """Writes a function call to the stream for the current node.
344 Per default it will write a leading comma but this can be
345 disabled by setting have_comma to False. If extra_kwargs is
346 given it must be a string that represents a single keyword
347 argument call that is inserted at the end of the regular
348 keyword argument calls.
349 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200350 have_comma = have_comma and [True] or []
351 def touch_comma():
352 if have_comma:
353 self.write(', ')
354 else:
355 have_comma.append(True)
356
357 for arg in node.args:
358 touch_comma()
359 self.visit(arg, frame)
360 for kwarg in node.kwargs:
361 touch_comma()
362 self.visit(kwarg, frame)
Armin Ronacher71082072008-04-12 14:19:36 +0200363 if extra_kwargs is not None:
364 touch_comma()
365 self.write(extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200366 if node.dyn_args:
367 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200368 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200369 self.visit(node.dyn_args, frame)
370 if node.dyn_kwargs:
371 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200372 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200373 self.visit(node.dyn_kwargs, frame)
374
Armin Ronacher625215e2008-04-13 16:31:08 +0200375 def pull_locals(self, frame, indent=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200376 """Pull all the references identifiers into the local scope.
377 This affects regular names, filters and tests. If indent is
378 set to False, no automatic indentation will take place.
379 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200380 if indent:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200381 self.indent()
382 for name in frame.identifiers.undeclared:
383 self.writeline('l_%s = context[%r]' % (name, name))
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200384 for name in frame.identifiers.filters:
385 self.writeline('f_%s = environment.filters[%r]' % (name, name))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200386 for name in frame.identifiers.tests:
387 self.writeline('t_%s = environment.tests[%r]' % (name, name))
Armin Ronacher625215e2008-04-13 16:31:08 +0200388 if indent:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200389 self.outdent()
390
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200391 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200392 """This function returns all the shadowed variables in a dict
393 in the form name: alias and will write the required assignments
394 into the current scope. No indentation takes place.
395 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200396 # make sure we "backup" overridden, local identifiers
397 # TODO: we should probably optimize this and check if the
398 # identifier is in use afterwards.
399 aliases = {}
400 for name in frame.identifiers.find_shadowed():
401 aliases[name] = ident = self.temporary_identifier()
402 self.writeline('%s = l_%s' % (ident, name))
403 return aliases
404
Armin Ronacher71082072008-04-12 14:19:36 +0200405 def function_scoping(self, node, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200406 """In Jinja a few statements require the help of anonymous
407 functions. Those are currently macros and call blocks and in
408 the future also recursive loops. As there is currently
409 technical limitation that doesn't allow reading and writing a
410 variable in a scope where the initial value is coming from an
411 outer scope, this function tries to fall back with a common
412 error message. Additionally the frame passed is modified so
413 that the argumetns are collected and callers are looked up.
414
415 This will return the modified frame.
416 """
Armin Ronacher71082072008-04-12 14:19:36 +0200417 func_frame = frame.inner()
418 func_frame.inspect(node.iter_child_nodes(), hard_scope=True)
419
420 # variables that are undeclared (accessed before declaration) and
421 # declared locally *and* part of an outside scope raise a template
422 # assertion error. Reason: we can't generate reasonable code from
423 # it without aliasing all the variables. XXX: alias them ^^
424 overriden_closure_vars = (
425 func_frame.identifiers.undeclared &
426 func_frame.identifiers.declared &
427 (func_frame.identifiers.declared_locally |
428 func_frame.identifiers.declared_parameter)
429 )
430 if overriden_closure_vars:
431 vars = ', '.join(sorted(overriden_closure_vars))
432 raise TemplateAssertionError('It\'s not possible to set and '
433 'access variables derived from '
434 'an outer scope! (affects: %s' %
Armin Ronacher68f77672008-04-17 11:50:39 +0200435 vars, node.lineno, self.name)
Armin Ronacher71082072008-04-12 14:19:36 +0200436
437 # remove variables from a closure from the frame's undeclared
438 # identifiers.
439 func_frame.identifiers.undeclared -= (
440 func_frame.identifiers.undeclared &
441 func_frame.identifiers.declared
442 )
443
Armin Ronacher963f97d2008-04-25 11:44:59 +0200444 func_frame.accesses_kwargs = False
445 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200446 func_frame.accesses_caller = False
447 func_frame.arguments = args = ['l_' + x.name for x in node.args]
448
Armin Ronacher963f97d2008-04-25 11:44:59 +0200449 if 'kwargs' in func_frame.identifiers.undeclared:
450 func_frame.accesses_kwargs = True
451 func_frame.identifiers.add_special('kwargs')
452 args.append('l_kwargs')
453 if 'varargs' in func_frame.identifiers.undeclared:
454 func_frame.accesses_varargs = True
455 func_frame.identifiers.add_special('varargs')
456 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200457 if 'caller' in func_frame.identifiers.undeclared:
458 func_frame.accesses_caller = True
459 func_frame.identifiers.add_special('caller')
460 args.append('l_caller')
461 return func_frame
462
Armin Ronachere791c2a2008-04-07 18:39:54 +0200463 # -- Visitors
464
465 def visit_Template(self, node, frame=None):
466 assert frame is None, 'no root frame allowed'
467 self.writeline('from jinja2.runtime import *')
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200468 self.writeline('name = %r' % self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200469
Armin Ronacher75cfb862008-04-11 13:47:22 +0200470 # do we have an extends tag at all? If not, we can save some
471 # overhead by just not processing any inheritance code.
472 have_extends = node.find(nodes.Extends) is not None
473
Armin Ronacher8edbe492008-04-10 20:43:43 +0200474 # find all blocks
475 for block in node.find_all(nodes.Block):
476 if block.name in self.blocks:
477 raise TemplateAssertionError('block %r defined twice' %
478 block.name, block.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200479 self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200480 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200481
Armin Ronacher8efc5222008-04-08 14:47:40 +0200482 # generate the root render function.
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200483 self.writeline('def root(context, environment=environment'
484 '):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200485 if have_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200486 self.indent()
487 self.writeline('parent_template = None')
488 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200489
490 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200491 frame = Frame()
492 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200493 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200494 self.indent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200495 self.pull_locals(frame, indent=False)
Armin Ronacher625215e2008-04-13 16:31:08 +0200496 self.blockvisit(node.body, frame, indent=False)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200497 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200498
Armin Ronacher8efc5222008-04-08 14:47:40 +0200499 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200500 if have_extends:
501 if not self.has_known_extends:
502 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200503 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200504 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200505 self.writeline('for event in parent_template.'
506 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200507 self.indent()
508 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200509 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200510
511 # at this point we now have the blocks collected and can visit them too.
512 for name, block in self.blocks.iteritems():
513 block_frame = Frame()
514 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200515 block_frame.block = name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200516 block_frame.identifiers.add_special('super')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200517 block_frame.name_overrides['super'] = 'context.super(%r, ' \
518 'block_%s)' % (name, name)
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200519 self.writeline('def block_%s(context, environment=environment):'
520 % name, block, 1)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200521 self.pull_locals(block_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200522 self.blockvisit(block.body, block_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200523
Armin Ronacher75cfb862008-04-11 13:47:22 +0200524 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200525 for x in self.blocks),
526 extra=1)
527
528 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200529 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
530 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200531
Armin Ronachere791c2a2008-04-07 18:39:54 +0200532 def visit_Block(self, node, frame):
533 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200534 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200535 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200536 # if we know that we are a child template, there is no need to
537 # check if we are one
538 if self.has_known_extends:
539 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200540 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200541 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200542 self.indent()
543 level += 1
544 self.writeline('for event in context.blocks[%r][-1](context):' % node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200545 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200546 if frame.buffer is None:
547 self.writeline('yield event')
548 else:
549 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200550 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200551
552 def visit_Extends(self, node, frame):
553 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200554 if not frame.toplevel:
555 raise TemplateAssertionError('cannot use extend from a non '
556 'top-level scope', node.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200557 self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200558
Armin Ronacher7fb38972008-04-11 13:54:28 +0200559 # if the number of extends statements in general is zero so
560 # far, we don't have to add a check if something extended
561 # the template before this one.
562 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200563
Armin Ronacher7fb38972008-04-11 13:54:28 +0200564 # if we have a known extends we just add a template runtime
565 # error into the generated code. We could catch that at compile
566 # time too, but i welcome it not to confuse users by throwing the
567 # same error at different times just "because we can".
568 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200569 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200570 self.indent()
571 self.writeline('raise TemplateRuntimeError(%r)' %
572 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200573
Armin Ronacher7fb38972008-04-11 13:54:28 +0200574 # if we have a known extends already we don't need that code here
575 # as we know that the template execution will end here.
576 if self.has_known_extends:
577 raise CompilerExit()
578 self.outdent()
579
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200580 self.writeline('parent_template = environment.get_template(', node, 1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200581 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200582 self.write(', %r)' % self.name)
583 self.writeline('for name, parent_block in parent_template.'
584 'blocks.iteritems():')
585 self.indent()
586 self.writeline('context.blocks.setdefault(name, []).'
587 'insert(0, parent_block)')
588 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200589
590 # if this extends statement was in the root level we can take
591 # advantage of that information and simplify the generated code
592 # in the top level from this point onwards
593 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200594
Armin Ronacher7fb38972008-04-11 13:54:28 +0200595 # and now we have one more
596 self.extends_so_far += 1
597
Armin Ronacherf059ec12008-04-11 22:21:00 +0200598 def visit_Include(self, node, frame):
599 """Handles includes."""
600 # simpled include is include into a variable. This kind of
601 # include works the same on every level, so we handle it first.
602 if node.target is not None:
603 self.writeline('l_%s = ' % node.target, node)
604 if frame.toplevel:
605 self.write('context[%r] = ' % node.target)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200606 self.write('environment.get_template(')
Armin Ronacherf059ec12008-04-11 22:21:00 +0200607 self.visit(node.template, frame)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200608 self.write(', %r).include(context)' % self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200609 return
610
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200611 self.writeline('included_template = environment.get_template(', node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200612 self.visit(node.template, frame)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200613 self.write(', %r)' % self.name)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200614 if frame.toplevel:
615 self.writeline('included_context = included_template.new_context('
616 'context.get_root())')
617 self.writeline('for event in included_template.root_render_func('
618 'included_context):')
619 else:
620 self.writeline('for event in included_template.root_render_func('
621 'included_template.new_context(context.get_root())):')
Armin Ronacherf059ec12008-04-11 22:21:00 +0200622 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200623 if frame.buffer is None:
624 self.writeline('yield event')
625 else:
626 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200627 self.outdent()
628
629 # if we have a toplevel include the exported variables are copied
630 # into the current context without exporting them. context.udpate
631 # does *not* mark the variables as exported
632 if frame.toplevel:
633 self.writeline('context.update(included_context.get_exported())')
634
Armin Ronachere791c2a2008-04-07 18:39:54 +0200635 def visit_For(self, node, frame):
636 loop_frame = frame.inner()
637 loop_frame.inspect(node.iter_child_nodes())
Armin Ronachere791c2a2008-04-07 18:39:54 +0200638 extended_loop = bool(node.else_) or \
639 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200640 if extended_loop:
641 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200642
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200643 aliases = self.collect_shadowed(loop_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200644 self.pull_locals(loop_frame, indent=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200645 if node.else_:
646 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200647
648 self.newline(node)
649 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200650 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200651 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200652
653 # the expression pointing to the parent loop. We make the
654 # undefined a bit more debug friendly at the same time.
655 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200656 or "environment.undefined(%r)" % "'loop' is undefined. " \
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200657 'the filter section of a loop as well as the ' \
658 'else block doesn\'t have access to the special ' \
659 "'loop' variable of the current loop. Because " \
660 'there is no parent loop it\'s undefined.'
661
662 # if we have an extened loop and a node test, we filter in the
663 # "outer frame".
664 if extended_loop and node.test is not None:
665 self.write('(')
666 self.visit(node.target, loop_frame)
667 self.write(' for ')
668 self.visit(node.target, loop_frame)
669 self.write(' in ')
670 self.visit(node.iter, loop_frame)
671 self.write(' if (')
672 test_frame = loop_frame.copy()
673 test_frame.name_overrides['loop'] = parent_loop
674 self.visit(node.test, test_frame)
675 self.write('))')
676
677 else:
678 self.visit(node.iter, loop_frame)
679
Armin Ronachere791c2a2008-04-07 18:39:54 +0200680 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200681
682 # tests in not extended loops become a continue
683 if not extended_loop and node.test is not None:
684 self.indent()
685 self.writeline('if ')
686 self.visit(node.test)
687 self.write(':')
688 self.indent()
689 self.writeline('continue')
690 self.outdent(2)
691
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200692 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200693
694 if node.else_:
695 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200696 self.indent()
697 self.writeline('l_loop = ' + parent_loop)
698 self.outdent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200699 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200700
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200701 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200702 for name, alias in aliases.iteritems():
Armin Ronacher8efc5222008-04-08 14:47:40 +0200703 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200704
705 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200706 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200707 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200708 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200709 self.write(':')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200710 self.blockvisit(node.body, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200711 if node.else_:
712 self.writeline('else:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200713 self.blockvisit(node.else_, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200714
Armin Ronacher8efc5222008-04-08 14:47:40 +0200715 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200716 macro_frame = self.function_scoping(node, frame)
717 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200718 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200719 macro_frame.buffer = buf = self.temporary_identifier()
720 self.indent()
721 self.pull_locals(macro_frame, indent=False)
722 self.writeline('%s = []' % buf)
723 self.blockvisit(node.body, macro_frame, indent=False)
Armin Ronacher5236d8c2008-04-17 11:23:16 +0200724 self.writeline("return Markup(u''.join(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200725 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200726 self.newline()
727 if frame.toplevel:
728 self.write('context[%r] = ' % node.name)
729 arg_tuple = ', '.join(repr(x.name) for x in node.args)
730 if len(node.args) == 1:
731 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200732 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
733 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200734 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200735 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200736 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200737 self.write('), %s, %s, %s)' % (
738 macro_frame.accesses_kwargs and '1' or '0',
739 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200740 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200741 ))
742
743 def visit_CallBlock(self, node, frame):
744 call_frame = self.function_scoping(node, frame)
745 args = call_frame.arguments
746 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200747 call_frame.buffer = buf = self.temporary_identifier()
748 self.indent()
749 self.pull_locals(call_frame, indent=False)
750 self.writeline('%s = []' % buf)
751 self.blockvisit(node.body, call_frame, indent=False)
Armin Ronacher5236d8c2008-04-17 11:23:16 +0200752 self.writeline("return Markup(u''.join(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200753 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200754 arg_tuple = ', '.join(repr(x.name) for x in node.args)
755 if len(node.args) == 1:
756 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200757 self.writeline('caller = Macro(environment, call, None, (%s), (' %
758 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200759 for arg in node.defaults:
760 self.visit(arg)
761 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200762 self.write('), %s, %s, 0)' % (
763 call_frame.accesses_kwargs and '1' or '0',
764 call_frame.accesses_varargs and '1' or '0'
765 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200766 if frame.buffer is None:
767 self.writeline('yield ', node)
768 else:
769 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher71082072008-04-12 14:19:36 +0200770 self.visit_Call(node.call, call_frame, extra_kwargs='caller=caller')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200771 if frame.buffer is not None:
772 self.write(')')
773
774 def visit_FilterBlock(self, node, frame):
775 filter_frame = frame.inner()
776 filter_frame.inspect(node.iter_child_nodes())
777
778 aliases = self.collect_shadowed(filter_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200779 self.pull_locals(filter_frame, indent=False)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200780 filter_frame.buffer = buf = self.temporary_identifier()
781
782 self.writeline('%s = []' % buf, node)
783 for child in node.body:
784 self.visit(child, filter_frame)
785
786 if frame.buffer is None:
787 self.writeline('yield ', node)
788 else:
789 self.writeline('%s.append(' % frame.buffer, node)
790 self.visit_Filter(node.filter, filter_frame, "u''.join(%s)" % buf)
791 if frame.buffer is not None:
792 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200793
Armin Ronachere791c2a2008-04-07 18:39:54 +0200794 def visit_ExprStmt(self, node, frame):
795 self.newline(node)
796 self.visit(node, frame)
797
798 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200799 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +0200800 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200801 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200802
Armin Ronacher75cfb862008-04-11 13:47:22 +0200803 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200804 if self.environment.finalize is unicode:
805 finalizer = 'unicode'
Armin Ronacherf059ec12008-04-11 22:21:00 +0200806 have_finalizer = False
Armin Ronacher8edbe492008-04-10 20:43:43 +0200807 else:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200808 finalizer = 'environment.finalize'
809 have_finalizer = True
Armin Ronacher8edbe492008-04-10 20:43:43 +0200810
Armin Ronacher7fb38972008-04-11 13:54:28 +0200811 # if we are in the toplevel scope and there was already an extends
812 # statement we have to add a check that disables our yield(s) here
813 # so that they don't appear in the output.
814 outdent_later = False
815 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200816 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200817 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200818 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +0200819
Armin Ronachere791c2a2008-04-07 18:39:54 +0200820 # try to evaluate as many chunks as possible into a static
821 # string at compile time.
822 body = []
823 for child in node.nodes:
824 try:
825 const = unicode(child.as_const())
826 except:
827 body.append(child)
828 continue
829 if body and isinstance(body[-1], list):
830 body[-1].append(const)
831 else:
832 body.append([const])
833
834 # if we have less than 3 nodes we just yield them
835 if len(body) < 3:
836 for item in body:
837 if isinstance(item, list):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200838 val = repr(u''.join(item))
839 if frame.buffer is None:
840 self.writeline('yield ' + val)
841 else:
842 self.writeline('%s.append(%s)' % (frame.buffer, val))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200843 else:
844 self.newline(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200845 if frame.buffer is None:
846 self.write('yield ')
847 else:
848 self.write('%s.append(' % frame.buffer)
849 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200850 self.visit(item, frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200851 self.write(')' * (1 + (frame.buffer is not None)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200852
853 # otherwise we create a format string as this is faster in that case
854 else:
855 format = []
856 arguments = []
857 for item in body:
858 if isinstance(item, list):
859 format.append(u''.join(item).replace('%', '%%'))
860 else:
861 format.append('%s')
862 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200863 if frame.buffer is None:
864 self.writeline('yield ')
865 else:
866 self.writeline('%s.append(' % frame.buffer)
867 self.write(repr(u''.join(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200868 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200869 self.indent()
870 for argument in arguments:
871 self.newline(argument)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200872 if have_finalizer:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200873 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200874 self.visit(argument, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200875 if have_finalizer:
Armin Ronacher8edbe492008-04-10 20:43:43 +0200876 self.write(')')
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200877 self.write(',')
878 self.outdent()
879 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200880 if frame.buffer is not None:
881 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200882
Armin Ronacher7fb38972008-04-11 13:54:28 +0200883 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200884 self.outdent()
885
Armin Ronacher8efc5222008-04-08 14:47:40 +0200886 def visit_Assign(self, node, frame):
887 self.newline(node)
888 # toplevel assignments however go into the local namespace and
889 # the current template's context. We create a copy of the frame
890 # here and add a set so that the Name visitor can add the assigned
891 # names here.
892 if frame.toplevel:
893 assignment_frame = frame.copy()
894 assignment_frame.assigned_names = set()
895 else:
896 assignment_frame = frame
897 self.visit(node.target, assignment_frame)
898 self.write(' = ')
899 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200900
901 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200902 if frame.toplevel:
903 for name in assignment_frame.assigned_names:
904 self.writeline('context[%r] = l_%s' % (name, name))
905
Armin Ronachere791c2a2008-04-07 18:39:54 +0200906 def visit_Name(self, node, frame):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200907 if node.ctx == 'store':
908 if frame.toplevel:
909 frame.assigned_names.add(node.name)
910 frame.name_overrides.pop(node.name, None)
911 elif node.ctx == 'load':
912 if node.name in frame.name_overrides:
913 self.write(frame.name_overrides[node.name])
914 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200915 self.write('l_' + node.name)
916
917 def visit_Const(self, node, frame):
918 val = node.value
919 if isinstance(val, float):
920 # XXX: add checks for infinity and nan
921 self.write(str(val))
922 else:
923 self.write(repr(val))
924
Armin Ronacher8efc5222008-04-08 14:47:40 +0200925 def visit_Tuple(self, node, frame):
926 self.write('(')
927 idx = -1
928 for idx, item in enumerate(node.items):
929 if idx:
930 self.write(', ')
931 self.visit(item, frame)
932 self.write(idx == 0 and ',)' or ')')
933
Armin Ronacher8edbe492008-04-10 20:43:43 +0200934 def visit_List(self, node, frame):
935 self.write('[')
936 for idx, item in enumerate(node.items):
937 if idx:
938 self.write(', ')
939 self.visit(item, frame)
940 self.write(']')
941
942 def visit_Dict(self, node, frame):
943 self.write('{')
944 for idx, item in enumerate(node.items):
945 if idx:
946 self.write(', ')
947 self.visit(item.key, frame)
948 self.write(': ')
949 self.visit(item.value, frame)
950 self.write('}')
951
Armin Ronachere791c2a2008-04-07 18:39:54 +0200952 def binop(operator):
953 def visitor(self, node, frame):
954 self.write('(')
955 self.visit(node.left, frame)
956 self.write(' %s ' % operator)
957 self.visit(node.right, frame)
958 self.write(')')
959 return visitor
960
961 def uaop(operator):
962 def visitor(self, node, frame):
963 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +0200964 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200965 self.write(')')
966 return visitor
967
968 visit_Add = binop('+')
969 visit_Sub = binop('-')
970 visit_Mul = binop('*')
971 visit_Div = binop('/')
972 visit_FloorDiv = binop('//')
973 visit_Pow = binop('**')
974 visit_Mod = binop('%')
975 visit_And = binop('and')
976 visit_Or = binop('or')
977 visit_Pos = uaop('+')
978 visit_Neg = uaop('-')
979 visit_Not = uaop('not ')
980 del binop, uaop
981
982 def visit_Compare(self, node, frame):
983 self.visit(node.expr, frame)
984 for op in node.ops:
985 self.visit(op, frame)
986
987 def visit_Operand(self, node, frame):
988 self.write(' %s ' % operators[node.op])
989 self.visit(node.expr, frame)
990
991 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200992 if isinstance(node.arg, nodes.Slice):
993 self.visit(node.node, frame)
994 self.write('[')
995 self.visit(node.arg, frame)
996 self.write(']')
997 return
998 try:
999 const = node.arg.as_const()
1000 have_const = True
1001 except nodes.Impossible:
1002 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001003 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001004 self.visit(node.node, frame)
1005 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001006 if have_const:
1007 self.write(repr(const))
1008 else:
1009 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001010 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001011
1012 def visit_Slice(self, node, frame):
1013 if node.start is not None:
1014 self.visit(node.start, frame)
1015 self.write(':')
1016 if node.stop is not None:
1017 self.visit(node.stop, frame)
1018 if node.step is not None:
1019 self.write(':')
1020 self.visit(node.step, frame)
1021
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001022 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001023 self.write('f_%s(' % node.name)
Christoph Hack80909862008-04-14 01:35:10 +02001024 func = self.environment.filters.get(node.name)
1025 if getattr(func, 'contextfilter', False):
1026 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001027 elif getattr(func, 'environmentfilter', False):
1028 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001029 if isinstance(node.node, nodes.Filter):
1030 self.visit_Filter(node.node, frame, initial)
1031 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001032 self.write(initial)
1033 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001034 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001035 self.signature(node, frame)
1036 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001037
1038 def visit_Test(self, node, frame):
Armin Ronacherf059ec12008-04-11 22:21:00 +02001039 self.write('t_%s(' % node.name)
1040 func = self.environment.tests.get(node.name)
1041 if getattr(func, 'contexttest', False):
1042 self.write('context, ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001043 self.visit(node.node, frame)
1044 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001045 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001046
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001047 def visit_CondExpr(self, node, frame):
1048 if not have_condexpr:
1049 self.write('((')
1050 self.visit(node.test, frame)
1051 self.write(') and (')
1052 self.visit(node.expr1, frame)
1053 self.write(',) or (')
1054 self.visit(node.expr2, frame)
1055 self.write(',))[0]')
1056 else:
1057 self.write('(')
1058 self.visit(node.expr1, frame)
1059 self.write(' if ')
1060 self.visit(node.test, frame)
1061 self.write(' else ')
1062 self.visit(node.expr2, frame)
1063 self.write(')')
1064
Armin Ronacher71082072008-04-12 14:19:36 +02001065 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001066 if self.environment.sandboxed:
1067 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001068 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001069 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001070 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001071 self.write(')')
1072
1073 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001074 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001075 self.visit(node.value, frame)