blob: 958b2c3e6e2243bb826fc647ef222e376e6a1eb2 [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):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200213 self.identifiers.declared_locally.add(node.name)
214
Armin Ronacher0611e492008-04-25 23:44:14 +0200215 def visit_Import(self, node):
Armin Ronacherf059ec12008-04-11 22:21:00 +0200216 self.generic_visit(node)
Armin Ronacher0611e492008-04-25 23:44:14 +0200217 self.identifiers.declared_locally.add(node.target)
218
219 def visit_FromImport(self, node):
220 self.generic_visit(node)
221 self.identifiers.declared_locally.update(node.names)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200222
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200223 def visit_Assign(self, node):
224 """Visit assignments in the correct order."""
225 self.visit(node.node)
226 self.visit(node.target)
227
Armin Ronachere791c2a2008-04-07 18:39:54 +0200228 # stop traversing at instructions that have their own scope.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200229 visit_Block = visit_CallBlock = visit_FilterBlock = \
Armin Ronachere791c2a2008-04-07 18:39:54 +0200230 visit_For = lambda s, n: None
231
232
Armin Ronacher75cfb862008-04-11 13:47:22 +0200233class CompilerExit(Exception):
234 """Raised if the compiler encountered a situation where it just
235 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200236 raises such an exception is not further processed.
237 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200238
239
Armin Ronachere791c2a2008-04-07 18:39:54 +0200240class CodeGenerator(NodeVisitor):
241
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200242 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200243 if stream is None:
244 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200245 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200246 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200247 self.filename = filename
248 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200249
250 # a registry for all blocks. Because blocks are moved out
251 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200252 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200253
254 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200255 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200256
257 # some templates have a rootlevel extends. In this case we
258 # can safely assume that we're a child template and do some
259 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200260 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200261
Armin Ronacherba3757b2008-04-16 19:43:16 +0200262 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200263 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200264
265 # the debug information
266 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200267 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200268
Armin Ronacherfed44b52008-04-13 19:42:53 +0200269 # the number of new lines before the next write()
270 self._new_lines = 0
271
272 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200273 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200274
275 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200276 self._first_write = True
277
Armin Ronacherfed44b52008-04-13 19:42:53 +0200278 # used by the `temporary_identifier` method to get new
279 # unique, temporary identifier
280 self._last_identifier = 0
281
282 # the current indentation
283 self._indentation = 0
284
Armin Ronachere791c2a2008-04-07 18:39:54 +0200285 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200286 """Get a new unique identifier."""
287 self._last_identifier += 1
288 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200289
290 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200291 """Indent by one."""
292 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200293
Armin Ronacher8efc5222008-04-08 14:47:40 +0200294 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200295 """Outdent by step."""
296 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200297
Armin Ronacher625215e2008-04-13 16:31:08 +0200298 def blockvisit(self, nodes, frame, indent=True, force_generator=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200299 """Visit a list of nodes as block in a frame. Per default the
300 code is indented, but this can be disabled by setting the indent
301 parameter to False. If the current frame is no buffer a dummy
302 ``if 0: yield None`` is written automatically unless the
303 force_generator parameter is set to False.
304 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200305 if indent:
306 self.indent()
307 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200308 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200309 try:
310 for node in nodes:
311 self.visit(node, frame)
312 except CompilerExit:
313 pass
Armin Ronacher625215e2008-04-13 16:31:08 +0200314 if indent:
315 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200316
317 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200318 """Write a string into the output stream."""
319 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200320 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200321 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200322 self.code_lineno += self._new_lines
323 if self._write_debug_info is not None:
324 self.debug_info.append((self._write_debug_info,
325 self.code_lineno))
326 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200327 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200328 self.stream.write(' ' * self._indentation)
329 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200330 self.stream.write(x)
331
332 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200333 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200334 self.newline(node, extra)
335 self.write(x)
336
337 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200338 """Add one or more newlines before the next write."""
339 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200340 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200341 self._write_debug_info = node.lineno
342 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200343
Armin Ronacher71082072008-04-12 14:19:36 +0200344 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200345 """Writes a function call to the stream for the current node.
346 Per default it will write a leading comma but this can be
347 disabled by setting have_comma to False. If extra_kwargs is
348 given it must be a string that represents a single keyword
349 argument call that is inserted at the end of the regular
350 keyword argument calls.
351 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200352 have_comma = have_comma and [True] or []
353 def touch_comma():
354 if have_comma:
355 self.write(', ')
356 else:
357 have_comma.append(True)
358
359 for arg in node.args:
360 touch_comma()
361 self.visit(arg, frame)
362 for kwarg in node.kwargs:
363 touch_comma()
364 self.visit(kwarg, frame)
Armin Ronacher71082072008-04-12 14:19:36 +0200365 if extra_kwargs is not None:
366 touch_comma()
367 self.write(extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200368 if node.dyn_args:
369 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200370 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200371 self.visit(node.dyn_args, frame)
372 if node.dyn_kwargs:
373 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200374 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200375 self.visit(node.dyn_kwargs, frame)
376
Armin Ronacher625215e2008-04-13 16:31:08 +0200377 def pull_locals(self, frame, indent=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200378 """Pull all the references identifiers into the local scope.
379 This affects regular names, filters and tests. If indent is
380 set to False, no automatic indentation will take place.
381 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200382 if indent:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200383 self.indent()
384 for name in frame.identifiers.undeclared:
385 self.writeline('l_%s = context[%r]' % (name, name))
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200386 for name in frame.identifiers.filters:
387 self.writeline('f_%s = environment.filters[%r]' % (name, name))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200388 for name in frame.identifiers.tests:
389 self.writeline('t_%s = environment.tests[%r]' % (name, name))
Armin Ronacher625215e2008-04-13 16:31:08 +0200390 if indent:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200391 self.outdent()
392
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200393 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200394 """This function returns all the shadowed variables in a dict
395 in the form name: alias and will write the required assignments
396 into the current scope. No indentation takes place.
397 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200398 # make sure we "backup" overridden, local identifiers
399 # TODO: we should probably optimize this and check if the
400 # identifier is in use afterwards.
401 aliases = {}
402 for name in frame.identifiers.find_shadowed():
403 aliases[name] = ident = self.temporary_identifier()
404 self.writeline('%s = l_%s' % (ident, name))
405 return aliases
406
Armin Ronacher71082072008-04-12 14:19:36 +0200407 def function_scoping(self, node, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200408 """In Jinja a few statements require the help of anonymous
409 functions. Those are currently macros and call blocks and in
410 the future also recursive loops. As there is currently
411 technical limitation that doesn't allow reading and writing a
412 variable in a scope where the initial value is coming from an
413 outer scope, this function tries to fall back with a common
414 error message. Additionally the frame passed is modified so
415 that the argumetns are collected and callers are looked up.
416
417 This will return the modified frame.
418 """
Armin Ronacher71082072008-04-12 14:19:36 +0200419 func_frame = frame.inner()
420 func_frame.inspect(node.iter_child_nodes(), hard_scope=True)
421
422 # variables that are undeclared (accessed before declaration) and
423 # declared locally *and* part of an outside scope raise a template
424 # assertion error. Reason: we can't generate reasonable code from
425 # it without aliasing all the variables. XXX: alias them ^^
426 overriden_closure_vars = (
427 func_frame.identifiers.undeclared &
428 func_frame.identifiers.declared &
429 (func_frame.identifiers.declared_locally |
430 func_frame.identifiers.declared_parameter)
431 )
432 if overriden_closure_vars:
433 vars = ', '.join(sorted(overriden_closure_vars))
434 raise TemplateAssertionError('It\'s not possible to set and '
435 'access variables derived from '
436 'an outer scope! (affects: %s' %
Armin Ronacher68f77672008-04-17 11:50:39 +0200437 vars, node.lineno, self.name)
Armin Ronacher71082072008-04-12 14:19:36 +0200438
439 # remove variables from a closure from the frame's undeclared
440 # identifiers.
441 func_frame.identifiers.undeclared -= (
442 func_frame.identifiers.undeclared &
443 func_frame.identifiers.declared
444 )
445
Armin Ronacher963f97d2008-04-25 11:44:59 +0200446 func_frame.accesses_kwargs = False
447 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200448 func_frame.accesses_caller = False
449 func_frame.arguments = args = ['l_' + x.name for x in node.args]
450
Armin Ronacher963f97d2008-04-25 11:44:59 +0200451 if 'kwargs' in func_frame.identifiers.undeclared:
452 func_frame.accesses_kwargs = True
453 func_frame.identifiers.add_special('kwargs')
454 args.append('l_kwargs')
455 if 'varargs' in func_frame.identifiers.undeclared:
456 func_frame.accesses_varargs = True
457 func_frame.identifiers.add_special('varargs')
458 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200459 if 'caller' in func_frame.identifiers.undeclared:
460 func_frame.accesses_caller = True
461 func_frame.identifiers.add_special('caller')
462 args.append('l_caller')
463 return func_frame
464
Armin Ronachere791c2a2008-04-07 18:39:54 +0200465 # -- Visitors
466
467 def visit_Template(self, node, frame=None):
468 assert frame is None, 'no root frame allowed'
469 self.writeline('from jinja2.runtime import *')
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200470 self.writeline('name = %r' % self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200471
Armin Ronacher75cfb862008-04-11 13:47:22 +0200472 # do we have an extends tag at all? If not, we can save some
473 # overhead by just not processing any inheritance code.
474 have_extends = node.find(nodes.Extends) is not None
475
Armin Ronacher8edbe492008-04-10 20:43:43 +0200476 # find all blocks
477 for block in node.find_all(nodes.Block):
478 if block.name in self.blocks:
479 raise TemplateAssertionError('block %r defined twice' %
480 block.name, block.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200481 self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200482 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200483
Armin Ronacher8efc5222008-04-08 14:47:40 +0200484 # generate the root render function.
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200485 self.writeline('def root(context, environment=environment'
486 '):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200487 if have_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200488 self.indent()
489 self.writeline('parent_template = None')
490 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200491
492 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200493 frame = Frame()
494 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200495 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200496 self.indent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200497 self.pull_locals(frame, indent=False)
Armin Ronacher625215e2008-04-13 16:31:08 +0200498 self.blockvisit(node.body, frame, indent=False)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200499 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200500
Armin Ronacher8efc5222008-04-08 14:47:40 +0200501 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200502 if have_extends:
503 if not self.has_known_extends:
504 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200505 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200506 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200507 self.writeline('for event in parent_template.'
508 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200509 self.indent()
510 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200511 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200512
513 # at this point we now have the blocks collected and can visit them too.
514 for name, block in self.blocks.iteritems():
515 block_frame = Frame()
516 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200517 block_frame.block = name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200518 block_frame.identifiers.add_special('super')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200519 block_frame.name_overrides['super'] = 'context.super(%r, ' \
520 'block_%s)' % (name, name)
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200521 self.writeline('def block_%s(context, environment=environment):'
522 % name, block, 1)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200523 self.pull_locals(block_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200524 self.blockvisit(block.body, block_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200525
Armin Ronacher75cfb862008-04-11 13:47:22 +0200526 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200527 for x in self.blocks),
528 extra=1)
529
530 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200531 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
532 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200533
Armin Ronachere791c2a2008-04-07 18:39:54 +0200534 def visit_Block(self, node, frame):
535 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200536 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200537 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200538 # if we know that we are a child template, there is no need to
539 # check if we are one
540 if self.has_known_extends:
541 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200542 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200543 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200544 self.indent()
545 level += 1
546 self.writeline('for event in context.blocks[%r][-1](context):' % node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200547 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200548 if frame.buffer is None:
549 self.writeline('yield event')
550 else:
551 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200552 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200553
554 def visit_Extends(self, node, frame):
555 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200556 if not frame.toplevel:
557 raise TemplateAssertionError('cannot use extend from a non '
558 'top-level scope', node.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200559 self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200560
Armin Ronacher7fb38972008-04-11 13:54:28 +0200561 # if the number of extends statements in general is zero so
562 # far, we don't have to add a check if something extended
563 # the template before this one.
564 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200565
Armin Ronacher7fb38972008-04-11 13:54:28 +0200566 # if we have a known extends we just add a template runtime
567 # error into the generated code. We could catch that at compile
568 # time too, but i welcome it not to confuse users by throwing the
569 # same error at different times just "because we can".
570 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200571 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200572 self.indent()
573 self.writeline('raise TemplateRuntimeError(%r)' %
574 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200575
Armin Ronacher7fb38972008-04-11 13:54:28 +0200576 # if we have a known extends already we don't need that code here
577 # as we know that the template execution will end here.
578 if self.has_known_extends:
579 raise CompilerExit()
580 self.outdent()
581
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200582 self.writeline('parent_template = environment.get_template(', node, 1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200583 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200584 self.write(', %r)' % self.name)
585 self.writeline('for name, parent_block in parent_template.'
586 'blocks.iteritems():')
587 self.indent()
588 self.writeline('context.blocks.setdefault(name, []).'
589 'insert(0, parent_block)')
590 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200591
592 # if this extends statement was in the root level we can take
593 # advantage of that information and simplify the generated code
594 # in the top level from this point onwards
595 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200596
Armin Ronacher7fb38972008-04-11 13:54:28 +0200597 # and now we have one more
598 self.extends_so_far += 1
599
Armin Ronacherf059ec12008-04-11 22:21:00 +0200600 def visit_Include(self, node, frame):
601 """Handles includes."""
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200602 self.writeline('included_template = environment.get_template(', node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200603 self.visit(node.template, frame)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200604 self.write(', %r)' % self.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200605 self.writeline('for event in included_template.root_render_func('
606 'included_template.new_context(context.get_root())):')
Armin Ronacherf059ec12008-04-11 22:21:00 +0200607 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200608 if frame.buffer is None:
609 self.writeline('yield event')
610 else:
611 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200612 self.outdent()
613
Armin Ronacher0611e492008-04-25 23:44:14 +0200614 def visit_Import(self, node, frame):
615 """Visit regular imports."""
616 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200617 if frame.toplevel:
Armin Ronacher0611e492008-04-25 23:44:14 +0200618 self.write('context[%r] = ' % node.target)
619 self.write('environment.get_template(')
620 self.visit(node.template, frame)
621 self.write(', %r).include(context)' % self.name)
622
623 def visit_FromImport(self, node, frame):
624 """Visit named imports."""
625 self.newline(node)
626 self.write('included_template = environment.get_template(')
627 self.visit(node.template, frame)
628 self.write(', %r).include(context)' % self.name)
629 for name in node.names:
630 self.writeline('l_%s = getattr(included_template, '
631 '%r, missing)' % (name, name))
632 self.writeline('if l_%s is missing:' % name)
633 self.indent()
634 self.writeline('l_%s = environment.undefined(%r %% '
635 'included_template.name)' %
636 (name, 'the template %r does not export '
637 'the requested name ' + repr(name)))
638 self.outdent()
639 if frame.toplevel:
640 self.writeline('context[%r] = l_%s' % (name, name))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200641
Armin Ronachere791c2a2008-04-07 18:39:54 +0200642 def visit_For(self, node, frame):
643 loop_frame = frame.inner()
644 loop_frame.inspect(node.iter_child_nodes())
Armin Ronachere791c2a2008-04-07 18:39:54 +0200645 extended_loop = bool(node.else_) or \
646 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200647 if extended_loop:
648 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200649
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200650 aliases = self.collect_shadowed(loop_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200651 self.pull_locals(loop_frame, indent=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200652 if node.else_:
653 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200654
655 self.newline(node)
656 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200657 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200658 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200659
660 # the expression pointing to the parent loop. We make the
661 # undefined a bit more debug friendly at the same time.
662 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200663 or "environment.undefined(%r)" % "'loop' is undefined. " \
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200664 'the filter section of a loop as well as the ' \
665 'else block doesn\'t have access to the special ' \
666 "'loop' variable of the current loop. Because " \
667 'there is no parent loop it\'s undefined.'
668
669 # if we have an extened loop and a node test, we filter in the
670 # "outer frame".
671 if extended_loop and node.test is not None:
672 self.write('(')
673 self.visit(node.target, loop_frame)
674 self.write(' for ')
675 self.visit(node.target, loop_frame)
676 self.write(' in ')
677 self.visit(node.iter, loop_frame)
678 self.write(' if (')
679 test_frame = loop_frame.copy()
680 test_frame.name_overrides['loop'] = parent_loop
681 self.visit(node.test, test_frame)
682 self.write('))')
683
684 else:
685 self.visit(node.iter, loop_frame)
686
Armin Ronachere791c2a2008-04-07 18:39:54 +0200687 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200688
689 # tests in not extended loops become a continue
690 if not extended_loop and node.test is not None:
691 self.indent()
692 self.writeline('if ')
693 self.visit(node.test)
694 self.write(':')
695 self.indent()
696 self.writeline('continue')
697 self.outdent(2)
698
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200699 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200700
701 if node.else_:
702 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200703 self.indent()
704 self.writeline('l_loop = ' + parent_loop)
705 self.outdent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200706 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200707
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200708 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200709 for name, alias in aliases.iteritems():
Armin Ronacher8efc5222008-04-08 14:47:40 +0200710 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200711
712 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200713 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200714 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200715 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200716 self.write(':')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200717 self.blockvisit(node.body, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200718 if node.else_:
719 self.writeline('else:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200720 self.blockvisit(node.else_, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200721
Armin Ronacher8efc5222008-04-08 14:47:40 +0200722 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200723 macro_frame = self.function_scoping(node, frame)
724 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200725 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200726 macro_frame.buffer = buf = self.temporary_identifier()
727 self.indent()
728 self.pull_locals(macro_frame, indent=False)
729 self.writeline('%s = []' % buf)
730 self.blockvisit(node.body, macro_frame, indent=False)
Armin Ronacher5236d8c2008-04-17 11:23:16 +0200731 self.writeline("return Markup(u''.join(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200732 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200733 self.newline()
734 if frame.toplevel:
735 self.write('context[%r] = ' % node.name)
736 arg_tuple = ', '.join(repr(x.name) for x in node.args)
737 if len(node.args) == 1:
738 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200739 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
740 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200741 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200742 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200743 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200744 self.write('), %s, %s, %s)' % (
745 macro_frame.accesses_kwargs and '1' or '0',
746 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200747 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200748 ))
749
750 def visit_CallBlock(self, node, frame):
751 call_frame = self.function_scoping(node, frame)
752 args = call_frame.arguments
753 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200754 call_frame.buffer = buf = self.temporary_identifier()
755 self.indent()
756 self.pull_locals(call_frame, indent=False)
757 self.writeline('%s = []' % buf)
758 self.blockvisit(node.body, call_frame, indent=False)
Armin Ronacher5236d8c2008-04-17 11:23:16 +0200759 self.writeline("return Markup(u''.join(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200760 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200761 arg_tuple = ', '.join(repr(x.name) for x in node.args)
762 if len(node.args) == 1:
763 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200764 self.writeline('caller = Macro(environment, call, None, (%s), (' %
765 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200766 for arg in node.defaults:
767 self.visit(arg)
768 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200769 self.write('), %s, %s, 0)' % (
770 call_frame.accesses_kwargs and '1' or '0',
771 call_frame.accesses_varargs and '1' or '0'
772 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200773 if frame.buffer is None:
774 self.writeline('yield ', node)
775 else:
776 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher71082072008-04-12 14:19:36 +0200777 self.visit_Call(node.call, call_frame, extra_kwargs='caller=caller')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200778 if frame.buffer is not None:
779 self.write(')')
780
781 def visit_FilterBlock(self, node, frame):
782 filter_frame = frame.inner()
783 filter_frame.inspect(node.iter_child_nodes())
784
785 aliases = self.collect_shadowed(filter_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200786 self.pull_locals(filter_frame, indent=False)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200787 filter_frame.buffer = buf = self.temporary_identifier()
788
789 self.writeline('%s = []' % buf, node)
790 for child in node.body:
791 self.visit(child, filter_frame)
792
793 if frame.buffer is None:
794 self.writeline('yield ', node)
795 else:
796 self.writeline('%s.append(' % frame.buffer, node)
797 self.visit_Filter(node.filter, filter_frame, "u''.join(%s)" % buf)
798 if frame.buffer is not None:
799 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200800
Armin Ronachere791c2a2008-04-07 18:39:54 +0200801 def visit_ExprStmt(self, node, frame):
802 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +0200803 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200804
805 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200806 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +0200807 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200808 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200809
Armin Ronacher75cfb862008-04-11 13:47:22 +0200810 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200811 if self.environment.finalize is unicode:
812 finalizer = 'unicode'
Armin Ronacherf059ec12008-04-11 22:21:00 +0200813 have_finalizer = False
Armin Ronacher8edbe492008-04-10 20:43:43 +0200814 else:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200815 finalizer = 'environment.finalize'
816 have_finalizer = True
Armin Ronacher8edbe492008-04-10 20:43:43 +0200817
Armin Ronacher7fb38972008-04-11 13:54:28 +0200818 # if we are in the toplevel scope and there was already an extends
819 # statement we have to add a check that disables our yield(s) here
820 # so that they don't appear in the output.
821 outdent_later = False
822 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200823 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200824 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200825 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +0200826
Armin Ronachere791c2a2008-04-07 18:39:54 +0200827 # try to evaluate as many chunks as possible into a static
828 # string at compile time.
829 body = []
830 for child in node.nodes:
831 try:
832 const = unicode(child.as_const())
833 except:
834 body.append(child)
835 continue
836 if body and isinstance(body[-1], list):
837 body[-1].append(const)
838 else:
839 body.append([const])
840
841 # if we have less than 3 nodes we just yield them
842 if len(body) < 3:
843 for item in body:
844 if isinstance(item, list):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200845 val = repr(u''.join(item))
846 if frame.buffer is None:
847 self.writeline('yield ' + val)
848 else:
849 self.writeline('%s.append(%s)' % (frame.buffer, val))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200850 else:
851 self.newline(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200852 if frame.buffer is None:
853 self.write('yield ')
854 else:
855 self.write('%s.append(' % frame.buffer)
856 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200857 self.visit(item, frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200858 self.write(')' * (1 + (frame.buffer is not None)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200859
860 # otherwise we create a format string as this is faster in that case
861 else:
862 format = []
863 arguments = []
864 for item in body:
865 if isinstance(item, list):
866 format.append(u''.join(item).replace('%', '%%'))
867 else:
868 format.append('%s')
869 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200870 if frame.buffer is None:
871 self.writeline('yield ')
872 else:
873 self.writeline('%s.append(' % frame.buffer)
874 self.write(repr(u''.join(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200875 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200876 self.indent()
877 for argument in arguments:
878 self.newline(argument)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200879 if have_finalizer:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200880 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200881 self.visit(argument, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200882 if have_finalizer:
Armin Ronacher8edbe492008-04-10 20:43:43 +0200883 self.write(')')
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200884 self.write(',')
885 self.outdent()
886 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200887 if frame.buffer is not None:
888 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200889
Armin Ronacher7fb38972008-04-11 13:54:28 +0200890 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200891 self.outdent()
892
Armin Ronacher8efc5222008-04-08 14:47:40 +0200893 def visit_Assign(self, node, frame):
894 self.newline(node)
895 # toplevel assignments however go into the local namespace and
896 # the current template's context. We create a copy of the frame
897 # here and add a set so that the Name visitor can add the assigned
898 # names here.
899 if frame.toplevel:
900 assignment_frame = frame.copy()
901 assignment_frame.assigned_names = set()
902 else:
903 assignment_frame = frame
904 self.visit(node.target, assignment_frame)
905 self.write(' = ')
906 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200907
908 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200909 if frame.toplevel:
910 for name in assignment_frame.assigned_names:
911 self.writeline('context[%r] = l_%s' % (name, name))
912
Armin Ronachere791c2a2008-04-07 18:39:54 +0200913 def visit_Name(self, node, frame):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200914 if node.ctx == 'store':
915 if frame.toplevel:
916 frame.assigned_names.add(node.name)
917 frame.name_overrides.pop(node.name, None)
918 elif node.ctx == 'load':
919 if node.name in frame.name_overrides:
920 self.write(frame.name_overrides[node.name])
921 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200922 self.write('l_' + node.name)
923
924 def visit_Const(self, node, frame):
925 val = node.value
926 if isinstance(val, float):
927 # XXX: add checks for infinity and nan
928 self.write(str(val))
929 else:
930 self.write(repr(val))
931
Armin Ronacher8efc5222008-04-08 14:47:40 +0200932 def visit_Tuple(self, node, frame):
933 self.write('(')
934 idx = -1
935 for idx, item in enumerate(node.items):
936 if idx:
937 self.write(', ')
938 self.visit(item, frame)
939 self.write(idx == 0 and ',)' or ')')
940
Armin Ronacher8edbe492008-04-10 20:43:43 +0200941 def visit_List(self, node, frame):
942 self.write('[')
943 for idx, item in enumerate(node.items):
944 if idx:
945 self.write(', ')
946 self.visit(item, frame)
947 self.write(']')
948
949 def visit_Dict(self, node, frame):
950 self.write('{')
951 for idx, item in enumerate(node.items):
952 if idx:
953 self.write(', ')
954 self.visit(item.key, frame)
955 self.write(': ')
956 self.visit(item.value, frame)
957 self.write('}')
958
Armin Ronachere791c2a2008-04-07 18:39:54 +0200959 def binop(operator):
960 def visitor(self, node, frame):
961 self.write('(')
962 self.visit(node.left, frame)
963 self.write(' %s ' % operator)
964 self.visit(node.right, frame)
965 self.write(')')
966 return visitor
967
968 def uaop(operator):
969 def visitor(self, node, frame):
970 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +0200971 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200972 self.write(')')
973 return visitor
974
975 visit_Add = binop('+')
976 visit_Sub = binop('-')
977 visit_Mul = binop('*')
978 visit_Div = binop('/')
979 visit_FloorDiv = binop('//')
980 visit_Pow = binop('**')
981 visit_Mod = binop('%')
982 visit_And = binop('and')
983 visit_Or = binop('or')
984 visit_Pos = uaop('+')
985 visit_Neg = uaop('-')
986 visit_Not = uaop('not ')
987 del binop, uaop
988
989 def visit_Compare(self, node, frame):
990 self.visit(node.expr, frame)
991 for op in node.ops:
992 self.visit(op, frame)
993
994 def visit_Operand(self, node, frame):
995 self.write(' %s ' % operators[node.op])
996 self.visit(node.expr, frame)
997
998 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200999 if isinstance(node.arg, nodes.Slice):
1000 self.visit(node.node, frame)
1001 self.write('[')
1002 self.visit(node.arg, frame)
1003 self.write(']')
1004 return
1005 try:
1006 const = node.arg.as_const()
1007 have_const = True
1008 except nodes.Impossible:
1009 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001010 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001011 self.visit(node.node, frame)
1012 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001013 if have_const:
1014 self.write(repr(const))
1015 else:
1016 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001017 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001018
1019 def visit_Slice(self, node, frame):
1020 if node.start is not None:
1021 self.visit(node.start, frame)
1022 self.write(':')
1023 if node.stop is not None:
1024 self.visit(node.stop, frame)
1025 if node.step is not None:
1026 self.write(':')
1027 self.visit(node.step, frame)
1028
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001029 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001030 self.write('f_%s(' % node.name)
Christoph Hack80909862008-04-14 01:35:10 +02001031 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001032 if func is None:
1033 raise TemplateAssertionError('no filter named %r' % node.name,
1034 node.lineno, self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001035 if getattr(func, 'contextfilter', False):
1036 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001037 elif getattr(func, 'environmentfilter', False):
1038 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001039 if isinstance(node.node, nodes.Filter):
1040 self.visit_Filter(node.node, frame, initial)
1041 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001042 self.write(initial)
1043 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001044 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001045 self.signature(node, frame)
1046 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001047
1048 def visit_Test(self, node, frame):
Armin Ronacherf059ec12008-04-11 22:21:00 +02001049 self.write('t_%s(' % node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001050 if node.name not in self.environment.tests:
1051 raise TemplateAssertionError('no test named %r' % node.name,
1052 node.lineno, self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001053 self.visit(node.node, frame)
1054 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001055 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001056
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001057 def visit_CondExpr(self, node, frame):
1058 if not have_condexpr:
1059 self.write('((')
1060 self.visit(node.test, frame)
1061 self.write(') and (')
1062 self.visit(node.expr1, frame)
1063 self.write(',) or (')
1064 self.visit(node.expr2, frame)
1065 self.write(',))[0]')
1066 else:
1067 self.write('(')
1068 self.visit(node.expr1, frame)
1069 self.write(' if ')
1070 self.visit(node.test, frame)
1071 self.write(' else ')
1072 self.visit(node.expr2, frame)
1073 self.write(')')
1074
Armin Ronacher71082072008-04-12 14:19:36 +02001075 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001076 if self.environment.sandboxed:
1077 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001078 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001079 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001080 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001081 self.write(')')
1082
1083 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001084 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001085 self.visit(node.value, frame)