blob: 871728f48d1a82b2b0d844ed111c60ed29c2f575 [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 Ronacherf059ec12008-04-11 22:21:00 +0200478 self.writeline('def root(globals, environment=environment'
479 ', standalone=False):', extra=1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200480 self.indent()
Armin Ronacherc63243e2008-04-14 22:53:58 +0200481 self.writeline('context = TemplateContext(environment, globals, %r, '
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200482 'blocks, standalone)' % self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200483 if have_extends:
484 self.writeline('parent_root = None')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200485 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200486
487 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200488 frame = Frame()
489 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200490 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200491 self.indent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200492 self.pull_locals(frame, indent=False)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200493 self.writeline('yield context')
Armin Ronacher625215e2008-04-13 16:31:08 +0200494 self.blockvisit(node.body, frame, indent=False)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200495 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200496
Armin Ronacher8efc5222008-04-08 14:47:40 +0200497 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200498 if have_extends:
499 if not self.has_known_extends:
500 self.indent()
501 self.writeline('if parent_root is not None:')
502 self.indent()
Armin Ronacherf059ec12008-04-11 22:21:00 +0200503 self.writeline('stream = parent_root(context)')
504 self.writeline('stream.next()')
505 self.writeline('for event in stream:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200506 self.indent()
507 self.writeline('yield event')
Armin Ronacher7a52df82008-04-11 13:58:22 +0200508 self.outdent(1 + self.has_known_extends)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200509
510 # at this point we now have the blocks collected and can visit them too.
511 for name, block in self.blocks.iteritems():
512 block_frame = Frame()
513 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200514 block_frame.block = name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200515 block_frame.identifiers.add_special('super')
516 block_frame.name_overrides['super'] = 'context.super(%r)' % name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200517 self.writeline('def block_%s(context, environment=environment):'
518 % name, block, 1)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200519 self.pull_locals(block_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200520 self.blockvisit(block.body, block_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200521
Armin Ronacher75cfb862008-04-11 13:47:22 +0200522 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200523 for x in self.blocks),
524 extra=1)
525
526 # add a function that returns the debug info
527 self.writeline('def get_debug_info():', extra=1)
528 self.indent()
529 self.writeline('return %r' % self.debug_info)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200530
Armin Ronachere791c2a2008-04-07 18:39:54 +0200531 def visit_Block(self, node, frame):
532 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200533 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200534 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200535 # if we know that we are a child template, there is no need to
536 # check if we are one
537 if self.has_known_extends:
538 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200539 if self.extends_so_far > 0:
540 self.writeline('if parent_root is None:')
541 self.indent()
542 level += 1
543 self.writeline('for event in context.blocks[%r][-1](context):' % node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200544 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200545 if frame.buffer is None:
546 self.writeline('yield event')
547 else:
548 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200549 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200550
551 def visit_Extends(self, node, frame):
552 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200553 if not frame.toplevel:
554 raise TemplateAssertionError('cannot use extend from a non '
555 'top-level scope', node.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200556 self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200557
Armin Ronacher7fb38972008-04-11 13:54:28 +0200558 # if the number of extends statements in general is zero so
559 # far, we don't have to add a check if something extended
560 # the template before this one.
561 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200562
Armin Ronacher7fb38972008-04-11 13:54:28 +0200563 # if we have a known extends we just add a template runtime
564 # error into the generated code. We could catch that at compile
565 # time too, but i welcome it not to confuse users by throwing the
566 # same error at different times just "because we can".
567 if not self.has_known_extends:
568 self.writeline('if parent_root is not None:')
569 self.indent()
570 self.writeline('raise TemplateRuntimeError(%r)' %
571 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200572
Armin Ronacher7fb38972008-04-11 13:54:28 +0200573 # if we have a known extends already we don't need that code here
574 # as we know that the template execution will end here.
575 if self.has_known_extends:
576 raise CompilerExit()
577 self.outdent()
578
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200579 self.writeline('parent_root = environment.get_template(', node, 1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200580 self.visit(node.template, frame)
Armin Ronacher68f77672008-04-17 11:50:39 +0200581 self.write(', %r).root_render_func' % self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200582
583 # if this extends statement was in the root level we can take
584 # advantage of that information and simplify the generated code
585 # in the top level from this point onwards
586 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200587
Armin Ronacher7fb38972008-04-11 13:54:28 +0200588 # and now we have one more
589 self.extends_so_far += 1
590
Armin Ronacherf059ec12008-04-11 22:21:00 +0200591 def visit_Include(self, node, frame):
592 """Handles includes."""
593 # simpled include is include into a variable. This kind of
594 # include works the same on every level, so we handle it first.
595 if node.target is not None:
596 self.writeline('l_%s = ' % node.target, node)
597 if frame.toplevel:
598 self.write('context[%r] = ' % node.target)
599 self.write('IncludedTemplate(environment, context, ')
600 self.visit(node.template, frame)
601 self.write(')')
602 return
603
604 self.writeline('included_stream = environment.get_template(', node)
605 self.visit(node.template, frame)
606 self.write(').root_render_func(context, standalone=True)')
607 self.writeline('included_context = included_stream.next()')
608 self.writeline('for event in included_stream:')
609 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200610 if frame.buffer is None:
611 self.writeline('yield event')
612 else:
613 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200614 self.outdent()
615
616 # if we have a toplevel include the exported variables are copied
617 # into the current context without exporting them. context.udpate
618 # does *not* mark the variables as exported
619 if frame.toplevel:
620 self.writeline('context.update(included_context.get_exported())')
621
Armin Ronachere791c2a2008-04-07 18:39:54 +0200622 def visit_For(self, node, frame):
623 loop_frame = frame.inner()
624 loop_frame.inspect(node.iter_child_nodes())
Armin Ronachere791c2a2008-04-07 18:39:54 +0200625 extended_loop = bool(node.else_) or \
626 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200627 if extended_loop:
628 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200629
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200630 aliases = self.collect_shadowed(loop_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200631 self.pull_locals(loop_frame, indent=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200632 if node.else_:
633 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200634
635 self.newline(node)
636 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200637 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200638 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200639
640 # the expression pointing to the parent loop. We make the
641 # undefined a bit more debug friendly at the same time.
642 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200643 or "environment.undefined(%r)" % "'loop' is undefined. " \
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200644 'the filter section of a loop as well as the ' \
645 'else block doesn\'t have access to the special ' \
646 "'loop' variable of the current loop. Because " \
647 'there is no parent loop it\'s undefined.'
648
649 # if we have an extened loop and a node test, we filter in the
650 # "outer frame".
651 if extended_loop and node.test is not None:
652 self.write('(')
653 self.visit(node.target, loop_frame)
654 self.write(' for ')
655 self.visit(node.target, loop_frame)
656 self.write(' in ')
657 self.visit(node.iter, loop_frame)
658 self.write(' if (')
659 test_frame = loop_frame.copy()
660 test_frame.name_overrides['loop'] = parent_loop
661 self.visit(node.test, test_frame)
662 self.write('))')
663
664 else:
665 self.visit(node.iter, loop_frame)
666
Armin Ronachere791c2a2008-04-07 18:39:54 +0200667 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200668
669 # tests in not extended loops become a continue
670 if not extended_loop and node.test is not None:
671 self.indent()
672 self.writeline('if ')
673 self.visit(node.test)
674 self.write(':')
675 self.indent()
676 self.writeline('continue')
677 self.outdent(2)
678
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200679 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200680
681 if node.else_:
682 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200683 self.indent()
684 self.writeline('l_loop = ' + parent_loop)
685 self.outdent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200686 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200687
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200688 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200689 for name, alias in aliases.iteritems():
Armin Ronacher8efc5222008-04-08 14:47:40 +0200690 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200691
692 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200693 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200694 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200695 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200696 self.write(':')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200697 self.blockvisit(node.body, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200698 if node.else_:
699 self.writeline('else:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200700 self.blockvisit(node.else_, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200701
Armin Ronacher8efc5222008-04-08 14:47:40 +0200702 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200703 macro_frame = self.function_scoping(node, frame)
704 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200705 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200706 macro_frame.buffer = buf = self.temporary_identifier()
707 self.indent()
708 self.pull_locals(macro_frame, indent=False)
709 self.writeline('%s = []' % buf)
710 self.blockvisit(node.body, macro_frame, indent=False)
Armin Ronacher5236d8c2008-04-17 11:23:16 +0200711 self.writeline("return Markup(u''.join(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200712 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200713 self.newline()
714 if frame.toplevel:
715 self.write('context[%r] = ' % node.name)
716 arg_tuple = ', '.join(repr(x.name) for x in node.args)
717 if len(node.args) == 1:
718 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200719 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
720 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200721 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200722 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200723 self.write(', ')
Armin Ronacher00d5d212008-04-13 01:10:18 +0200724 self.write('), %s, %s)' % (
725 macro_frame.accesses_arguments and '1' or '0',
726 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200727 ))
728
729 def visit_CallBlock(self, node, frame):
730 call_frame = self.function_scoping(node, frame)
731 args = call_frame.arguments
732 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200733 call_frame.buffer = buf = self.temporary_identifier()
734 self.indent()
735 self.pull_locals(call_frame, indent=False)
736 self.writeline('%s = []' % buf)
737 self.blockvisit(node.body, call_frame, indent=False)
Armin Ronacher5236d8c2008-04-17 11:23:16 +0200738 self.writeline("return Markup(u''.join(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200739 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200740 arg_tuple = ', '.join(repr(x.name) for x in node.args)
741 if len(node.args) == 1:
742 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200743 self.writeline('caller = Macro(environment, call, None, (%s), (' %
744 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200745 for arg in node.defaults:
746 self.visit(arg)
747 self.write(', ')
Armin Ronacher00d5d212008-04-13 01:10:18 +0200748 self.write('), %s, 0)' % (call_frame.accesses_arguments and '1' or '0'))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200749 if frame.buffer is None:
750 self.writeline('yield ', node)
751 else:
752 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher71082072008-04-12 14:19:36 +0200753 self.visit_Call(node.call, call_frame, extra_kwargs='caller=caller')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200754 if frame.buffer is not None:
755 self.write(')')
756
757 def visit_FilterBlock(self, node, frame):
758 filter_frame = frame.inner()
759 filter_frame.inspect(node.iter_child_nodes())
760
761 aliases = self.collect_shadowed(filter_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200762 self.pull_locals(filter_frame, indent=False)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200763 filter_frame.buffer = buf = self.temporary_identifier()
764
765 self.writeline('%s = []' % buf, node)
766 for child in node.body:
767 self.visit(child, filter_frame)
768
769 if frame.buffer is None:
770 self.writeline('yield ', node)
771 else:
772 self.writeline('%s.append(' % frame.buffer, node)
773 self.visit_Filter(node.filter, filter_frame, "u''.join(%s)" % buf)
774 if frame.buffer is not None:
775 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200776
Armin Ronachere791c2a2008-04-07 18:39:54 +0200777 def visit_ExprStmt(self, node, frame):
778 self.newline(node)
779 self.visit(node, frame)
780
781 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200782 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +0200783 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200784 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200785
Armin Ronacher75cfb862008-04-11 13:47:22 +0200786 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200787 if self.environment.finalize is unicode:
788 finalizer = 'unicode'
Armin Ronacherf059ec12008-04-11 22:21:00 +0200789 have_finalizer = False
Armin Ronacher8edbe492008-04-10 20:43:43 +0200790 else:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200791 finalizer = 'environment.finalize'
792 have_finalizer = True
Armin Ronacher8edbe492008-04-10 20:43:43 +0200793
Armin Ronacher7fb38972008-04-11 13:54:28 +0200794 # if we are in the toplevel scope and there was already an extends
795 # statement we have to add a check that disables our yield(s) here
796 # so that they don't appear in the output.
797 outdent_later = False
798 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200799 self.writeline('if parent_root is None:')
800 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200801 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +0200802
Armin Ronachere791c2a2008-04-07 18:39:54 +0200803 # try to evaluate as many chunks as possible into a static
804 # string at compile time.
805 body = []
806 for child in node.nodes:
807 try:
808 const = unicode(child.as_const())
809 except:
810 body.append(child)
811 continue
812 if body and isinstance(body[-1], list):
813 body[-1].append(const)
814 else:
815 body.append([const])
816
817 # if we have less than 3 nodes we just yield them
818 if len(body) < 3:
819 for item in body:
820 if isinstance(item, list):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200821 val = repr(u''.join(item))
822 if frame.buffer is None:
823 self.writeline('yield ' + val)
824 else:
825 self.writeline('%s.append(%s)' % (frame.buffer, val))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200826 else:
827 self.newline(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200828 if frame.buffer is None:
829 self.write('yield ')
830 else:
831 self.write('%s.append(' % frame.buffer)
832 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200833 self.visit(item, frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200834 self.write(')' * (1 + (frame.buffer is not None)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200835
836 # otherwise we create a format string as this is faster in that case
837 else:
838 format = []
839 arguments = []
840 for item in body:
841 if isinstance(item, list):
842 format.append(u''.join(item).replace('%', '%%'))
843 else:
844 format.append('%s')
845 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200846 if frame.buffer is None:
847 self.writeline('yield ')
848 else:
849 self.writeline('%s.append(' % frame.buffer)
850 self.write(repr(u''.join(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200851 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200852 self.indent()
853 for argument in arguments:
854 self.newline(argument)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200855 if have_finalizer:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200856 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200857 self.visit(argument, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200858 if have_finalizer:
Armin Ronacher8edbe492008-04-10 20:43:43 +0200859 self.write(')')
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200860 self.write(',')
861 self.outdent()
862 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200863 if frame.buffer is not None:
864 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200865
Armin Ronacher7fb38972008-04-11 13:54:28 +0200866 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200867 self.outdent()
868
Armin Ronacher8efc5222008-04-08 14:47:40 +0200869 def visit_Assign(self, node, frame):
870 self.newline(node)
871 # toplevel assignments however go into the local namespace and
872 # the current template's context. We create a copy of the frame
873 # here and add a set so that the Name visitor can add the assigned
874 # names here.
875 if frame.toplevel:
876 assignment_frame = frame.copy()
877 assignment_frame.assigned_names = set()
878 else:
879 assignment_frame = frame
880 self.visit(node.target, assignment_frame)
881 self.write(' = ')
882 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200883
884 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200885 if frame.toplevel:
886 for name in assignment_frame.assigned_names:
887 self.writeline('context[%r] = l_%s' % (name, name))
888
Armin Ronachere791c2a2008-04-07 18:39:54 +0200889 def visit_Name(self, node, frame):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200890 if node.ctx == 'store':
891 if frame.toplevel:
892 frame.assigned_names.add(node.name)
893 frame.name_overrides.pop(node.name, None)
894 elif node.ctx == 'load':
895 if node.name in frame.name_overrides:
896 self.write(frame.name_overrides[node.name])
897 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200898 self.write('l_' + node.name)
899
900 def visit_Const(self, node, frame):
901 val = node.value
902 if isinstance(val, float):
903 # XXX: add checks for infinity and nan
904 self.write(str(val))
905 else:
906 self.write(repr(val))
907
Armin Ronacher8efc5222008-04-08 14:47:40 +0200908 def visit_Tuple(self, node, frame):
909 self.write('(')
910 idx = -1
911 for idx, item in enumerate(node.items):
912 if idx:
913 self.write(', ')
914 self.visit(item, frame)
915 self.write(idx == 0 and ',)' or ')')
916
Armin Ronacher8edbe492008-04-10 20:43:43 +0200917 def visit_List(self, node, frame):
918 self.write('[')
919 for idx, item in enumerate(node.items):
920 if idx:
921 self.write(', ')
922 self.visit(item, frame)
923 self.write(']')
924
925 def visit_Dict(self, node, frame):
926 self.write('{')
927 for idx, item in enumerate(node.items):
928 if idx:
929 self.write(', ')
930 self.visit(item.key, frame)
931 self.write(': ')
932 self.visit(item.value, frame)
933 self.write('}')
934
Armin Ronachere791c2a2008-04-07 18:39:54 +0200935 def binop(operator):
936 def visitor(self, node, frame):
937 self.write('(')
938 self.visit(node.left, frame)
939 self.write(' %s ' % operator)
940 self.visit(node.right, frame)
941 self.write(')')
942 return visitor
943
944 def uaop(operator):
945 def visitor(self, node, frame):
946 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +0200947 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200948 self.write(')')
949 return visitor
950
951 visit_Add = binop('+')
952 visit_Sub = binop('-')
953 visit_Mul = binop('*')
954 visit_Div = binop('/')
955 visit_FloorDiv = binop('//')
956 visit_Pow = binop('**')
957 visit_Mod = binop('%')
958 visit_And = binop('and')
959 visit_Or = binop('or')
960 visit_Pos = uaop('+')
961 visit_Neg = uaop('-')
962 visit_Not = uaop('not ')
963 del binop, uaop
964
965 def visit_Compare(self, node, frame):
966 self.visit(node.expr, frame)
967 for op in node.ops:
968 self.visit(op, frame)
969
970 def visit_Operand(self, node, frame):
971 self.write(' %s ' % operators[node.op])
972 self.visit(node.expr, frame)
973
974 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200975 if isinstance(node.arg, nodes.Slice):
976 self.visit(node.node, frame)
977 self.write('[')
978 self.visit(node.arg, frame)
979 self.write(']')
980 return
981 try:
982 const = node.arg.as_const()
983 have_const = True
984 except nodes.Impossible:
985 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +0200986 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200987 self.visit(node.node, frame)
988 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200989 if have_const:
990 self.write(repr(const))
991 else:
992 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200993 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200994
995 def visit_Slice(self, node, frame):
996 if node.start is not None:
997 self.visit(node.start, frame)
998 self.write(':')
999 if node.stop is not None:
1000 self.visit(node.stop, frame)
1001 if node.step is not None:
1002 self.write(':')
1003 self.visit(node.step, frame)
1004
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001005 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001006 self.write('f_%s(' % node.name)
Christoph Hack80909862008-04-14 01:35:10 +02001007 func = self.environment.filters.get(node.name)
1008 if getattr(func, 'contextfilter', False):
1009 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001010 elif getattr(func, 'environmentfilter', False):
1011 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001012 if isinstance(node.node, nodes.Filter):
1013 self.visit_Filter(node.node, frame, initial)
1014 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001015 self.write(initial)
1016 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001017 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001018 self.signature(node, frame)
1019 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001020
1021 def visit_Test(self, node, frame):
Armin Ronacherf059ec12008-04-11 22:21:00 +02001022 self.write('t_%s(' % node.name)
1023 func = self.environment.tests.get(node.name)
1024 if getattr(func, 'contexttest', False):
1025 self.write('context, ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001026 self.visit(node.node, frame)
1027 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001028 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001029
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001030 def visit_CondExpr(self, node, frame):
1031 if not have_condexpr:
1032 self.write('((')
1033 self.visit(node.test, frame)
1034 self.write(') and (')
1035 self.visit(node.expr1, frame)
1036 self.write(',) or (')
1037 self.visit(node.expr2, frame)
1038 self.write(',))[0]')
1039 else:
1040 self.write('(')
1041 self.visit(node.expr1, frame)
1042 self.write(' if ')
1043 self.visit(node.test, frame)
1044 self.write(' else ')
1045 self.visit(node.expr2, frame)
1046 self.write(')')
1047
Armin Ronacher71082072008-04-12 14:19:36 +02001048 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001049 if self.environment.sandboxed:
1050 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001051 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001052 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001053 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001054 self.write(')')
1055
1056 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001057 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001058 self.visit(node.value, frame)