blob: 4716de194d8d23dcb1d72b44cba2b575e2f3a5e5 [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 Ronacher32a910f2008-04-26 23:21:03 +020011from time import time
Armin Ronacher8efc5222008-04-08 14:47:40 +020012from copy import copy
Armin Ronachere791c2a2008-04-07 18:39:54 +020013from random import randrange
Armin Ronacher2feed1d2008-04-26 16:26:52 +020014from keyword import iskeyword
Armin Ronachere791c2a2008-04-07 18:39:54 +020015from cStringIO import StringIO
Armin Ronacherd1ff8582008-05-11 00:30:43 +020016from itertools import chain
Armin Ronachere791c2a2008-04-07 18:39:54 +020017from jinja2 import nodes
18from jinja2.visitor import NodeVisitor, NodeTransformer
19from jinja2.exceptions import TemplateAssertionError
Armin Ronacher7ceced52008-05-03 10:15:31 +020020from jinja2.utils import Markup, concat
Armin Ronachere791c2a2008-04-07 18:39:54 +020021
22
23operators = {
24 'eq': '==',
25 'ne': '!=',
26 'gt': '>',
27 'gteq': '>=',
28 'lt': '<',
29 'lteq': '<=',
30 'in': 'in',
31 'notin': 'not in'
32}
33
Armin Ronacher3d8b7842008-04-13 13:16:50 +020034try:
35 exec '(0 if 0 else 0)'
36except SyntaxError:
37 have_condexpr = False
38else:
39 have_condexpr = True
40
41
Armin Ronacher8e8d0712008-04-16 23:10:49 +020042def generate(node, environment, name, filename, stream=None):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020043 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020044 if not isinstance(node, nodes.Template):
45 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher8e8d0712008-04-16 23:10:49 +020046 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020047 generator.visit(node)
48 if stream is None:
49 return generator.stream.getvalue()
50
51
Armin Ronacher4dfc9752008-04-09 15:03:29 +020052def has_safe_repr(value):
53 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020054 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020055 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020056 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher32a910f2008-04-26 23:21:03 +020057 xrange, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020058 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020059 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020060 for item in value:
61 if not has_safe_repr(item):
62 return False
63 return True
64 elif isinstance(value, dict):
65 for key, value in value.iteritems():
66 if not has_safe_repr(key):
67 return False
68 if not has_safe_repr(value):
69 return False
70 return True
71 return False
72
73
Armin Ronacherc9705c22008-04-27 21:28:03 +020074def find_undeclared(nodes, names):
75 """Check if the names passed are accessed undeclared. The return value
76 is a set of all the undeclared names from the sequence of names found.
77 """
78 visitor = UndeclaredNameVisitor(names)
79 try:
80 for node in nodes:
81 visitor.visit(node)
82 except VisitorExit:
83 pass
84 return visitor.undeclared
85
86
Armin Ronachere791c2a2008-04-07 18:39:54 +020087class Identifiers(object):
88 """Tracks the status of identifiers in frames."""
89
90 def __init__(self):
91 # variables that are known to be declared (probably from outer
92 # frames or because they are special for the frame)
93 self.declared = set()
94
Armin Ronacher10f3ba22008-04-18 11:30:37 +020095 # undeclared variables from outer scopes
96 self.outer_undeclared = set()
97
Armin Ronachere791c2a2008-04-07 18:39:54 +020098 # names that are accessed without being explicitly declared by
99 # this one or any of the outer scopes. Names can appear both in
100 # declared and undeclared.
101 self.undeclared = set()
102
103 # names that are declared locally
104 self.declared_locally = set()
105
106 # names that are declared by parameters
107 self.declared_parameter = set()
108
109 def add_special(self, name):
110 """Register a special name like `loop`."""
111 self.undeclared.discard(name)
112 self.declared.add(name)
113
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200114 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200115 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200116 if name in self.declared_locally or name in self.declared_parameter:
117 return True
118 if local_only:
119 return False
120 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200121
122 def find_shadowed(self):
123 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200124 return (self.declared | self.outer_undeclared) & \
125 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200126
127
128class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200129 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200130
131 def __init__(self, parent=None):
132 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200133
Armin Ronacher75cfb862008-04-11 13:47:22 +0200134 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200135 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200136
Armin Ronacher75cfb862008-04-11 13:47:22 +0200137 # the root frame is basically just the outermost frame, so no if
138 # conditions. This information is used to optimize inheritance
139 # situations.
140 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200141
142 # inside some tags we are using a buffer rather than yield statements.
143 # this for example affects {% filter %} or {% macro %}. If a frame
144 # is buffered this variable points to the name of the list used as
145 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200146 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200147
Armin Ronacherfed44b52008-04-13 19:42:53 +0200148 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200149 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200150
151 # the parent of this frame
152 self.parent = parent
153
Armin Ronachere791c2a2008-04-07 18:39:54 +0200154 if parent is not None:
155 self.identifiers.declared.update(
156 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200157 parent.identifiers.declared_locally |
158 parent.identifiers.declared_parameter
159 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200160 self.identifiers.outer_undeclared.update(
161 parent.identifiers.undeclared -
162 self.identifiers.declared
163 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200164 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200165
Armin Ronacher8efc5222008-04-08 14:47:40 +0200166 def copy(self):
167 """Create a copy of the current one."""
168 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200169 rv.identifiers = copy(self.identifiers)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200170 return rv
171
Armin Ronacherc9705c22008-04-27 21:28:03 +0200172 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200173 """Walk the node and check for identifiers. If the scope is hard (eg:
174 enforce on a python level) overrides from outer scopes are tracked
175 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200176 """
177 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200178 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200179 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200180
181 def inner(self):
182 """Return an inner frame."""
183 return Frame(self)
184
Armin Ronacher75cfb862008-04-11 13:47:22 +0200185 def soft(self):
186 """Return a soft frame. A soft frame may not be modified as
187 standalone thing as it shares the resources with the frame it
188 was created of, but it's not a rootlevel frame any longer.
189 """
190 rv = copy(self)
191 rv.rootlevel = False
192 return rv
193
Armin Ronachere791c2a2008-04-07 18:39:54 +0200194
Armin Ronacherc9705c22008-04-27 21:28:03 +0200195class VisitorExit(RuntimeError):
196 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
197
198
199class DependencyFinderVisitor(NodeVisitor):
200 """A visitor that collects filter and test calls."""
201
202 def __init__(self):
203 self.filters = set()
204 self.tests = set()
205
206 def visit_Filter(self, node):
207 self.generic_visit(node)
208 self.filters.add(node.name)
209
210 def visit_Test(self, node):
211 self.generic_visit(node)
212 self.tests.add(node.name)
213
214 def visit_Block(self, node):
215 """Stop visiting at blocks."""
216
217
218class UndeclaredNameVisitor(NodeVisitor):
219 """A visitor that checks if a name is accessed without being
220 declared. This is different from the frame visitor as it will
221 not stop at closure frames.
222 """
223
224 def __init__(self, names):
225 self.names = set(names)
226 self.undeclared = set()
227
228 def visit_Name(self, node):
229 if node.ctx == 'load' and node.name in self.names:
230 self.undeclared.add(node.name)
231 if self.undeclared == self.names:
232 raise VisitorExit()
233 else:
234 self.names.discard(node.name)
235
236 def visit_Block(self, node):
237 """Stop visiting a blocks."""
238
239
Armin Ronachere791c2a2008-04-07 18:39:54 +0200240class FrameIdentifierVisitor(NodeVisitor):
241 """A visitor for `Frame.inspect`."""
242
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200243 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200244 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200245 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200246
Armin Ronacherc9705c22008-04-27 21:28:03 +0200247 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200248 """All assignments to names go through this function."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200249 if node.ctx in ('store', 'param'):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200250 self.identifiers.declared_locally.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200251 elif node.ctx == 'load' and not \
252 self.identifiers.is_declared(node.name, self.hard_scope):
253 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200254
Armin Ronacherc9705c22008-04-27 21:28:03 +0200255 def visit_Macro(self, node):
256 self.generic_visit(node)
257 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200258
Armin Ronacherc9705c22008-04-27 21:28:03 +0200259 def visit_Import(self, node):
260 self.generic_visit(node)
261 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200262
Armin Ronacherc9705c22008-04-27 21:28:03 +0200263 def visit_FromImport(self, node):
264 self.generic_visit(node)
265 for name in node.names:
266 if isinstance(name, tuple):
267 self.identifiers.declared_locally.add(name[1])
268 else:
269 self.identifiers.declared_locally.add(name)
270
271 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200272 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200273 self.visit(node.node)
274 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200275
Armin Ronacherc9705c22008-04-27 21:28:03 +0200276 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200277 """Visiting stops at for blocks. However the block sequence
278 is visited as part of the outer scope.
279 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200280 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200281
Armin Ronacherc9705c22008-04-27 21:28:03 +0200282 def visit_CallBlock(self, node):
283 for child in node.iter_child_nodes(exclude=('body',)):
284 self.visit(child)
285
286 def visit_FilterBlock(self, node):
287 self.visit(node.filter)
288
289 def visit_Block(self, node):
290 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200291
292
Armin Ronacher75cfb862008-04-11 13:47:22 +0200293class CompilerExit(Exception):
294 """Raised if the compiler encountered a situation where it just
295 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200296 raises such an exception is not further processed.
297 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200298
299
Armin Ronachere791c2a2008-04-07 18:39:54 +0200300class CodeGenerator(NodeVisitor):
301
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200302 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200303 if stream is None:
304 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200305 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200306 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200307 self.filename = filename
308 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200309
Armin Ronacher023b5e92008-05-08 11:03:10 +0200310 # aliases for imports
311 self.import_aliases = {}
312
Armin Ronacherfed44b52008-04-13 19:42:53 +0200313 # a registry for all blocks. Because blocks are moved out
314 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200315 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200316
317 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200318 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200319
320 # some templates have a rootlevel extends. In this case we
321 # can safely assume that we're a child template and do some
322 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200323 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200324
Armin Ronacherba3757b2008-04-16 19:43:16 +0200325 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200326 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200327
Armin Ronacherb9e78752008-05-10 23:36:28 +0200328 # registry of all filters and tests (global, not block local)
329 self.tests = {}
330 self.filters = {}
331
Armin Ronacherba3757b2008-04-16 19:43:16 +0200332 # the debug information
333 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200334 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200335
Armin Ronacherfed44b52008-04-13 19:42:53 +0200336 # the number of new lines before the next write()
337 self._new_lines = 0
338
339 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200340 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200341
342 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200343 self._first_write = True
344
Armin Ronacherfed44b52008-04-13 19:42:53 +0200345 # used by the `temporary_identifier` method to get new
346 # unique, temporary identifier
347 self._last_identifier = 0
348
349 # the current indentation
350 self._indentation = 0
351
Armin Ronachere791c2a2008-04-07 18:39:54 +0200352 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200353 """Get a new unique identifier."""
354 self._last_identifier += 1
355 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200356
357 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200358 """Indent by one."""
359 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200360
Armin Ronacher8efc5222008-04-08 14:47:40 +0200361 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200362 """Outdent by step."""
363 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200364
Armin Ronacherc9705c22008-04-27 21:28:03 +0200365 def blockvisit(self, nodes, frame, force_generator=True):
366 """Visit a list of nodes as block in a frame. If the current frame
367 is no buffer a dummy ``if 0: yield None`` is written automatically
368 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200369 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200370 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200371 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200372 try:
373 for node in nodes:
374 self.visit(node, frame)
375 except CompilerExit:
376 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200377
378 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200379 """Write a string into the output stream."""
380 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200381 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200382 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200383 self.code_lineno += self._new_lines
384 if self._write_debug_info is not None:
385 self.debug_info.append((self._write_debug_info,
386 self.code_lineno))
387 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200388 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200389 self.stream.write(' ' * self._indentation)
390 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200391 self.stream.write(x)
392
393 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200394 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200395 self.newline(node, extra)
396 self.write(x)
397
398 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200399 """Add one or more newlines before the next write."""
400 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200401 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200402 self._write_debug_info = node.lineno
403 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200404
Armin Ronacher71082072008-04-12 14:19:36 +0200405 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200406 """Writes a function call to the stream for the current node.
407 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200408 disabled by setting have_comma to False. The extra keyword
409 arguments may not include python keywords otherwise a syntax
410 error could occour. The extra keyword arguments should be given
411 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200412 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200413 have_comma = have_comma and [True] or []
414 def touch_comma():
415 if have_comma:
416 self.write(', ')
417 else:
418 have_comma.append(True)
419
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200420 # if any of the given keyword arguments is a python keyword
421 # we have to make sure that no invalid call is created.
422 kwarg_workaround = False
423 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
424 if iskeyword(kwarg):
425 kwarg_workaround = True
426 break
427
Armin Ronacher8efc5222008-04-08 14:47:40 +0200428 for arg in node.args:
429 touch_comma()
430 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200431
432 if not kwarg_workaround:
433 for kwarg in node.kwargs:
434 touch_comma()
435 self.visit(kwarg, frame)
436 if extra_kwargs is not None:
437 for key, value in extra_kwargs.iteritems():
438 touch_comma()
439 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200440 if node.dyn_args:
441 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200442 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200443 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200444
445 if kwarg_workaround:
446 touch_comma()
447 if node.dyn_kwargs is not None:
448 self.write('**dict({')
449 else:
450 self.write('**{')
451 for kwarg in node.kwargs:
452 self.write('%r: ' % kwarg.key)
453 self.visit(kwarg.value, frame)
454 self.write(', ')
455 if extra_kwargs is not None:
456 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200457 self.write('%r: %s, ' % (key, value))
458 if node.dyn_kwargs is not None:
459 self.write('}, **')
460 self.visit(node.dyn_kwargs, frame)
461 self.write(')')
462 else:
463 self.write('}')
464
465 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200466 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200467 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200468 self.visit(node.dyn_kwargs, frame)
469
Armin Ronacherc9705c22008-04-27 21:28:03 +0200470 def pull_locals(self, frame):
471 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200472 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200473 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200474
475 def pull_dependencies(self, nodes):
476 """Pull all the dependencies."""
477 visitor = DependencyFinderVisitor()
478 for node in nodes:
479 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200480 for dependency in 'filters', 'tests':
481 mapping = getattr(self, dependency)
482 for name in getattr(visitor, dependency):
483 if name not in mapping:
484 mapping[name] = self.temporary_identifier()
485 self.writeline('%s = environment.%s[%r]' %
486 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200487
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200488 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200489 """This function returns all the shadowed variables in a dict
490 in the form name: alias and will write the required assignments
491 into the current scope. No indentation takes place.
492 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200493 # make sure we "backup" overridden, local identifiers
494 # TODO: we should probably optimize this and check if the
495 # identifier is in use afterwards.
496 aliases = {}
497 for name in frame.identifiers.find_shadowed():
498 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200499 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200500 return aliases
501
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200502 def function_scoping(self, node, frame, children=None,
503 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200504 """In Jinja a few statements require the help of anonymous
505 functions. Those are currently macros and call blocks and in
506 the future also recursive loops. As there is currently
507 technical limitation that doesn't allow reading and writing a
508 variable in a scope where the initial value is coming from an
509 outer scope, this function tries to fall back with a common
510 error message. Additionally the frame passed is modified so
511 that the argumetns are collected and callers are looked up.
512
513 This will return the modified frame.
514 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200515 # we have to iterate twice over it, make sure that works
516 if children is None:
517 children = node.iter_child_nodes()
518 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200519 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200520 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200521
522 # variables that are undeclared (accessed before declaration) and
523 # declared locally *and* part of an outside scope raise a template
524 # assertion error. Reason: we can't generate reasonable code from
525 # it without aliasing all the variables. XXX: alias them ^^
526 overriden_closure_vars = (
527 func_frame.identifiers.undeclared &
528 func_frame.identifiers.declared &
529 (func_frame.identifiers.declared_locally |
530 func_frame.identifiers.declared_parameter)
531 )
532 if overriden_closure_vars:
533 vars = ', '.join(sorted(overriden_closure_vars))
534 raise TemplateAssertionError('It\'s not possible to set and '
535 'access variables derived from '
536 'an outer scope! (affects: %s' %
Armin Ronacher68f77672008-04-17 11:50:39 +0200537 vars, node.lineno, self.name)
Armin Ronacher71082072008-04-12 14:19:36 +0200538
539 # remove variables from a closure from the frame's undeclared
540 # identifiers.
541 func_frame.identifiers.undeclared -= (
542 func_frame.identifiers.undeclared &
543 func_frame.identifiers.declared
544 )
545
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200546 # no special variables for this scope, abort early
547 if not find_special:
548 return func_frame
549
Armin Ronacher963f97d2008-04-25 11:44:59 +0200550 func_frame.accesses_kwargs = False
551 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200552 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200553 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200554
Armin Ronacherc9705c22008-04-27 21:28:03 +0200555 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
556
557 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200558 func_frame.accesses_caller = True
559 func_frame.identifiers.add_special('caller')
560 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200561 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200562 func_frame.accesses_kwargs = True
563 func_frame.identifiers.add_special('kwargs')
564 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200565 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200566 func_frame.accesses_varargs = True
567 func_frame.identifiers.add_special('varargs')
568 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200569 return func_frame
570
Armin Ronachere791c2a2008-04-07 18:39:54 +0200571 # -- Visitors
572
573 def visit_Template(self, node, frame=None):
574 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200575 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200576 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200577 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8edbe492008-04-10 20:43:43 +0200578
Armin Ronacher75cfb862008-04-11 13:47:22 +0200579 # do we have an extends tag at all? If not, we can save some
580 # overhead by just not processing any inheritance code.
581 have_extends = node.find(nodes.Extends) is not None
582
Armin Ronacher8edbe492008-04-10 20:43:43 +0200583 # find all blocks
584 for block in node.find_all(nodes.Block):
585 if block.name in self.blocks:
586 raise TemplateAssertionError('block %r defined twice' %
587 block.name, block.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200588 self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200589 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200590
Armin Ronacher023b5e92008-05-08 11:03:10 +0200591 # find all imports and import them
592 for import_ in node.find_all(nodes.ImportedName):
593 if import_.importname not in self.import_aliases:
594 imp = import_.importname
595 self.import_aliases[imp] = alias = self.temporary_identifier()
596 if '.' in imp:
597 module, obj = imp.rsplit('.', 1)
598 self.writeline('from %s import %s as %s' %
599 (module, obj, alias))
600 else:
601 self.writeline('import %s as %s' % (imp, alias))
602
603 # add the load name
604 self.writeline('name = %r' % self.name)
605
Armin Ronacher8efc5222008-04-08 14:47:40 +0200606 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200607 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200608
609 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200610 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200611 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200612 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200613 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200614 if have_extends:
615 self.writeline('parent_template = None')
616 self.pull_locals(frame)
617 self.pull_dependencies(node.body)
618 if 'self' in find_undeclared(node.body, ('self',)):
619 frame.identifiers.add_special('self')
620 self.writeline('l_self = TemplateReference(context)')
621 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200622 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200623
Armin Ronacher8efc5222008-04-08 14:47:40 +0200624 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200625 if have_extends:
626 if not self.has_known_extends:
627 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200628 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200629 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200630 self.writeline('for event in parent_template.'
631 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200632 self.indent()
633 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200634 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200635
636 # at this point we now have the blocks collected and can visit them too.
637 for name, block in self.blocks.iteritems():
638 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200639 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200640 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200641 self.writeline('def block_%s(context, environment=environment):'
642 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200643 self.indent()
644 undeclared = find_undeclared(block.body, ('self', 'super'))
645 if 'self' in undeclared:
646 block_frame.identifiers.add_special('self')
647 self.writeline('l_self = TemplateReference(context)')
648 if 'super' in undeclared:
649 block_frame.identifiers.add_special('super')
650 self.writeline('l_super = context.super(%r, '
651 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200652 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200653 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200654 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200655 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200656
Armin Ronacher75cfb862008-04-11 13:47:22 +0200657 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200658 for x in self.blocks),
659 extra=1)
660
661 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200662 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
663 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200664
Armin Ronachere791c2a2008-04-07 18:39:54 +0200665 def visit_Block(self, node, frame):
666 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200667 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200668 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200669 # if we know that we are a child template, there is no need to
670 # check if we are one
671 if self.has_known_extends:
672 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200673 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200674 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200675 self.indent()
676 level += 1
Armin Ronacherc9705c22008-04-27 21:28:03 +0200677 self.writeline('for event in context.blocks[%r][-1](context):' %
678 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200679 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200680 if frame.buffer is None:
681 self.writeline('yield event')
682 else:
683 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200684 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200685
686 def visit_Extends(self, node, frame):
687 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200688 if not frame.toplevel:
689 raise TemplateAssertionError('cannot use extend from a non '
690 'top-level scope', node.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200691 self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200692
Armin Ronacher7fb38972008-04-11 13:54:28 +0200693 # if the number of extends statements in general is zero so
694 # far, we don't have to add a check if something extended
695 # the template before this one.
696 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200697
Armin Ronacher7fb38972008-04-11 13:54:28 +0200698 # if we have a known extends we just add a template runtime
699 # error into the generated code. We could catch that at compile
700 # time too, but i welcome it not to confuse users by throwing the
701 # same error at different times just "because we can".
702 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200703 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200704 self.indent()
705 self.writeline('raise TemplateRuntimeError(%r)' %
706 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200707
Armin Ronacher7fb38972008-04-11 13:54:28 +0200708 # if we have a known extends already we don't need that code here
709 # as we know that the template execution will end here.
710 if self.has_known_extends:
711 raise CompilerExit()
712 self.outdent()
713
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200714 self.writeline('parent_template = environment.get_template(', node, 1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200715 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200716 self.write(', %r)' % self.name)
717 self.writeline('for name, parent_block in parent_template.'
718 'blocks.iteritems():')
719 self.indent()
720 self.writeline('context.blocks.setdefault(name, []).'
721 'insert(0, parent_block)')
722 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200723
724 # if this extends statement was in the root level we can take
725 # advantage of that information and simplify the generated code
726 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200727 if frame.rootlevel:
728 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200729
Armin Ronacher7fb38972008-04-11 13:54:28 +0200730 # and now we have one more
731 self.extends_so_far += 1
732
Armin Ronacherf059ec12008-04-11 22:21:00 +0200733 def visit_Include(self, node, frame):
734 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200735 if node.with_context:
736 self.writeline('template = environment.get_template(', node)
737 self.visit(node.template, frame)
738 self.write(', %r)' % self.name)
739 self.writeline('for event in template.root_render_func('
740 'template.new_context(context.parent, True)):')
741 else:
742 self.writeline('for event in environment.get_template(', node)
743 self.visit(node.template, frame)
744 self.write(', %r).module._TemplateModule__body_stream:' %
745 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200746 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200747 if frame.buffer is None:
748 self.writeline('yield event')
749 else:
750 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200751 self.outdent()
752
Armin Ronacher0611e492008-04-25 23:44:14 +0200753 def visit_Import(self, node, frame):
754 """Visit regular imports."""
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200755 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200756 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200757 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200758 self.write('environment.get_template(')
759 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200760 self.write(', %r).' % self.name)
761 if node.with_context:
762 self.write('make_module(context.parent, True)')
763 else:
764 self.write('module')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200765 if frame.toplevel and not node.target.startswith('__'):
Armin Ronacher53042292008-04-26 18:30:19 +0200766 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200767
768 def visit_FromImport(self, node, frame):
769 """Visit named imports."""
770 self.newline(node)
771 self.write('included_template = environment.get_template(')
772 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200773 self.write(', %r).' % self.name)
774 if node.with_context:
775 self.write('make_module(context.parent, True)')
776 else:
777 self.write('module')
Armin Ronacher0611e492008-04-25 23:44:14 +0200778 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200779 if isinstance(name, tuple):
780 name, alias = name
781 else:
782 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200783 self.writeline('l_%s = getattr(included_template, '
784 '%r, missing)' % (alias, name))
785 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200786 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200787 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200788 'included_template.name, '
789 'name=included_template.name)' %
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200790 (alias, 'the template %r does not export '
791 'the requested name ' + repr(name)))
Armin Ronacher0611e492008-04-25 23:44:14 +0200792 self.outdent()
793 if frame.toplevel:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200794 self.writeline('context.vars[%r] = l_%s' % (alias, alias))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200795 if not alias.startswith('__'):
796 self.writeline('context.exported_vars.discard(%r)' % alias)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200797
Armin Ronachere791c2a2008-04-07 18:39:54 +0200798 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200799 # when calculating the nodes for the inner frame we have to exclude
800 # the iterator contents from it
801 children = node.iter_child_nodes(exclude=('iter',))
802
803 if node.recursive:
804 loop_frame = self.function_scoping(node, frame, children,
805 find_special=False)
806 else:
807 loop_frame = frame.inner()
808 loop_frame.inspect(children)
809
810 extended_loop = node.recursive or node.else_ or \
Armin Ronachere791c2a2008-04-07 18:39:54 +0200811 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200812 if extended_loop:
813 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200814
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200815 # if we don't have an recursive loop we have to find the shadowed
816 # variables at that point
817 if not node.recursive:
818 aliases = self.collect_shadowed(loop_frame)
819
820 # otherwise we set up a buffer and add a function def
821 else:
822 loop_frame.buffer = buf = self.temporary_identifier()
823 self.writeline('def loop(reciter, loop_render_func):', node)
824 self.indent()
825 self.writeline('%s = []' % buf, node)
826 aliases = {}
827
Armin Ronacherc9705c22008-04-27 21:28:03 +0200828 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200829 if node.else_:
830 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200831
832 self.newline(node)
833 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200834 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200835 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200836
837 # the expression pointing to the parent loop. We make the
838 # undefined a bit more debug friendly at the same time.
839 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200840 or "environment.undefined(%r, name='loop')" % "'loop' " \
841 'is undefined. "the filter section of a loop as well ' \
842 'as the else block doesn\'t have access to the ' \
843 "special 'loop' variable of the current loop. " \
844 "Because there is no parent loop it's undefined."
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200845
846 # if we have an extened loop and a node test, we filter in the
847 # "outer frame".
848 if extended_loop and node.test is not None:
849 self.write('(')
850 self.visit(node.target, loop_frame)
851 self.write(' for ')
852 self.visit(node.target, loop_frame)
853 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200854 if node.recursive:
855 self.write('reciter')
856 else:
857 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200858 self.write(' if (')
859 test_frame = loop_frame.copy()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200860 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200861 self.visit(node.test, test_frame)
862 self.write('))')
863
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200864 elif node.recursive:
865 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200866 else:
867 self.visit(node.iter, loop_frame)
868
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200869 if node.recursive:
870 self.write(', recurse=loop_render_func):')
871 else:
872 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200873
874 # tests in not extended loops become a continue
875 if not extended_loop and node.test is not None:
876 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200877 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200878 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200879 self.write(':')
880 self.indent()
881 self.writeline('continue')
882 self.outdent(2)
883
Armin Ronacherc9705c22008-04-27 21:28:03 +0200884 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200885 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200886 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200887
888 if node.else_:
889 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200890 self.indent()
891 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher625215e2008-04-13 16:31:08 +0200892 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200893 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200894
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200895 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200896 for name, alias in aliases.iteritems():
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200897 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200898
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200899 # if the node was recursive we have to return the buffer contents
900 # and start the iteration code
901 if node.recursive:
902 if self.environment.autoescape:
903 self.writeline('return Markup(concat(%s))' % buf)
904 else:
905 self.writeline('return concat(%s)' % buf)
906 self.outdent()
907 if frame.buffer is None:
908 self.writeline('yield loop(', node)
909 else:
910 self.writeline('%s.append(loop(' % frame.buffer, node)
911 self.visit(node.iter, frame)
912 self.write(', loop)')
913 if frame.buffer is not None:
914 self.write(')')
915
Armin Ronachere791c2a2008-04-07 18:39:54 +0200916 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200917 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200918 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200919 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200920 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200921 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200922 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200923 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200924 if node.else_:
925 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200926 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200927 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200928 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200929
Armin Ronacher8efc5222008-04-08 14:47:40 +0200930 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200931 macro_frame = self.function_scoping(node, frame)
932 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200933 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200934 macro_frame.buffer = buf = self.temporary_identifier()
935 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200936 self.pull_locals(macro_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200937 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200938 self.blockvisit(node.body, macro_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200939 if self.environment.autoescape:
940 self.writeline('return Markup(concat(%s))' % buf)
941 else:
942 self.writeline("return concat(%s)" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200943 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200944 self.newline()
945 if frame.toplevel:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200946 if not node.name.startswith('__'):
947 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +0200948 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200949 arg_tuple = ', '.join(repr(x.name) for x in node.args)
950 if len(node.args) == 1:
951 arg_tuple += ','
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200952 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
953 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200954 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200955 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200956 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200957 self.write('), %s, %s, %s)' % (
958 macro_frame.accesses_kwargs and '1' or '0',
959 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200960 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200961 ))
962
963 def visit_CallBlock(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200964 call_frame = self.function_scoping(node, frame, node.iter_child_nodes
965 (exclude=('call',)))
Armin Ronacher71082072008-04-12 14:19:36 +0200966 args = call_frame.arguments
967 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200968 call_frame.buffer = buf = self.temporary_identifier()
969 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200970 self.pull_locals(call_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200971 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200972 self.blockvisit(node.body, call_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200973 if self.environment.autoescape:
974 self.writeline("return Markup(concat(%s))" % buf)
975 else:
976 self.writeline('return concat(%s)' % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200977 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200978 arg_tuple = ', '.join(repr(x.name) for x in node.args)
979 if len(node.args) == 1:
980 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200981 self.writeline('caller = Macro(environment, call, None, (%s), (' %
982 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200983 for arg in node.defaults:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200984 self.visit(arg, call_frame)
Armin Ronacher71082072008-04-12 14:19:36 +0200985 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200986 self.write('), %s, %s, 0)' % (
987 call_frame.accesses_kwargs and '1' or '0',
988 call_frame.accesses_varargs and '1' or '0'
989 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200990 if frame.buffer is None:
991 self.writeline('yield ', node)
992 else:
993 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200994 self.visit_Call(node.call, call_frame,
995 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200996 if frame.buffer is not None:
997 self.write(')')
998
999 def visit_FilterBlock(self, node, frame):
1000 filter_frame = frame.inner()
1001 filter_frame.inspect(node.iter_child_nodes())
1002
1003 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001004 self.pull_locals(filter_frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001005 filter_frame.buffer = buf = self.temporary_identifier()
1006
1007 self.writeline('%s = []' % buf, node)
1008 for child in node.body:
1009 self.visit(child, filter_frame)
1010
1011 if frame.buffer is None:
1012 self.writeline('yield ', node)
1013 else:
1014 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacherde6bf712008-04-26 01:44:14 +02001015 self.visit_Filter(node.filter, filter_frame, 'concat(%s)' % buf)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001016 if frame.buffer is not None:
1017 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001018
Armin Ronachere791c2a2008-04-07 18:39:54 +02001019 def visit_ExprStmt(self, node, frame):
1020 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001021 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001022
1023 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001024 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +02001025 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001026 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001027
Armin Ronacher75cfb862008-04-11 13:47:22 +02001028 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001029
Armin Ronacher7fb38972008-04-11 13:54:28 +02001030 # if we are in the toplevel scope and there was already an extends
1031 # statement we have to add a check that disables our yield(s) here
1032 # so that they don't appear in the output.
1033 outdent_later = False
1034 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001035 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001036 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001037 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001038
Armin Ronachere791c2a2008-04-07 18:39:54 +02001039 # try to evaluate as many chunks as possible into a static
1040 # string at compile time.
1041 body = []
1042 for child in node.nodes:
1043 try:
1044 const = unicode(child.as_const())
1045 except:
1046 body.append(child)
1047 continue
1048 if body and isinstance(body[-1], list):
1049 body[-1].append(const)
1050 else:
1051 body.append([const])
1052
Armin Ronacher32a910f2008-04-26 23:21:03 +02001053 # if we have less than 3 nodes or less than 6 and a buffer we
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001054 # yield or extend/append
Armin Ronacher32a910f2008-04-26 23:21:03 +02001055 if len(body) < 3 or (frame.buffer is not None and len(body) < 6):
1056 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001057 # for one item we append, for more we extend
1058 if len(body) == 1:
1059 self.writeline('%s.append(' % frame.buffer)
1060 else:
1061 self.writeline('%s.extend((' % frame.buffer)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001062 for item in body:
1063 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001064 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001065 if frame.buffer is None:
1066 self.writeline('yield ' + val)
1067 else:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001068 self.write(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001069 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001070 if frame.buffer is None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001071 self.writeline('yield ')
Armin Ronacherd1342312008-04-28 12:20:12 +02001072 close = 1
1073 if self.environment.autoescape:
1074 self.write('escape(')
1075 else:
1076 self.write('unicode(')
1077 if self.environment.finalize is not None:
1078 self.write('environment.finalize(')
1079 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001080 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001081 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001082 if frame.buffer is not None:
1083 self.write(', ')
1084 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001085 # close the open parentheses
1086 self.write(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001087
1088 # otherwise we create a format string as this is faster in that case
1089 else:
1090 format = []
1091 arguments = []
1092 for item in body:
1093 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001094 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001095 else:
1096 format.append('%s')
1097 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001098 if frame.buffer is None:
1099 self.writeline('yield ')
1100 else:
1101 self.writeline('%s.append(' % frame.buffer)
Armin Ronacherde6bf712008-04-26 01:44:14 +02001102 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001103 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001104 self.indent()
1105 for argument in arguments:
1106 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001107 close = 0
1108 if self.environment.autoescape:
1109 self.write('escape(')
1110 close += 1
1111 if self.environment.finalize is not None:
1112 self.write('environment.finalize(')
1113 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001114 self.visit(argument, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001115 self.write(')' * close + ',')
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001116 self.outdent()
1117 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001118 if frame.buffer is not None:
1119 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001120
Armin Ronacher7fb38972008-04-11 13:54:28 +02001121 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001122 self.outdent()
1123
Armin Ronacher8efc5222008-04-08 14:47:40 +02001124 def visit_Assign(self, node, frame):
1125 self.newline(node)
1126 # toplevel assignments however go into the local namespace and
1127 # the current template's context. We create a copy of the frame
1128 # here and add a set so that the Name visitor can add the assigned
1129 # names here.
1130 if frame.toplevel:
1131 assignment_frame = frame.copy()
1132 assignment_frame.assigned_names = set()
1133 else:
1134 assignment_frame = frame
1135 self.visit(node.target, assignment_frame)
1136 self.write(' = ')
1137 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001138
1139 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001140 if frame.toplevel:
1141 for name in assignment_frame.assigned_names:
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001142 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +02001143 if not name.startswith('__'):
1144 self.writeline('context.exported_vars.add(%r)' % name)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001145
Armin Ronachere791c2a2008-04-07 18:39:54 +02001146 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001147 if node.ctx == 'store' and frame.toplevel:
1148 frame.assigned_names.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001149 self.write('l_' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001150
Armin Ronacherd84ec462008-04-29 13:43:16 +02001151 def visit_MarkSafe(self, node, frame):
1152 self.write('Markup(')
1153 self.visit(node.expr, frame)
1154 self.write(')')
1155
Armin Ronacher023b5e92008-05-08 11:03:10 +02001156 def visit_EnvironmentAttribute(self, node, frame):
1157 self.write('environment.' + node.name)
1158
1159 def visit_ExtensionAttribute(self, node, frame):
1160 self.write('environment.extensions[%r].%s' % (node.identifier, node.attr))
1161
1162 def visit_ImportedName(self, node, frame):
1163 self.write(self.import_aliases[node.importname])
1164
1165 def visit_InternalName(self, node, frame):
1166 self.write(node.name)
1167
Armin Ronachere791c2a2008-04-07 18:39:54 +02001168 def visit_Const(self, node, frame):
1169 val = node.value
1170 if isinstance(val, float):
1171 # XXX: add checks for infinity and nan
1172 self.write(str(val))
1173 else:
1174 self.write(repr(val))
1175
Armin Ronacher8efc5222008-04-08 14:47:40 +02001176 def visit_Tuple(self, node, frame):
1177 self.write('(')
1178 idx = -1
1179 for idx, item in enumerate(node.items):
1180 if idx:
1181 self.write(', ')
1182 self.visit(item, frame)
1183 self.write(idx == 0 and ',)' or ')')
1184
Armin Ronacher8edbe492008-04-10 20:43:43 +02001185 def visit_List(self, node, frame):
1186 self.write('[')
1187 for idx, item in enumerate(node.items):
1188 if idx:
1189 self.write(', ')
1190 self.visit(item, frame)
1191 self.write(']')
1192
1193 def visit_Dict(self, node, frame):
1194 self.write('{')
1195 for idx, item in enumerate(node.items):
1196 if idx:
1197 self.write(', ')
1198 self.visit(item.key, frame)
1199 self.write(': ')
1200 self.visit(item.value, frame)
1201 self.write('}')
1202
Armin Ronachere791c2a2008-04-07 18:39:54 +02001203 def binop(operator):
1204 def visitor(self, node, frame):
1205 self.write('(')
1206 self.visit(node.left, frame)
1207 self.write(' %s ' % operator)
1208 self.visit(node.right, frame)
1209 self.write(')')
1210 return visitor
1211
1212 def uaop(operator):
1213 def visitor(self, node, frame):
1214 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001215 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001216 self.write(')')
1217 return visitor
1218
1219 visit_Add = binop('+')
1220 visit_Sub = binop('-')
1221 visit_Mul = binop('*')
1222 visit_Div = binop('/')
1223 visit_FloorDiv = binop('//')
1224 visit_Pow = binop('**')
1225 visit_Mod = binop('%')
1226 visit_And = binop('and')
1227 visit_Or = binop('or')
1228 visit_Pos = uaop('+')
1229 visit_Neg = uaop('-')
1230 visit_Not = uaop('not ')
1231 del binop, uaop
1232
Armin Ronacherd1342312008-04-28 12:20:12 +02001233 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001234 self.write('%s((' % (self.environment.autoescape and
1235 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001236 for arg in node.nodes:
1237 self.visit(arg, frame)
1238 self.write(', ')
1239 self.write('))')
1240
Armin Ronachere791c2a2008-04-07 18:39:54 +02001241 def visit_Compare(self, node, frame):
1242 self.visit(node.expr, frame)
1243 for op in node.ops:
1244 self.visit(op, frame)
1245
1246 def visit_Operand(self, node, frame):
1247 self.write(' %s ' % operators[node.op])
1248 self.visit(node.expr, frame)
1249
1250 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001251 if isinstance(node.arg, nodes.Slice):
1252 self.visit(node.node, frame)
1253 self.write('[')
1254 self.visit(node.arg, frame)
1255 self.write(']')
1256 return
1257 try:
1258 const = node.arg.as_const()
1259 have_const = True
1260 except nodes.Impossible:
1261 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001262 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001263 self.visit(node.node, frame)
1264 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001265 if have_const:
1266 self.write(repr(const))
1267 else:
1268 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001269 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001270
1271 def visit_Slice(self, node, frame):
1272 if node.start is not None:
1273 self.visit(node.start, frame)
1274 self.write(':')
1275 if node.stop is not None:
1276 self.visit(node.stop, frame)
1277 if node.step is not None:
1278 self.write(':')
1279 self.visit(node.step, frame)
1280
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001281 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001282 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001283 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001284 if func is None:
1285 raise TemplateAssertionError('no filter named %r' % node.name,
1286 node.lineno, self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001287 if getattr(func, 'contextfilter', False):
1288 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001289 elif getattr(func, 'environmentfilter', False):
1290 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001291 if isinstance(node.node, nodes.Filter):
1292 self.visit_Filter(node.node, frame, initial)
1293 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001294 self.write(initial)
1295 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001296 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001297 self.signature(node, frame)
1298 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001299
1300 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001301 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001302 if node.name not in self.environment.tests:
1303 raise TemplateAssertionError('no test named %r' % node.name,
1304 node.lineno, self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001305 self.visit(node.node, frame)
1306 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001307 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001308
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001309 def visit_CondExpr(self, node, frame):
1310 if not have_condexpr:
1311 self.write('((')
1312 self.visit(node.test, frame)
1313 self.write(') and (')
1314 self.visit(node.expr1, frame)
1315 self.write(',) or (')
1316 self.visit(node.expr2, frame)
1317 self.write(',))[0]')
1318 else:
1319 self.write('(')
1320 self.visit(node.expr1, frame)
1321 self.write(' if ')
1322 self.visit(node.test, frame)
1323 self.write(' else ')
1324 self.visit(node.expr2, frame)
1325 self.write(')')
1326
Armin Ronacher71082072008-04-12 14:19:36 +02001327 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001328 if self.environment.sandboxed:
1329 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001330 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001331 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001332 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001333 self.write(')')
1334
1335 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001336 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001337 self.visit(node.value, frame)