blob: 9bf1e4d61a69984a64b5b7cbfd83f7cf9e5fec7b [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
444 func_frame.accesses_arguments = False
445 func_frame.accesses_caller = False
446 func_frame.arguments = args = ['l_' + x.name for x in node.args]
447
448 if 'arguments' in func_frame.identifiers.undeclared:
449 func_frame.accesses_arguments = True
450 func_frame.identifiers.add_special('arguments')
451 args.append('l_arguments')
452 if 'caller' in func_frame.identifiers.undeclared:
453 func_frame.accesses_caller = True
454 func_frame.identifiers.add_special('caller')
455 args.append('l_caller')
456 return func_frame
457
Armin Ronachere791c2a2008-04-07 18:39:54 +0200458 # -- Visitors
459
460 def visit_Template(self, node, frame=None):
461 assert frame is None, 'no root frame allowed'
462 self.writeline('from jinja2.runtime import *')
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200463 self.writeline('name = %r' % self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200464
Armin Ronacher75cfb862008-04-11 13:47:22 +0200465 # do we have an extends tag at all? If not, we can save some
466 # overhead by just not processing any inheritance code.
467 have_extends = node.find(nodes.Extends) is not None
468
Armin Ronacher8edbe492008-04-10 20:43:43 +0200469 # find all blocks
470 for block in node.find_all(nodes.Block):
471 if block.name in self.blocks:
472 raise TemplateAssertionError('block %r defined twice' %
473 block.name, block.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200474 self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200475 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200476
Armin Ronacher8efc5222008-04-08 14:47:40 +0200477 # generate the root render function.
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200478 self.writeline('def root(context, environment=environment'
479 '):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200480 if have_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200481 self.indent()
482 self.writeline('parent_template = None')
483 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200484
485 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200486 frame = Frame()
487 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200488 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200489 self.indent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200490 self.pull_locals(frame, indent=False)
Armin Ronacher625215e2008-04-13 16:31:08 +0200491 self.blockvisit(node.body, frame, indent=False)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200492 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200493
Armin Ronacher8efc5222008-04-08 14:47:40 +0200494 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200495 if have_extends:
496 if not self.has_known_extends:
497 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200498 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200499 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200500 self.writeline('for event in parent_template.'
501 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200502 self.indent()
503 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200504 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200505
506 # at this point we now have the blocks collected and can visit them too.
507 for name, block in self.blocks.iteritems():
508 block_frame = Frame()
509 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200510 block_frame.block = name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200511 block_frame.identifiers.add_special('super')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200512 block_frame.name_overrides['super'] = 'context.super(%r, ' \
513 'block_%s)' % (name, name)
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200514 self.writeline('def block_%s(context, environment=environment):'
515 % name, block, 1)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200516 self.pull_locals(block_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200517 self.blockvisit(block.body, block_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200518
Armin Ronacher75cfb862008-04-11 13:47:22 +0200519 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200520 for x in self.blocks),
521 extra=1)
522
523 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200524 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
525 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200526
Armin Ronachere791c2a2008-04-07 18:39:54 +0200527 def visit_Block(self, node, frame):
528 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200529 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200530 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200531 # if we know that we are a child template, there is no need to
532 # check if we are one
533 if self.has_known_extends:
534 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200535 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200536 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200537 self.indent()
538 level += 1
539 self.writeline('for event in context.blocks[%r][-1](context):' % node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200540 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200541 if frame.buffer is None:
542 self.writeline('yield event')
543 else:
544 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200545 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200546
547 def visit_Extends(self, node, frame):
548 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200549 if not frame.toplevel:
550 raise TemplateAssertionError('cannot use extend from a non '
551 'top-level scope', node.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200552 self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200553
Armin Ronacher7fb38972008-04-11 13:54:28 +0200554 # if the number of extends statements in general is zero so
555 # far, we don't have to add a check if something extended
556 # the template before this one.
557 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200558
Armin Ronacher7fb38972008-04-11 13:54:28 +0200559 # if we have a known extends we just add a template runtime
560 # error into the generated code. We could catch that at compile
561 # time too, but i welcome it not to confuse users by throwing the
562 # same error at different times just "because we can".
563 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200564 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200565 self.indent()
566 self.writeline('raise TemplateRuntimeError(%r)' %
567 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200568
Armin Ronacher7fb38972008-04-11 13:54:28 +0200569 # if we have a known extends already we don't need that code here
570 # as we know that the template execution will end here.
571 if self.has_known_extends:
572 raise CompilerExit()
573 self.outdent()
574
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200575 self.writeline('parent_template = environment.get_template(', node, 1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200576 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200577 self.write(', %r)' % self.name)
578 self.writeline('for name, parent_block in parent_template.'
579 'blocks.iteritems():')
580 self.indent()
581 self.writeline('context.blocks.setdefault(name, []).'
582 'insert(0, parent_block)')
583 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200584
585 # if this extends statement was in the root level we can take
586 # advantage of that information and simplify the generated code
587 # in the top level from this point onwards
588 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200589
Armin Ronacher7fb38972008-04-11 13:54:28 +0200590 # and now we have one more
591 self.extends_so_far += 1
592
Armin Ronacherf059ec12008-04-11 22:21:00 +0200593 def visit_Include(self, node, frame):
594 """Handles includes."""
595 # simpled include is include into a variable. This kind of
596 # include works the same on every level, so we handle it first.
597 if node.target is not None:
598 self.writeline('l_%s = ' % node.target, node)
599 if frame.toplevel:
600 self.write('context[%r] = ' % node.target)
601 self.write('IncludedTemplate(environment, context, ')
602 self.visit(node.template, frame)
603 self.write(')')
604 return
605
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200606 self.writeline('included_template = environment.get_template(', node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200607 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200608 self.write(')')
609 if frame.toplevel:
610 self.writeline('included_context = included_template.new_context('
611 'context.get_root())')
612 self.writeline('for event in included_template.root_render_func('
613 'included_context):')
614 else:
615 self.writeline('for event in included_template.root_render_func('
616 'included_template.new_context(context.get_root())):')
Armin Ronacherf059ec12008-04-11 22:21:00 +0200617 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200618 if frame.buffer is None:
619 self.writeline('yield event')
620 else:
621 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200622 self.outdent()
623
624 # if we have a toplevel include the exported variables are copied
625 # into the current context without exporting them. context.udpate
626 # does *not* mark the variables as exported
627 if frame.toplevel:
628 self.writeline('context.update(included_context.get_exported())')
629
Armin Ronachere791c2a2008-04-07 18:39:54 +0200630 def visit_For(self, node, frame):
631 loop_frame = frame.inner()
632 loop_frame.inspect(node.iter_child_nodes())
Armin Ronachere791c2a2008-04-07 18:39:54 +0200633 extended_loop = bool(node.else_) or \
634 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200635 if extended_loop:
636 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200637
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200638 aliases = self.collect_shadowed(loop_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200639 self.pull_locals(loop_frame, indent=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200640 if node.else_:
641 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200642
643 self.newline(node)
644 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200645 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200646 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200647
648 # the expression pointing to the parent loop. We make the
649 # undefined a bit more debug friendly at the same time.
650 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200651 or "environment.undefined(%r)" % "'loop' is undefined. " \
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200652 'the filter section of a loop as well as the ' \
653 'else block doesn\'t have access to the special ' \
654 "'loop' variable of the current loop. Because " \
655 'there is no parent loop it\'s undefined.'
656
657 # if we have an extened loop and a node test, we filter in the
658 # "outer frame".
659 if extended_loop and node.test is not None:
660 self.write('(')
661 self.visit(node.target, loop_frame)
662 self.write(' for ')
663 self.visit(node.target, loop_frame)
664 self.write(' in ')
665 self.visit(node.iter, loop_frame)
666 self.write(' if (')
667 test_frame = loop_frame.copy()
668 test_frame.name_overrides['loop'] = parent_loop
669 self.visit(node.test, test_frame)
670 self.write('))')
671
672 else:
673 self.visit(node.iter, loop_frame)
674
Armin Ronachere791c2a2008-04-07 18:39:54 +0200675 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200676
677 # tests in not extended loops become a continue
678 if not extended_loop and node.test is not None:
679 self.indent()
680 self.writeline('if ')
681 self.visit(node.test)
682 self.write(':')
683 self.indent()
684 self.writeline('continue')
685 self.outdent(2)
686
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200687 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200688
689 if node.else_:
690 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200691 self.indent()
692 self.writeline('l_loop = ' + parent_loop)
693 self.outdent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200694 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200695
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200696 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200697 for name, alias in aliases.iteritems():
Armin Ronacher8efc5222008-04-08 14:47:40 +0200698 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200699
700 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200701 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200702 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200703 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200704 self.write(':')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200705 self.blockvisit(node.body, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200706 if node.else_:
707 self.writeline('else:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200708 self.blockvisit(node.else_, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200709
Armin Ronacher8efc5222008-04-08 14:47:40 +0200710 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200711 macro_frame = self.function_scoping(node, frame)
712 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200713 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200714 macro_frame.buffer = buf = self.temporary_identifier()
715 self.indent()
716 self.pull_locals(macro_frame, indent=False)
717 self.writeline('%s = []' % buf)
718 self.blockvisit(node.body, macro_frame, indent=False)
Armin Ronacher5236d8c2008-04-17 11:23:16 +0200719 self.writeline("return Markup(u''.join(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200720 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200721 self.newline()
722 if frame.toplevel:
723 self.write('context[%r] = ' % node.name)
724 arg_tuple = ', '.join(repr(x.name) for x in node.args)
725 if len(node.args) == 1:
726 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200727 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
728 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200729 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200730 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200731 self.write(', ')
Armin Ronacher00d5d212008-04-13 01:10:18 +0200732 self.write('), %s, %s)' % (
733 macro_frame.accesses_arguments and '1' or '0',
734 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200735 ))
736
737 def visit_CallBlock(self, node, frame):
738 call_frame = self.function_scoping(node, frame)
739 args = call_frame.arguments
740 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200741 call_frame.buffer = buf = self.temporary_identifier()
742 self.indent()
743 self.pull_locals(call_frame, indent=False)
744 self.writeline('%s = []' % buf)
745 self.blockvisit(node.body, call_frame, indent=False)
Armin Ronacher5236d8c2008-04-17 11:23:16 +0200746 self.writeline("return Markup(u''.join(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200747 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200748 arg_tuple = ', '.join(repr(x.name) for x in node.args)
749 if len(node.args) == 1:
750 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200751 self.writeline('caller = Macro(environment, call, None, (%s), (' %
752 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200753 for arg in node.defaults:
754 self.visit(arg)
755 self.write(', ')
Armin Ronacher00d5d212008-04-13 01:10:18 +0200756 self.write('), %s, 0)' % (call_frame.accesses_arguments and '1' or '0'))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200757 if frame.buffer is None:
758 self.writeline('yield ', node)
759 else:
760 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher71082072008-04-12 14:19:36 +0200761 self.visit_Call(node.call, call_frame, extra_kwargs='caller=caller')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200762 if frame.buffer is not None:
763 self.write(')')
764
765 def visit_FilterBlock(self, node, frame):
766 filter_frame = frame.inner()
767 filter_frame.inspect(node.iter_child_nodes())
768
769 aliases = self.collect_shadowed(filter_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200770 self.pull_locals(filter_frame, indent=False)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200771 filter_frame.buffer = buf = self.temporary_identifier()
772
773 self.writeline('%s = []' % buf, node)
774 for child in node.body:
775 self.visit(child, filter_frame)
776
777 if frame.buffer is None:
778 self.writeline('yield ', node)
779 else:
780 self.writeline('%s.append(' % frame.buffer, node)
781 self.visit_Filter(node.filter, filter_frame, "u''.join(%s)" % buf)
782 if frame.buffer is not None:
783 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200784
Armin Ronachere791c2a2008-04-07 18:39:54 +0200785 def visit_ExprStmt(self, node, frame):
786 self.newline(node)
787 self.visit(node, frame)
788
789 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200790 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +0200791 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200792 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200793
Armin Ronacher75cfb862008-04-11 13:47:22 +0200794 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200795 if self.environment.finalize is unicode:
796 finalizer = 'unicode'
Armin Ronacherf059ec12008-04-11 22:21:00 +0200797 have_finalizer = False
Armin Ronacher8edbe492008-04-10 20:43:43 +0200798 else:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200799 finalizer = 'environment.finalize'
800 have_finalizer = True
Armin Ronacher8edbe492008-04-10 20:43:43 +0200801
Armin Ronacher7fb38972008-04-11 13:54:28 +0200802 # if we are in the toplevel scope and there was already an extends
803 # statement we have to add a check that disables our yield(s) here
804 # so that they don't appear in the output.
805 outdent_later = False
806 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200807 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200808 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200809 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +0200810
Armin Ronachere791c2a2008-04-07 18:39:54 +0200811 # try to evaluate as many chunks as possible into a static
812 # string at compile time.
813 body = []
814 for child in node.nodes:
815 try:
816 const = unicode(child.as_const())
817 except:
818 body.append(child)
819 continue
820 if body and isinstance(body[-1], list):
821 body[-1].append(const)
822 else:
823 body.append([const])
824
825 # if we have less than 3 nodes we just yield them
826 if len(body) < 3:
827 for item in body:
828 if isinstance(item, list):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200829 val = repr(u''.join(item))
830 if frame.buffer is None:
831 self.writeline('yield ' + val)
832 else:
833 self.writeline('%s.append(%s)' % (frame.buffer, val))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200834 else:
835 self.newline(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200836 if frame.buffer is None:
837 self.write('yield ')
838 else:
839 self.write('%s.append(' % frame.buffer)
840 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200841 self.visit(item, frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200842 self.write(')' * (1 + (frame.buffer is not None)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200843
844 # otherwise we create a format string as this is faster in that case
845 else:
846 format = []
847 arguments = []
848 for item in body:
849 if isinstance(item, list):
850 format.append(u''.join(item).replace('%', '%%'))
851 else:
852 format.append('%s')
853 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200854 if frame.buffer is None:
855 self.writeline('yield ')
856 else:
857 self.writeline('%s.append(' % frame.buffer)
858 self.write(repr(u''.join(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200859 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200860 self.indent()
861 for argument in arguments:
862 self.newline(argument)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200863 if have_finalizer:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200864 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200865 self.visit(argument, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200866 if have_finalizer:
Armin Ronacher8edbe492008-04-10 20:43:43 +0200867 self.write(')')
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200868 self.write(',')
869 self.outdent()
870 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200871 if frame.buffer is not None:
872 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200873
Armin Ronacher7fb38972008-04-11 13:54:28 +0200874 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200875 self.outdent()
876
Armin Ronacher8efc5222008-04-08 14:47:40 +0200877 def visit_Assign(self, node, frame):
878 self.newline(node)
879 # toplevel assignments however go into the local namespace and
880 # the current template's context. We create a copy of the frame
881 # here and add a set so that the Name visitor can add the assigned
882 # names here.
883 if frame.toplevel:
884 assignment_frame = frame.copy()
885 assignment_frame.assigned_names = set()
886 else:
887 assignment_frame = frame
888 self.visit(node.target, assignment_frame)
889 self.write(' = ')
890 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200891
892 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200893 if frame.toplevel:
894 for name in assignment_frame.assigned_names:
895 self.writeline('context[%r] = l_%s' % (name, name))
896
Armin Ronachere791c2a2008-04-07 18:39:54 +0200897 def visit_Name(self, node, frame):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200898 if node.ctx == 'store':
899 if frame.toplevel:
900 frame.assigned_names.add(node.name)
901 frame.name_overrides.pop(node.name, None)
902 elif node.ctx == 'load':
903 if node.name in frame.name_overrides:
904 self.write(frame.name_overrides[node.name])
905 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200906 self.write('l_' + node.name)
907
908 def visit_Const(self, node, frame):
909 val = node.value
910 if isinstance(val, float):
911 # XXX: add checks for infinity and nan
912 self.write(str(val))
913 else:
914 self.write(repr(val))
915
Armin Ronacher8efc5222008-04-08 14:47:40 +0200916 def visit_Tuple(self, node, frame):
917 self.write('(')
918 idx = -1
919 for idx, item in enumerate(node.items):
920 if idx:
921 self.write(', ')
922 self.visit(item, frame)
923 self.write(idx == 0 and ',)' or ')')
924
Armin Ronacher8edbe492008-04-10 20:43:43 +0200925 def visit_List(self, node, frame):
926 self.write('[')
927 for idx, item in enumerate(node.items):
928 if idx:
929 self.write(', ')
930 self.visit(item, frame)
931 self.write(']')
932
933 def visit_Dict(self, node, frame):
934 self.write('{')
935 for idx, item in enumerate(node.items):
936 if idx:
937 self.write(', ')
938 self.visit(item.key, frame)
939 self.write(': ')
940 self.visit(item.value, frame)
941 self.write('}')
942
Armin Ronachere791c2a2008-04-07 18:39:54 +0200943 def binop(operator):
944 def visitor(self, node, frame):
945 self.write('(')
946 self.visit(node.left, frame)
947 self.write(' %s ' % operator)
948 self.visit(node.right, frame)
949 self.write(')')
950 return visitor
951
952 def uaop(operator):
953 def visitor(self, node, frame):
954 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +0200955 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200956 self.write(')')
957 return visitor
958
959 visit_Add = binop('+')
960 visit_Sub = binop('-')
961 visit_Mul = binop('*')
962 visit_Div = binop('/')
963 visit_FloorDiv = binop('//')
964 visit_Pow = binop('**')
965 visit_Mod = binop('%')
966 visit_And = binop('and')
967 visit_Or = binop('or')
968 visit_Pos = uaop('+')
969 visit_Neg = uaop('-')
970 visit_Not = uaop('not ')
971 del binop, uaop
972
973 def visit_Compare(self, node, frame):
974 self.visit(node.expr, frame)
975 for op in node.ops:
976 self.visit(op, frame)
977
978 def visit_Operand(self, node, frame):
979 self.write(' %s ' % operators[node.op])
980 self.visit(node.expr, frame)
981
982 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200983 if isinstance(node.arg, nodes.Slice):
984 self.visit(node.node, frame)
985 self.write('[')
986 self.visit(node.arg, frame)
987 self.write(']')
988 return
989 try:
990 const = node.arg.as_const()
991 have_const = True
992 except nodes.Impossible:
993 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +0200994 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200995 self.visit(node.node, frame)
996 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200997 if have_const:
998 self.write(repr(const))
999 else:
1000 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001001 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001002
1003 def visit_Slice(self, node, frame):
1004 if node.start is not None:
1005 self.visit(node.start, frame)
1006 self.write(':')
1007 if node.stop is not None:
1008 self.visit(node.stop, frame)
1009 if node.step is not None:
1010 self.write(':')
1011 self.visit(node.step, frame)
1012
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001013 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001014 self.write('f_%s(' % node.name)
Christoph Hack80909862008-04-14 01:35:10 +02001015 func = self.environment.filters.get(node.name)
1016 if getattr(func, 'contextfilter', False):
1017 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001018 elif getattr(func, 'environmentfilter', False):
1019 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001020 if isinstance(node.node, nodes.Filter):
1021 self.visit_Filter(node.node, frame, initial)
1022 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001023 self.write(initial)
1024 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001025 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001026 self.signature(node, frame)
1027 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001028
1029 def visit_Test(self, node, frame):
Armin Ronacherf059ec12008-04-11 22:21:00 +02001030 self.write('t_%s(' % node.name)
1031 func = self.environment.tests.get(node.name)
1032 if getattr(func, 'contexttest', False):
1033 self.write('context, ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001034 self.visit(node.node, frame)
1035 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001036 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001037
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001038 def visit_CondExpr(self, node, frame):
1039 if not have_condexpr:
1040 self.write('((')
1041 self.visit(node.test, frame)
1042 self.write(') and (')
1043 self.visit(node.expr1, frame)
1044 self.write(',) or (')
1045 self.visit(node.expr2, frame)
1046 self.write(',))[0]')
1047 else:
1048 self.write('(')
1049 self.visit(node.expr1, frame)
1050 self.write(' if ')
1051 self.visit(node.test, frame)
1052 self.write(' else ')
1053 self.visit(node.expr2, frame)
1054 self.write(')')
1055
Armin Ronacher71082072008-04-12 14:19:36 +02001056 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001057 if self.environment.sandboxed:
1058 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001059 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001060 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001061 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001062 self.write(')')
1063
1064 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001065 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001066 self.visit(node.value, frame)