blob: cb0da5a1f030408fa4329a3097516a2dfd04a087 [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 Ronacher69e12db2008-05-12 09:00:03 +020046 node.freeze()
Armin Ronacher8e8d0712008-04-16 23:10:49 +020047 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020048 generator.visit(node)
49 if stream is None:
50 return generator.stream.getvalue()
51
52
Armin Ronacher4dfc9752008-04-09 15:03:29 +020053def has_safe_repr(value):
54 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020055 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020056 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020057 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher32a910f2008-04-26 23:21:03 +020058 xrange, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020059 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020060 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020061 for item in value:
62 if not has_safe_repr(item):
63 return False
64 return True
65 elif isinstance(value, dict):
66 for key, value in value.iteritems():
67 if not has_safe_repr(key):
68 return False
69 if not has_safe_repr(value):
70 return False
71 return True
72 return False
73
74
Armin Ronacherc9705c22008-04-27 21:28:03 +020075def find_undeclared(nodes, names):
76 """Check if the names passed are accessed undeclared. The return value
77 is a set of all the undeclared names from the sequence of names found.
78 """
79 visitor = UndeclaredNameVisitor(names)
80 try:
81 for node in nodes:
82 visitor.visit(node)
83 except VisitorExit:
84 pass
85 return visitor.undeclared
86
87
Armin Ronachere791c2a2008-04-07 18:39:54 +020088class Identifiers(object):
89 """Tracks the status of identifiers in frames."""
90
91 def __init__(self):
92 # variables that are known to be declared (probably from outer
93 # frames or because they are special for the frame)
94 self.declared = set()
95
Armin Ronacher10f3ba22008-04-18 11:30:37 +020096 # undeclared variables from outer scopes
97 self.outer_undeclared = set()
98
Armin Ronachere791c2a2008-04-07 18:39:54 +020099 # names that are accessed without being explicitly declared by
100 # this one or any of the outer scopes. Names can appear both in
101 # declared and undeclared.
102 self.undeclared = set()
103
104 # names that are declared locally
105 self.declared_locally = set()
106
107 # names that are declared by parameters
108 self.declared_parameter = set()
109
110 def add_special(self, name):
111 """Register a special name like `loop`."""
112 self.undeclared.discard(name)
113 self.declared.add(name)
114
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200115 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200116 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200117 if name in self.declared_locally or name in self.declared_parameter:
118 return True
119 if local_only:
120 return False
121 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200122
123 def find_shadowed(self):
124 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200125 return (self.declared | self.outer_undeclared) & \
126 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200127
128
129class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200130 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200131
132 def __init__(self, parent=None):
133 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200134
Armin Ronacher75cfb862008-04-11 13:47:22 +0200135 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200136 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200137
Armin Ronacher75cfb862008-04-11 13:47:22 +0200138 # the root frame is basically just the outermost frame, so no if
139 # conditions. This information is used to optimize inheritance
140 # situations.
141 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200142
143 # inside some tags we are using a buffer rather than yield statements.
144 # this for example affects {% filter %} or {% macro %}. If a frame
145 # is buffered this variable points to the name of the list used as
146 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200147 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200148
Armin Ronacherfed44b52008-04-13 19:42:53 +0200149 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200150 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200151
152 # the parent of this frame
153 self.parent = parent
154
Armin Ronachere791c2a2008-04-07 18:39:54 +0200155 if parent is not None:
156 self.identifiers.declared.update(
157 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200158 parent.identifiers.declared_locally |
159 parent.identifiers.declared_parameter
160 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200161 self.identifiers.outer_undeclared.update(
162 parent.identifiers.undeclared -
163 self.identifiers.declared
164 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200165 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200166
Armin Ronacher8efc5222008-04-08 14:47:40 +0200167 def copy(self):
168 """Create a copy of the current one."""
169 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200170 rv.identifiers = copy(self.identifiers)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200171 return rv
172
Armin Ronacherc9705c22008-04-27 21:28:03 +0200173 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200174 """Walk the node and check for identifiers. If the scope is hard (eg:
175 enforce on a python level) overrides from outer scopes are tracked
176 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200177 """
178 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200179 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200180 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200181
182 def inner(self):
183 """Return an inner frame."""
184 return Frame(self)
185
Armin Ronacher75cfb862008-04-11 13:47:22 +0200186 def soft(self):
187 """Return a soft frame. A soft frame may not be modified as
188 standalone thing as it shares the resources with the frame it
189 was created of, but it's not a rootlevel frame any longer.
190 """
191 rv = copy(self)
192 rv.rootlevel = False
193 return rv
194
Armin Ronachere791c2a2008-04-07 18:39:54 +0200195
Armin Ronacherc9705c22008-04-27 21:28:03 +0200196class VisitorExit(RuntimeError):
197 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
198
199
200class DependencyFinderVisitor(NodeVisitor):
201 """A visitor that collects filter and test calls."""
202
203 def __init__(self):
204 self.filters = set()
205 self.tests = set()
206
207 def visit_Filter(self, node):
208 self.generic_visit(node)
209 self.filters.add(node.name)
210
211 def visit_Test(self, node):
212 self.generic_visit(node)
213 self.tests.add(node.name)
214
215 def visit_Block(self, node):
216 """Stop visiting at blocks."""
217
218
219class UndeclaredNameVisitor(NodeVisitor):
220 """A visitor that checks if a name is accessed without being
221 declared. This is different from the frame visitor as it will
222 not stop at closure frames.
223 """
224
225 def __init__(self, names):
226 self.names = set(names)
227 self.undeclared = set()
228
229 def visit_Name(self, node):
230 if node.ctx == 'load' and node.name in self.names:
231 self.undeclared.add(node.name)
232 if self.undeclared == self.names:
233 raise VisitorExit()
234 else:
235 self.names.discard(node.name)
236
237 def visit_Block(self, node):
238 """Stop visiting a blocks."""
239
240
Armin Ronachere791c2a2008-04-07 18:39:54 +0200241class FrameIdentifierVisitor(NodeVisitor):
242 """A visitor for `Frame.inspect`."""
243
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200244 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200245 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200246 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200247
Armin Ronacherc9705c22008-04-27 21:28:03 +0200248 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200249 """All assignments to names go through this function."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200250 if node.ctx in ('store', 'param'):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200251 self.identifiers.declared_locally.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200252 elif node.ctx == 'load' and not \
253 self.identifiers.is_declared(node.name, self.hard_scope):
254 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200255
Armin Ronacherc9705c22008-04-27 21:28:03 +0200256 def visit_Macro(self, node):
257 self.generic_visit(node)
258 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200259
Armin Ronacherc9705c22008-04-27 21:28:03 +0200260 def visit_Import(self, node):
261 self.generic_visit(node)
262 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200263
Armin Ronacherc9705c22008-04-27 21:28:03 +0200264 def visit_FromImport(self, node):
265 self.generic_visit(node)
266 for name in node.names:
267 if isinstance(name, tuple):
268 self.identifiers.declared_locally.add(name[1])
269 else:
270 self.identifiers.declared_locally.add(name)
271
272 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200273 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200274 self.visit(node.node)
275 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200276
Armin Ronacherc9705c22008-04-27 21:28:03 +0200277 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200278 """Visiting stops at for blocks. However the block sequence
279 is visited as part of the outer scope.
280 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200281 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200282
Armin Ronacherc9705c22008-04-27 21:28:03 +0200283 def visit_CallBlock(self, node):
284 for child in node.iter_child_nodes(exclude=('body',)):
285 self.visit(child)
286
287 def visit_FilterBlock(self, node):
288 self.visit(node.filter)
289
290 def visit_Block(self, node):
291 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200292
293
Armin Ronacher75cfb862008-04-11 13:47:22 +0200294class CompilerExit(Exception):
295 """Raised if the compiler encountered a situation where it just
296 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200297 raises such an exception is not further processed.
298 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200299
300
Armin Ronachere791c2a2008-04-07 18:39:54 +0200301class CodeGenerator(NodeVisitor):
302
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200303 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200304 if stream is None:
305 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200306 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200307 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200308 self.filename = filename
309 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200310
Armin Ronacher023b5e92008-05-08 11:03:10 +0200311 # aliases for imports
312 self.import_aliases = {}
313
Armin Ronacherfed44b52008-04-13 19:42:53 +0200314 # a registry for all blocks. Because blocks are moved out
315 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200316 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200317
318 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200319 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200320
321 # some templates have a rootlevel extends. In this case we
322 # can safely assume that we're a child template and do some
323 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200324 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200325
Armin Ronacherba3757b2008-04-16 19:43:16 +0200326 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200327 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200328
Armin Ronacherb9e78752008-05-10 23:36:28 +0200329 # registry of all filters and tests (global, not block local)
330 self.tests = {}
331 self.filters = {}
332
Armin Ronacherba3757b2008-04-16 19:43:16 +0200333 # the debug information
334 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200335 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200336
Armin Ronacherfed44b52008-04-13 19:42:53 +0200337 # the number of new lines before the next write()
338 self._new_lines = 0
339
340 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200341 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200342
343 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200344 self._first_write = True
345
Armin Ronacherfed44b52008-04-13 19:42:53 +0200346 # used by the `temporary_identifier` method to get new
347 # unique, temporary identifier
348 self._last_identifier = 0
349
350 # the current indentation
351 self._indentation = 0
352
Armin Ronachere791c2a2008-04-07 18:39:54 +0200353 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200354 """Get a new unique identifier."""
355 self._last_identifier += 1
356 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200357
358 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200359 """Indent by one."""
360 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200361
Armin Ronacher8efc5222008-04-08 14:47:40 +0200362 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200363 """Outdent by step."""
364 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200365
Armin Ronacherc9705c22008-04-27 21:28:03 +0200366 def blockvisit(self, nodes, frame, force_generator=True):
367 """Visit a list of nodes as block in a frame. If the current frame
368 is no buffer a dummy ``if 0: yield None`` is written automatically
369 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200370 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200371 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200372 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200373 try:
374 for node in nodes:
375 self.visit(node, frame)
376 except CompilerExit:
377 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200378
379 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200380 """Write a string into the output stream."""
381 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200382 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200383 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200384 self.code_lineno += self._new_lines
385 if self._write_debug_info is not None:
386 self.debug_info.append((self._write_debug_info,
387 self.code_lineno))
388 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200389 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200390 self.stream.write(' ' * self._indentation)
391 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200392 self.stream.write(x)
393
394 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200395 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200396 self.newline(node, extra)
397 self.write(x)
398
399 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200400 """Add one or more newlines before the next write."""
401 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200402 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200403 self._write_debug_info = node.lineno
404 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200405
Armin Ronacher71082072008-04-12 14:19:36 +0200406 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200407 """Writes a function call to the stream for the current node.
408 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200409 disabled by setting have_comma to False. The extra keyword
410 arguments may not include python keywords otherwise a syntax
411 error could occour. The extra keyword arguments should be given
412 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200413 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200414 have_comma = have_comma and [True] or []
415 def touch_comma():
416 if have_comma:
417 self.write(', ')
418 else:
419 have_comma.append(True)
420
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200421 # if any of the given keyword arguments is a python keyword
422 # we have to make sure that no invalid call is created.
423 kwarg_workaround = False
424 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
425 if iskeyword(kwarg):
426 kwarg_workaround = True
427 break
428
Armin Ronacher8efc5222008-04-08 14:47:40 +0200429 for arg in node.args:
430 touch_comma()
431 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200432
433 if not kwarg_workaround:
434 for kwarg in node.kwargs:
435 touch_comma()
436 self.visit(kwarg, frame)
437 if extra_kwargs is not None:
438 for key, value in extra_kwargs.iteritems():
439 touch_comma()
440 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200441 if node.dyn_args:
442 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200443 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200444 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200445
446 if kwarg_workaround:
447 touch_comma()
448 if node.dyn_kwargs is not None:
449 self.write('**dict({')
450 else:
451 self.write('**{')
452 for kwarg in node.kwargs:
453 self.write('%r: ' % kwarg.key)
454 self.visit(kwarg.value, frame)
455 self.write(', ')
456 if extra_kwargs is not None:
457 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200458 self.write('%r: %s, ' % (key, value))
459 if node.dyn_kwargs is not None:
460 self.write('}, **')
461 self.visit(node.dyn_kwargs, frame)
462 self.write(')')
463 else:
464 self.write('}')
465
466 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200467 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200468 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200469 self.visit(node.dyn_kwargs, frame)
470
Armin Ronacherc9705c22008-04-27 21:28:03 +0200471 def pull_locals(self, frame):
472 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200473 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200474 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200475
476 def pull_dependencies(self, nodes):
477 """Pull all the dependencies."""
478 visitor = DependencyFinderVisitor()
479 for node in nodes:
480 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200481 for dependency in 'filters', 'tests':
482 mapping = getattr(self, dependency)
483 for name in getattr(visitor, dependency):
484 if name not in mapping:
485 mapping[name] = self.temporary_identifier()
486 self.writeline('%s = environment.%s[%r]' %
487 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200488
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200489 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200490 """This function returns all the shadowed variables in a dict
491 in the form name: alias and will write the required assignments
492 into the current scope. No indentation takes place.
493 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200494 # make sure we "backup" overridden, local identifiers
495 # TODO: we should probably optimize this and check if the
496 # identifier is in use afterwards.
497 aliases = {}
498 for name in frame.identifiers.find_shadowed():
499 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200500 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200501 return aliases
502
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200503 def function_scoping(self, node, frame, children=None,
504 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200505 """In Jinja a few statements require the help of anonymous
506 functions. Those are currently macros and call blocks and in
507 the future also recursive loops. As there is currently
508 technical limitation that doesn't allow reading and writing a
509 variable in a scope where the initial value is coming from an
510 outer scope, this function tries to fall back with a common
511 error message. Additionally the frame passed is modified so
512 that the argumetns are collected and callers are looked up.
513
514 This will return the modified frame.
515 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200516 # we have to iterate twice over it, make sure that works
517 if children is None:
518 children = node.iter_child_nodes()
519 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200520 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200521 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200522
523 # variables that are undeclared (accessed before declaration) and
524 # declared locally *and* part of an outside scope raise a template
525 # assertion error. Reason: we can't generate reasonable code from
526 # it without aliasing all the variables. XXX: alias them ^^
527 overriden_closure_vars = (
528 func_frame.identifiers.undeclared &
529 func_frame.identifiers.declared &
530 (func_frame.identifiers.declared_locally |
531 func_frame.identifiers.declared_parameter)
532 )
533 if overriden_closure_vars:
534 vars = ', '.join(sorted(overriden_closure_vars))
535 raise TemplateAssertionError('It\'s not possible to set and '
536 'access variables derived from '
537 'an outer scope! (affects: %s' %
Armin Ronacher66a93442008-05-11 23:42:19 +0200538 vars, node.lineno, self.filename)
Armin Ronacher71082072008-04-12 14:19:36 +0200539
540 # remove variables from a closure from the frame's undeclared
541 # identifiers.
542 func_frame.identifiers.undeclared -= (
543 func_frame.identifiers.undeclared &
544 func_frame.identifiers.declared
545 )
546
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200547 # no special variables for this scope, abort early
548 if not find_special:
549 return func_frame
550
Armin Ronacher963f97d2008-04-25 11:44:59 +0200551 func_frame.accesses_kwargs = False
552 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200553 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200554 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200555
Armin Ronacherc9705c22008-04-27 21:28:03 +0200556 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
557
558 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200559 func_frame.accesses_caller = True
560 func_frame.identifiers.add_special('caller')
561 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200562 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200563 func_frame.accesses_kwargs = True
564 func_frame.identifiers.add_special('kwargs')
565 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200566 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200567 func_frame.accesses_varargs = True
568 func_frame.identifiers.add_special('varargs')
569 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200570 return func_frame
571
Armin Ronachere791c2a2008-04-07 18:39:54 +0200572 # -- Visitors
573
574 def visit_Template(self, node, frame=None):
575 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200576 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200577 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200578 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8edbe492008-04-10 20:43:43 +0200579
Armin Ronacher75cfb862008-04-11 13:47:22 +0200580 # do we have an extends tag at all? If not, we can save some
581 # overhead by just not processing any inheritance code.
582 have_extends = node.find(nodes.Extends) is not None
583
Armin Ronacher8edbe492008-04-10 20:43:43 +0200584 # find all blocks
585 for block in node.find_all(nodes.Block):
586 if block.name in self.blocks:
587 raise TemplateAssertionError('block %r defined twice' %
588 block.name, block.lineno,
Armin Ronacher66a93442008-05-11 23:42:19 +0200589 self.filename)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200590 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200591
Armin Ronacher023b5e92008-05-08 11:03:10 +0200592 # find all imports and import them
593 for import_ in node.find_all(nodes.ImportedName):
594 if import_.importname not in self.import_aliases:
595 imp = import_.importname
596 self.import_aliases[imp] = alias = self.temporary_identifier()
597 if '.' in imp:
598 module, obj = imp.rsplit('.', 1)
599 self.writeline('from %s import %s as %s' %
600 (module, obj, alias))
601 else:
602 self.writeline('import %s as %s' % (imp, alias))
603
604 # add the load name
Armin Ronacher66a93442008-05-11 23:42:19 +0200605 self.writeline('name = %r' % self.filename)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200606
Armin Ronacher8efc5222008-04-08 14:47:40 +0200607 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200608 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200609
610 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200611 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200612 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200613 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200614 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200615 if have_extends:
616 self.writeline('parent_template = None')
617 self.pull_locals(frame)
618 self.pull_dependencies(node.body)
619 if 'self' in find_undeclared(node.body, ('self',)):
620 frame.identifiers.add_special('self')
621 self.writeline('l_self = TemplateReference(context)')
622 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200623 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200624
Armin Ronacher8efc5222008-04-08 14:47:40 +0200625 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200626 if have_extends:
627 if not self.has_known_extends:
628 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200629 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200630 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200631 self.writeline('for event in parent_template.'
632 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200633 self.indent()
634 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200635 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200636
637 # at this point we now have the blocks collected and can visit them too.
638 for name, block in self.blocks.iteritems():
639 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200640 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200641 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200642 self.writeline('def block_%s(context, environment=environment):'
643 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200644 self.indent()
645 undeclared = find_undeclared(block.body, ('self', 'super'))
646 if 'self' in undeclared:
647 block_frame.identifiers.add_special('self')
648 self.writeline('l_self = TemplateReference(context)')
649 if 'super' in undeclared:
650 block_frame.identifiers.add_special('super')
651 self.writeline('l_super = context.super(%r, '
652 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200653 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200654 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200655 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200656 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200657
Armin Ronacher75cfb862008-04-11 13:47:22 +0200658 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200659 for x in self.blocks),
660 extra=1)
661
662 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200663 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
664 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200665
Armin Ronachere791c2a2008-04-07 18:39:54 +0200666 def visit_Block(self, node, frame):
667 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200668 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200669 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200670 # if we know that we are a child template, there is no need to
671 # check if we are one
672 if self.has_known_extends:
673 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200674 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200675 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200676 self.indent()
677 level += 1
Armin Ronacherc9705c22008-04-27 21:28:03 +0200678 self.writeline('for event in context.blocks[%r][-1](context):' %
679 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200680 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200681 if frame.buffer is None:
682 self.writeline('yield event')
683 else:
684 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200685 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200686
687 def visit_Extends(self, node, frame):
688 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200689 if not frame.toplevel:
690 raise TemplateAssertionError('cannot use extend from a non '
691 'top-level scope', node.lineno,
Armin Ronacher66a93442008-05-11 23:42:19 +0200692 self.filename)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200693
Armin Ronacher7fb38972008-04-11 13:54:28 +0200694 # if the number of extends statements in general is zero so
695 # far, we don't have to add a check if something extended
696 # the template before this one.
697 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200698
Armin Ronacher7fb38972008-04-11 13:54:28 +0200699 # if we have a known extends we just add a template runtime
700 # error into the generated code. We could catch that at compile
701 # time too, but i welcome it not to confuse users by throwing the
702 # same error at different times just "because we can".
703 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200704 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200705 self.indent()
706 self.writeline('raise TemplateRuntimeError(%r)' %
707 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200708
Armin Ronacher7fb38972008-04-11 13:54:28 +0200709 # if we have a known extends already we don't need that code here
710 # as we know that the template execution will end here.
711 if self.has_known_extends:
712 raise CompilerExit()
713 self.outdent()
714
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200715 self.writeline('parent_template = environment.get_template(', node, 1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200716 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200717 self.write(', %r)' % self.name)
718 self.writeline('for name, parent_block in parent_template.'
719 'blocks.iteritems():')
720 self.indent()
721 self.writeline('context.blocks.setdefault(name, []).'
722 'insert(0, parent_block)')
723 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200724
725 # if this extends statement was in the root level we can take
726 # advantage of that information and simplify the generated code
727 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200728 if frame.rootlevel:
729 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200730
Armin Ronacher7fb38972008-04-11 13:54:28 +0200731 # and now we have one more
732 self.extends_so_far += 1
733
Armin Ronacherf059ec12008-04-11 22:21:00 +0200734 def visit_Include(self, node, frame):
735 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200736 if node.with_context:
737 self.writeline('template = environment.get_template(', node)
738 self.visit(node.template, frame)
739 self.write(', %r)' % self.name)
740 self.writeline('for event in template.root_render_func('
741 'template.new_context(context.parent, True)):')
742 else:
743 self.writeline('for event in environment.get_template(', node)
744 self.visit(node.template, frame)
745 self.write(', %r).module._TemplateModule__body_stream:' %
746 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200747 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200748 if frame.buffer is None:
749 self.writeline('yield event')
750 else:
751 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200752 self.outdent()
753
Armin Ronacher0611e492008-04-25 23:44:14 +0200754 def visit_Import(self, node, frame):
755 """Visit regular imports."""
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200756 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200757 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200758 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200759 self.write('environment.get_template(')
760 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200761 self.write(', %r).' % self.name)
762 if node.with_context:
763 self.write('make_module(context.parent, True)')
764 else:
765 self.write('module')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200766 if frame.toplevel and not node.target.startswith('__'):
Armin Ronacher53042292008-04-26 18:30:19 +0200767 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200768
769 def visit_FromImport(self, node, frame):
770 """Visit named imports."""
771 self.newline(node)
772 self.write('included_template = environment.get_template(')
773 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200774 self.write(', %r).' % self.name)
775 if node.with_context:
776 self.write('make_module(context.parent, True)')
777 else:
778 self.write('module')
Armin Ronacher0611e492008-04-25 23:44:14 +0200779 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200780 if isinstance(name, tuple):
781 name, alias = name
782 else:
783 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200784 self.writeline('l_%s = getattr(included_template, '
785 '%r, missing)' % (alias, name))
786 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200787 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200788 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200789 'included_template.name, '
790 'name=included_template.name)' %
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200791 (alias, 'the template %r does not export '
792 'the requested name ' + repr(name)))
Armin Ronacher0611e492008-04-25 23:44:14 +0200793 self.outdent()
794 if frame.toplevel:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200795 self.writeline('context.vars[%r] = l_%s' % (alias, alias))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200796 if not alias.startswith('__'):
797 self.writeline('context.exported_vars.discard(%r)' % alias)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200798
Armin Ronachere791c2a2008-04-07 18:39:54 +0200799 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200800 # when calculating the nodes for the inner frame we have to exclude
801 # the iterator contents from it
802 children = node.iter_child_nodes(exclude=('iter',))
803
804 if node.recursive:
805 loop_frame = self.function_scoping(node, frame, children,
806 find_special=False)
807 else:
808 loop_frame = frame.inner()
809 loop_frame.inspect(children)
810
811 extended_loop = node.recursive or node.else_ or \
Armin Ronachere791c2a2008-04-07 18:39:54 +0200812 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200813 if extended_loop:
814 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200815
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200816 # if we don't have an recursive loop we have to find the shadowed
817 # variables at that point
818 if not node.recursive:
819 aliases = self.collect_shadowed(loop_frame)
820
821 # otherwise we set up a buffer and add a function def
822 else:
823 loop_frame.buffer = buf = self.temporary_identifier()
824 self.writeline('def loop(reciter, loop_render_func):', node)
825 self.indent()
826 self.writeline('%s = []' % buf, node)
827 aliases = {}
828
Armin Ronacherc9705c22008-04-27 21:28:03 +0200829 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200830 if node.else_:
831 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200832
833 self.newline(node)
834 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200835 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200836 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200837
838 # the expression pointing to the parent loop. We make the
839 # undefined a bit more debug friendly at the same time.
840 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200841 or "environment.undefined(%r, name='loop')" % "'loop' " \
842 'is undefined. "the filter section of a loop as well ' \
843 'as the else block doesn\'t have access to the ' \
844 "special 'loop' variable of the current loop. " \
845 "Because there is no parent loop it's undefined."
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200846
847 # if we have an extened loop and a node test, we filter in the
848 # "outer frame".
849 if extended_loop and node.test is not None:
850 self.write('(')
851 self.visit(node.target, loop_frame)
852 self.write(' for ')
853 self.visit(node.target, loop_frame)
854 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200855 if node.recursive:
856 self.write('reciter')
857 else:
858 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200859 self.write(' if (')
860 test_frame = loop_frame.copy()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200861 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200862 self.visit(node.test, test_frame)
863 self.write('))')
864
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200865 elif node.recursive:
866 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200867 else:
868 self.visit(node.iter, loop_frame)
869
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200870 if node.recursive:
871 self.write(', recurse=loop_render_func):')
872 else:
873 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200874
875 # tests in not extended loops become a continue
876 if not extended_loop and node.test is not None:
877 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200878 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200879 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200880 self.write(':')
881 self.indent()
882 self.writeline('continue')
883 self.outdent(2)
884
Armin Ronacherc9705c22008-04-27 21:28:03 +0200885 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200886 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200887 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200888
889 if node.else_:
890 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200891 self.indent()
892 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher625215e2008-04-13 16:31:08 +0200893 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200894 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200895
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200896 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200897 for name, alias in aliases.iteritems():
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200898 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200899
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200900 # if the node was recursive we have to return the buffer contents
901 # and start the iteration code
902 if node.recursive:
903 if self.environment.autoescape:
904 self.writeline('return Markup(concat(%s))' % buf)
905 else:
906 self.writeline('return concat(%s)' % buf)
907 self.outdent()
908 if frame.buffer is None:
909 self.writeline('yield loop(', node)
910 else:
911 self.writeline('%s.append(loop(' % frame.buffer, node)
912 self.visit(node.iter, frame)
913 self.write(', loop)')
914 if frame.buffer is not None:
915 self.write(')')
916
Armin Ronachere791c2a2008-04-07 18:39:54 +0200917 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200918 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200919 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200920 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200921 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200922 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200923 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200924 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200925 if node.else_:
926 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200927 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200928 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200929 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200930
Armin Ronacher8efc5222008-04-08 14:47:40 +0200931 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200932 macro_frame = self.function_scoping(node, frame)
933 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200934 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200935 macro_frame.buffer = buf = self.temporary_identifier()
936 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200937 self.pull_locals(macro_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200938 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200939 self.blockvisit(node.body, macro_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200940 if self.environment.autoescape:
941 self.writeline('return Markup(concat(%s))' % buf)
942 else:
943 self.writeline("return concat(%s)" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200944 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200945 self.newline()
946 if frame.toplevel:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200947 if not node.name.startswith('__'):
948 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +0200949 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200950 arg_tuple = ', '.join(repr(x.name) for x in node.args)
951 if len(node.args) == 1:
952 arg_tuple += ','
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200953 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
954 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200955 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200956 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200957 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200958 self.write('), %s, %s, %s)' % (
959 macro_frame.accesses_kwargs and '1' or '0',
960 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200961 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200962 ))
963
964 def visit_CallBlock(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200965 call_frame = self.function_scoping(node, frame, node.iter_child_nodes
966 (exclude=('call',)))
Armin Ronacher71082072008-04-12 14:19:36 +0200967 args = call_frame.arguments
968 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200969 call_frame.buffer = buf = self.temporary_identifier()
970 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200971 self.pull_locals(call_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200972 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200973 self.blockvisit(node.body, call_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200974 if self.environment.autoescape:
975 self.writeline("return Markup(concat(%s))" % buf)
976 else:
977 self.writeline('return concat(%s)' % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200978 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200979 arg_tuple = ', '.join(repr(x.name) for x in node.args)
980 if len(node.args) == 1:
981 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200982 self.writeline('caller = Macro(environment, call, None, (%s), (' %
983 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200984 for arg in node.defaults:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200985 self.visit(arg, call_frame)
Armin Ronacher71082072008-04-12 14:19:36 +0200986 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200987 self.write('), %s, %s, 0)' % (
988 call_frame.accesses_kwargs and '1' or '0',
989 call_frame.accesses_varargs and '1' or '0'
990 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200991 if frame.buffer is None:
992 self.writeline('yield ', node)
993 else:
994 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200995 self.visit_Call(node.call, call_frame,
996 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200997 if frame.buffer is not None:
998 self.write(')')
999
1000 def visit_FilterBlock(self, node, frame):
1001 filter_frame = frame.inner()
1002 filter_frame.inspect(node.iter_child_nodes())
1003
1004 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001005 self.pull_locals(filter_frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001006 filter_frame.buffer = buf = self.temporary_identifier()
1007
1008 self.writeline('%s = []' % buf, node)
1009 for child in node.body:
1010 self.visit(child, filter_frame)
1011
1012 if frame.buffer is None:
1013 self.writeline('yield ', node)
1014 else:
1015 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacherde6bf712008-04-26 01:44:14 +02001016 self.visit_Filter(node.filter, filter_frame, 'concat(%s)' % buf)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001017 if frame.buffer is not None:
1018 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001019
Armin Ronachere791c2a2008-04-07 18:39:54 +02001020 def visit_ExprStmt(self, node, frame):
1021 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001022 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001023
1024 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001025 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +02001026 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001027 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001028
Armin Ronacher75cfb862008-04-11 13:47:22 +02001029 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001030
Armin Ronacher7fb38972008-04-11 13:54:28 +02001031 # if we are in the toplevel scope and there was already an extends
1032 # statement we have to add a check that disables our yield(s) here
1033 # so that they don't appear in the output.
1034 outdent_later = False
1035 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001036 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001037 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001038 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001039
Armin Ronachere791c2a2008-04-07 18:39:54 +02001040 # try to evaluate as many chunks as possible into a static
1041 # string at compile time.
1042 body = []
1043 for child in node.nodes:
1044 try:
1045 const = unicode(child.as_const())
1046 except:
1047 body.append(child)
1048 continue
1049 if body and isinstance(body[-1], list):
1050 body[-1].append(const)
1051 else:
1052 body.append([const])
1053
Armin Ronacher32a910f2008-04-26 23:21:03 +02001054 # if we have less than 3 nodes or less than 6 and a buffer we
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001055 # yield or extend/append
Armin Ronacher32a910f2008-04-26 23:21:03 +02001056 if len(body) < 3 or (frame.buffer is not None and len(body) < 6):
1057 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001058 # for one item we append, for more we extend
1059 if len(body) == 1:
1060 self.writeline('%s.append(' % frame.buffer)
1061 else:
1062 self.writeline('%s.extend((' % frame.buffer)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001063 for item in body:
1064 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001065 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001066 if frame.buffer is None:
1067 self.writeline('yield ' + val)
1068 else:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001069 self.write(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001070 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001071 if frame.buffer is None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001072 self.writeline('yield ')
Armin Ronacherd1342312008-04-28 12:20:12 +02001073 close = 1
1074 if self.environment.autoescape:
1075 self.write('escape(')
1076 else:
1077 self.write('unicode(')
1078 if self.environment.finalize is not None:
1079 self.write('environment.finalize(')
1080 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001081 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001082 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001083 if frame.buffer is not None:
1084 self.write(', ')
1085 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001086 # close the open parentheses
1087 self.write(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001088
1089 # otherwise we create a format string as this is faster in that case
1090 else:
1091 format = []
1092 arguments = []
1093 for item in body:
1094 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001095 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001096 else:
1097 format.append('%s')
1098 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001099 if frame.buffer is None:
1100 self.writeline('yield ')
1101 else:
1102 self.writeline('%s.append(' % frame.buffer)
Armin Ronacherde6bf712008-04-26 01:44:14 +02001103 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001104 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001105 self.indent()
1106 for argument in arguments:
1107 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001108 close = 0
1109 if self.environment.autoescape:
1110 self.write('escape(')
1111 close += 1
1112 if self.environment.finalize is not None:
1113 self.write('environment.finalize(')
1114 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001115 self.visit(argument, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001116 self.write(')' * close + ',')
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001117 self.outdent()
1118 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001119 if frame.buffer is not None:
1120 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001121
Armin Ronacher7fb38972008-04-11 13:54:28 +02001122 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001123 self.outdent()
1124
Armin Ronacher8efc5222008-04-08 14:47:40 +02001125 def visit_Assign(self, node, frame):
1126 self.newline(node)
1127 # toplevel assignments however go into the local namespace and
1128 # the current template's context. We create a copy of the frame
1129 # here and add a set so that the Name visitor can add the assigned
1130 # names here.
1131 if frame.toplevel:
1132 assignment_frame = frame.copy()
1133 assignment_frame.assigned_names = set()
1134 else:
1135 assignment_frame = frame
1136 self.visit(node.target, assignment_frame)
1137 self.write(' = ')
1138 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001139
1140 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001141 if frame.toplevel:
Armin Ronacher69e12db2008-05-12 09:00:03 +02001142 public_names = [x for x in assignment_frame.assigned_names
1143 if not x.startswith('__')]
1144 if len(assignment_frame.assigned_names) == 1:
1145 name = iter(assignment_frame.assigned_names).next()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001146 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001147 else:
1148 self.writeline('context.vars.update({')
1149 for idx, name in enumerate(assignment_frame.assigned_names):
1150 if idx:
1151 self.write(', ')
1152 self.write('%r: l_%s' % (name, name))
1153 self.write('})')
1154 if public_names:
1155 if len(public_names) == 1:
1156 self.writeline('context.exported_vars.add(%r)' %
1157 public_names[0])
1158 else:
1159 self.writeline('context.exported_vars.update((%s))' %
1160 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001161
Armin Ronachere791c2a2008-04-07 18:39:54 +02001162 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001163 if node.ctx == 'store' and frame.toplevel:
1164 frame.assigned_names.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001165 self.write('l_' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001166
Armin Ronacherd84ec462008-04-29 13:43:16 +02001167 def visit_MarkSafe(self, node, frame):
1168 self.write('Markup(')
1169 self.visit(node.expr, frame)
1170 self.write(')')
1171
Armin Ronacher023b5e92008-05-08 11:03:10 +02001172 def visit_EnvironmentAttribute(self, node, frame):
1173 self.write('environment.' + node.name)
1174
1175 def visit_ExtensionAttribute(self, node, frame):
1176 self.write('environment.extensions[%r].%s' % (node.identifier, node.attr))
1177
1178 def visit_ImportedName(self, node, frame):
1179 self.write(self.import_aliases[node.importname])
1180
1181 def visit_InternalName(self, node, frame):
1182 self.write(node.name)
1183
Armin Ronachere791c2a2008-04-07 18:39:54 +02001184 def visit_Const(self, node, frame):
1185 val = node.value
1186 if isinstance(val, float):
1187 # XXX: add checks for infinity and nan
1188 self.write(str(val))
1189 else:
1190 self.write(repr(val))
1191
Armin Ronacher8efc5222008-04-08 14:47:40 +02001192 def visit_Tuple(self, node, frame):
1193 self.write('(')
1194 idx = -1
1195 for idx, item in enumerate(node.items):
1196 if idx:
1197 self.write(', ')
1198 self.visit(item, frame)
1199 self.write(idx == 0 and ',)' or ')')
1200
Armin Ronacher8edbe492008-04-10 20:43:43 +02001201 def visit_List(self, node, frame):
1202 self.write('[')
1203 for idx, item in enumerate(node.items):
1204 if idx:
1205 self.write(', ')
1206 self.visit(item, frame)
1207 self.write(']')
1208
1209 def visit_Dict(self, node, frame):
1210 self.write('{')
1211 for idx, item in enumerate(node.items):
1212 if idx:
1213 self.write(', ')
1214 self.visit(item.key, frame)
1215 self.write(': ')
1216 self.visit(item.value, frame)
1217 self.write('}')
1218
Armin Ronachere791c2a2008-04-07 18:39:54 +02001219 def binop(operator):
1220 def visitor(self, node, frame):
1221 self.write('(')
1222 self.visit(node.left, frame)
1223 self.write(' %s ' % operator)
1224 self.visit(node.right, frame)
1225 self.write(')')
1226 return visitor
1227
1228 def uaop(operator):
1229 def visitor(self, node, frame):
1230 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001231 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001232 self.write(')')
1233 return visitor
1234
1235 visit_Add = binop('+')
1236 visit_Sub = binop('-')
1237 visit_Mul = binop('*')
1238 visit_Div = binop('/')
1239 visit_FloorDiv = binop('//')
1240 visit_Pow = binop('**')
1241 visit_Mod = binop('%')
1242 visit_And = binop('and')
1243 visit_Or = binop('or')
1244 visit_Pos = uaop('+')
1245 visit_Neg = uaop('-')
1246 visit_Not = uaop('not ')
1247 del binop, uaop
1248
Armin Ronacherd1342312008-04-28 12:20:12 +02001249 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001250 self.write('%s((' % (self.environment.autoescape and
1251 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001252 for arg in node.nodes:
1253 self.visit(arg, frame)
1254 self.write(', ')
1255 self.write('))')
1256
Armin Ronachere791c2a2008-04-07 18:39:54 +02001257 def visit_Compare(self, node, frame):
1258 self.visit(node.expr, frame)
1259 for op in node.ops:
1260 self.visit(op, frame)
1261
1262 def visit_Operand(self, node, frame):
1263 self.write(' %s ' % operators[node.op])
1264 self.visit(node.expr, frame)
1265
1266 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001267 if isinstance(node.arg, nodes.Slice):
1268 self.visit(node.node, frame)
1269 self.write('[')
1270 self.visit(node.arg, frame)
1271 self.write(']')
1272 return
1273 try:
1274 const = node.arg.as_const()
1275 have_const = True
1276 except nodes.Impossible:
1277 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001278 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001279 self.visit(node.node, frame)
1280 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001281 if have_const:
1282 self.write(repr(const))
1283 else:
1284 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001285 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001286
1287 def visit_Slice(self, node, frame):
1288 if node.start is not None:
1289 self.visit(node.start, frame)
1290 self.write(':')
1291 if node.stop is not None:
1292 self.visit(node.stop, frame)
1293 if node.step is not None:
1294 self.write(':')
1295 self.visit(node.step, frame)
1296
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001297 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001298 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001299 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001300 if func is None:
1301 raise TemplateAssertionError('no filter named %r' % node.name,
1302 node.lineno, self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001303 if getattr(func, 'contextfilter', False):
1304 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001305 elif getattr(func, 'environmentfilter', False):
1306 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001307 if isinstance(node.node, nodes.Filter):
1308 self.visit_Filter(node.node, frame, initial)
1309 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001310 self.write(initial)
1311 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001312 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001313 self.signature(node, frame)
1314 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001315
1316 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001317 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001318 if node.name not in self.environment.tests:
1319 raise TemplateAssertionError('no test named %r' % node.name,
1320 node.lineno, self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001321 self.visit(node.node, frame)
1322 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001323 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001324
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001325 def visit_CondExpr(self, node, frame):
1326 if not have_condexpr:
1327 self.write('((')
1328 self.visit(node.test, frame)
1329 self.write(') and (')
1330 self.visit(node.expr1, frame)
1331 self.write(',) or (')
1332 self.visit(node.expr2, frame)
1333 self.write(',))[0]')
1334 else:
1335 self.write('(')
1336 self.visit(node.expr1, frame)
1337 self.write(' if ')
1338 self.visit(node.test, frame)
1339 self.write(' else ')
1340 self.visit(node.expr2, frame)
1341 self.write(')')
1342
Armin Ronacher71082072008-04-12 14:19:36 +02001343 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001344 if self.environment.sandboxed:
1345 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001346 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001347 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001348 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001349 self.write(')')
1350
1351 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001352 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001353 self.visit(node.value, frame)