blob: 773203a47802390f53cce822a82f0d51aa905dc0 [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
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200110 # static subscribes
111 self.static_subscribes = {}
112
Armin Ronachere791c2a2008-04-07 18:39:54 +0200113 def add_special(self, name):
114 """Register a special name like `loop`."""
115 self.undeclared.discard(name)
116 self.declared.add(name)
117
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200118 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200119 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200120 if name in self.declared_locally or name in self.declared_parameter:
121 return True
122 if local_only:
123 return False
124 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200125
126 def find_shadowed(self):
127 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200128 return (self.declared | self.outer_undeclared) & \
129 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200130
131
132class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200133 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200134
135 def __init__(self, parent=None):
136 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200137
Armin Ronacher75cfb862008-04-11 13:47:22 +0200138 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200139 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200140
Armin Ronacher75cfb862008-04-11 13:47:22 +0200141 # the root frame is basically just the outermost frame, so no if
142 # conditions. This information is used to optimize inheritance
143 # situations.
144 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200145
146 # inside some tags we are using a buffer rather than yield statements.
147 # this for example affects {% filter %} or {% macro %}. If a frame
148 # is buffered this variable points to the name of the list used as
149 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200150 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200151
Armin Ronacherfed44b52008-04-13 19:42:53 +0200152 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200153 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200154
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200155 # node overlays. see `CodeGenerator.overlay` for more details
156 self.overlays = {}
157
Armin Ronacherfed44b52008-04-13 19:42:53 +0200158 # the parent of this frame
159 self.parent = parent
160
Armin Ronachere791c2a2008-04-07 18:39:54 +0200161 if parent is not None:
162 self.identifiers.declared.update(
163 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200164 parent.identifiers.declared_locally |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200165 parent.identifiers.declared_parameter |
166 parent.identifiers.undeclared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200167 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200168 self.identifiers.outer_undeclared.update(
169 parent.identifiers.undeclared -
170 self.identifiers.declared
171 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200172 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200173
Armin Ronacher8efc5222008-04-08 14:47:40 +0200174 def copy(self):
175 """Create a copy of the current one."""
176 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200177 rv.identifiers = copy(self.identifiers)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200178 return rv
179
Armin Ronacherc9705c22008-04-27 21:28:03 +0200180 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200181 """Walk the node and check for identifiers. If the scope is hard (eg:
182 enforce on a python level) overrides from outer scopes are tracked
183 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200184 """
185 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200186 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200187 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200188
189 def inner(self):
190 """Return an inner frame."""
191 return Frame(self)
192
Armin Ronacher75cfb862008-04-11 13:47:22 +0200193 def soft(self):
194 """Return a soft frame. A soft frame may not be modified as
195 standalone thing as it shares the resources with the frame it
196 was created of, but it's not a rootlevel frame any longer.
197 """
198 rv = copy(self)
199 rv.rootlevel = False
200 return rv
201
Armin Ronachere791c2a2008-04-07 18:39:54 +0200202
Armin Ronacherc9705c22008-04-27 21:28:03 +0200203class VisitorExit(RuntimeError):
204 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
205
206
207class DependencyFinderVisitor(NodeVisitor):
208 """A visitor that collects filter and test calls."""
209
210 def __init__(self):
211 self.filters = set()
212 self.tests = set()
213
214 def visit_Filter(self, node):
215 self.generic_visit(node)
216 self.filters.add(node.name)
217
218 def visit_Test(self, node):
219 self.generic_visit(node)
220 self.tests.add(node.name)
221
222 def visit_Block(self, node):
223 """Stop visiting at blocks."""
224
225
226class UndeclaredNameVisitor(NodeVisitor):
227 """A visitor that checks if a name is accessed without being
228 declared. This is different from the frame visitor as it will
229 not stop at closure frames.
230 """
231
232 def __init__(self, names):
233 self.names = set(names)
234 self.undeclared = set()
235
236 def visit_Name(self, node):
237 if node.ctx == 'load' and node.name in self.names:
238 self.undeclared.add(node.name)
239 if self.undeclared == self.names:
240 raise VisitorExit()
241 else:
242 self.names.discard(node.name)
243
244 def visit_Block(self, node):
245 """Stop visiting a blocks."""
246
247
Armin Ronachere791c2a2008-04-07 18:39:54 +0200248class FrameIdentifierVisitor(NodeVisitor):
249 """A visitor for `Frame.inspect`."""
250
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200251 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200252 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200253 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200254
Armin Ronacherc9705c22008-04-27 21:28:03 +0200255 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200256 """All assignments to names go through this function."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200257 if node.ctx in ('store', 'param'):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200258 self.identifiers.declared_locally.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200259 elif node.ctx == 'load' and not \
260 self.identifiers.is_declared(node.name, self.hard_scope):
261 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200262
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200263 def visit_Subscript(self, node):
264 """Under some circumstances subscripts are aliased with local names:
265
266 - the subscript node is either already aliased or a name that was not
267 reassigned.
268 - and the subscription argument is a constant string.
269 """
270 self.generic_visit(node)
271 if isinstance(node.arg, nodes.Const) and \
272 isinstance(node.arg.value, basestring) and \
273 (isinstance(node.node, nodes.Name) and
274 node.node.name not in (self.identifiers.declared_locally |
275 self.identifiers.declared_parameter)) or \
276 node.node in self.identifiers.static_subscribes:
277 if node in self.identifiers.static_subscribes:
278 self.identifiers.static_subscribes[node] += 1
279 else:
280 self.identifiers.static_subscribes[node] = 1
281
Armin Ronacherc9705c22008-04-27 21:28:03 +0200282 def visit_Macro(self, node):
283 self.generic_visit(node)
284 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200285
Armin Ronacherc9705c22008-04-27 21:28:03 +0200286 def visit_Import(self, node):
287 self.generic_visit(node)
288 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200289
Armin Ronacherc9705c22008-04-27 21:28:03 +0200290 def visit_FromImport(self, node):
291 self.generic_visit(node)
292 for name in node.names:
293 if isinstance(name, tuple):
294 self.identifiers.declared_locally.add(name[1])
295 else:
296 self.identifiers.declared_locally.add(name)
297
298 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200299 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200300 self.visit(node.node)
301 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200302
Armin Ronacherc9705c22008-04-27 21:28:03 +0200303 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200304 """Visiting stops at for blocks. However the block sequence
305 is visited as part of the outer scope.
306 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200307 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200308
Armin Ronacherc9705c22008-04-27 21:28:03 +0200309 def visit_CallBlock(self, node):
310 for child in node.iter_child_nodes(exclude=('body',)):
311 self.visit(child)
312
313 def visit_FilterBlock(self, node):
314 self.visit(node.filter)
315
316 def visit_Block(self, node):
317 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200318
319
Armin Ronacher75cfb862008-04-11 13:47:22 +0200320class CompilerExit(Exception):
321 """Raised if the compiler encountered a situation where it just
322 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200323 raises such an exception is not further processed.
324 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200325
326
Armin Ronachere791c2a2008-04-07 18:39:54 +0200327class CodeGenerator(NodeVisitor):
328
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200329 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200330 if stream is None:
331 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200332 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200333 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200334 self.filename = filename
335 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200336
Armin Ronacher023b5e92008-05-08 11:03:10 +0200337 # aliases for imports
338 self.import_aliases = {}
339
Armin Ronacherfed44b52008-04-13 19:42:53 +0200340 # a registry for all blocks. Because blocks are moved out
341 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200342 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200343
344 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200345 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200346
347 # some templates have a rootlevel extends. In this case we
348 # can safely assume that we're a child template and do some
349 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200350 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200351
Armin Ronacherba3757b2008-04-16 19:43:16 +0200352 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200353 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200354
Armin Ronacherb9e78752008-05-10 23:36:28 +0200355 # registry of all filters and tests (global, not block local)
356 self.tests = {}
357 self.filters = {}
358
Armin Ronacherba3757b2008-04-16 19:43:16 +0200359 # the debug information
360 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200361 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200362
Armin Ronacherfed44b52008-04-13 19:42:53 +0200363 # the number of new lines before the next write()
364 self._new_lines = 0
365
366 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200367 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200368
369 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200370 self._first_write = True
371
Armin Ronacherfed44b52008-04-13 19:42:53 +0200372 # used by the `temporary_identifier` method to get new
373 # unique, temporary identifier
374 self._last_identifier = 0
375
376 # the current indentation
377 self._indentation = 0
378
Armin Ronachere791c2a2008-04-07 18:39:54 +0200379 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200380 """Get a new unique identifier."""
381 self._last_identifier += 1
382 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200383
384 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200385 """Indent by one."""
386 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200387
Armin Ronacher8efc5222008-04-08 14:47:40 +0200388 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200389 """Outdent by step."""
390 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200391
Armin Ronacherc9705c22008-04-27 21:28:03 +0200392 def blockvisit(self, nodes, frame, force_generator=True):
393 """Visit a list of nodes as block in a frame. If the current frame
394 is no buffer a dummy ``if 0: yield None`` is written automatically
395 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200396 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200397 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200398 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200399 try:
400 for node in nodes:
401 self.visit(node, frame)
402 except CompilerExit:
403 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200404
405 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200406 """Write a string into the output stream."""
407 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200408 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200409 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200410 self.code_lineno += self._new_lines
411 if self._write_debug_info is not None:
412 self.debug_info.append((self._write_debug_info,
413 self.code_lineno))
414 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200415 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200416 self.stream.write(' ' * self._indentation)
417 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200418 self.stream.write(x)
419
420 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200421 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200422 self.newline(node, extra)
423 self.write(x)
424
425 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200426 """Add one or more newlines before the next write."""
427 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200428 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200429 self._write_debug_info = node.lineno
430 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200431
Armin Ronacher71082072008-04-12 14:19:36 +0200432 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200433 """Writes a function call to the stream for the current node.
434 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200435 disabled by setting have_comma to False. The extra keyword
436 arguments may not include python keywords otherwise a syntax
437 error could occour. The extra keyword arguments should be given
438 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200439 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200440 have_comma = have_comma and [True] or []
441 def touch_comma():
442 if have_comma:
443 self.write(', ')
444 else:
445 have_comma.append(True)
446
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200447 # if any of the given keyword arguments is a python keyword
448 # we have to make sure that no invalid call is created.
449 kwarg_workaround = False
450 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
451 if iskeyword(kwarg):
452 kwarg_workaround = True
453 break
454
Armin Ronacher8efc5222008-04-08 14:47:40 +0200455 for arg in node.args:
456 touch_comma()
457 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200458
459 if not kwarg_workaround:
460 for kwarg in node.kwargs:
461 touch_comma()
462 self.visit(kwarg, frame)
463 if extra_kwargs is not None:
464 for key, value in extra_kwargs.iteritems():
465 touch_comma()
466 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200467 if node.dyn_args:
468 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200469 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200470 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200471
472 if kwarg_workaround:
473 touch_comma()
474 if node.dyn_kwargs is not None:
475 self.write('**dict({')
476 else:
477 self.write('**{')
478 for kwarg in node.kwargs:
479 self.write('%r: ' % kwarg.key)
480 self.visit(kwarg.value, frame)
481 self.write(', ')
482 if extra_kwargs is not None:
483 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200484 self.write('%r: %s, ' % (key, value))
485 if node.dyn_kwargs is not None:
486 self.write('}, **')
487 self.visit(node.dyn_kwargs, frame)
488 self.write(')')
489 else:
490 self.write('}')
491
492 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200493 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200494 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200495 self.visit(node.dyn_kwargs, frame)
496
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200497 def overlay(self, node, frame):
498 """Visit an overlay and return `True` or `False` if the overlay
499 does not exist or is exhausted. An overlay is used to replace a
500 node with another one (or an identifier) N times. This is for
501 example used to replace static subscribes before reassignments
502 of a name that occour more than one time. If a node has overlays
503 it's important that this method is called, otherwise the count
504 will be out of sync and the generated code is broken.
505 """
506 if node not in frame.overlays:
507 return False
508 overlay, count = frame.overlays[node]
509 if count is not None and count <= 0:
510 return False
511 if isinstance(overlay, basestring):
512 self.write(overlay)
513 else:
514 self.visit(overlay, frame)
515 frame.overlays[node] = (overlay, count - 1)
516 return True
517
Armin Ronacherc9705c22008-04-27 21:28:03 +0200518 def pull_locals(self, frame):
519 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200520 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200521 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200522
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200523 # find all the static subscribes with a count > 2 and
524 # order them properly so that subscribes depending on other
525 # subscribes are handled later.
526 static_subscribes = [(node, count) for node, count in
527 frame.identifiers.static_subscribes.items() if
528 count >= 2]
529 if static_subscribes:
530 static_subscribes.sort(key=lambda x: type(x[0].node)
531 is nodes.Subscript)
532 for node, count in static_subscribes:
533 ident = self.temporary_identifier()
534 self.writeline(ident + ' = ')
535 self.visit(node, frame)
536 frame.overlays[node] = (ident, count)
537
Armin Ronacherc9705c22008-04-27 21:28:03 +0200538 def pull_dependencies(self, nodes):
539 """Pull all the dependencies."""
540 visitor = DependencyFinderVisitor()
541 for node in nodes:
542 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200543 for dependency in 'filters', 'tests':
544 mapping = getattr(self, dependency)
545 for name in getattr(visitor, dependency):
546 if name not in mapping:
547 mapping[name] = self.temporary_identifier()
548 self.writeline('%s = environment.%s[%r]' %
549 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200550
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200551 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200552 """This function returns all the shadowed variables in a dict
553 in the form name: alias and will write the required assignments
554 into the current scope. No indentation takes place.
555 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200556 # make sure we "backup" overridden, local identifiers
557 # TODO: we should probably optimize this and check if the
558 # identifier is in use afterwards.
559 aliases = {}
560 for name in frame.identifiers.find_shadowed():
561 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200562 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200563 return aliases
564
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200565 def function_scoping(self, node, frame, children=None,
566 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200567 """In Jinja a few statements require the help of anonymous
568 functions. Those are currently macros and call blocks and in
569 the future also recursive loops. As there is currently
570 technical limitation that doesn't allow reading and writing a
571 variable in a scope where the initial value is coming from an
572 outer scope, this function tries to fall back with a common
573 error message. Additionally the frame passed is modified so
574 that the argumetns are collected and callers are looked up.
575
576 This will return the modified frame.
577 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200578 # we have to iterate twice over it, make sure that works
579 if children is None:
580 children = node.iter_child_nodes()
581 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200582 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200583 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200584
585 # variables that are undeclared (accessed before declaration) and
586 # declared locally *and* part of an outside scope raise a template
587 # assertion error. Reason: we can't generate reasonable code from
588 # it without aliasing all the variables. XXX: alias them ^^
589 overriden_closure_vars = (
590 func_frame.identifiers.undeclared &
591 func_frame.identifiers.declared &
592 (func_frame.identifiers.declared_locally |
593 func_frame.identifiers.declared_parameter)
594 )
595 if overriden_closure_vars:
596 vars = ', '.join(sorted(overriden_closure_vars))
597 raise TemplateAssertionError('It\'s not possible to set and '
598 'access variables derived from '
599 'an outer scope! (affects: %s' %
Armin Ronacher66a93442008-05-11 23:42:19 +0200600 vars, node.lineno, self.filename)
Armin Ronacher71082072008-04-12 14:19:36 +0200601
602 # remove variables from a closure from the frame's undeclared
603 # identifiers.
604 func_frame.identifiers.undeclared -= (
605 func_frame.identifiers.undeclared &
606 func_frame.identifiers.declared
607 )
608
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200609 # no special variables for this scope, abort early
610 if not find_special:
611 return func_frame
612
Armin Ronacher963f97d2008-04-25 11:44:59 +0200613 func_frame.accesses_kwargs = False
614 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200615 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200616 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200617
Armin Ronacherc9705c22008-04-27 21:28:03 +0200618 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
619
620 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200621 func_frame.accesses_caller = True
622 func_frame.identifiers.add_special('caller')
623 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200624 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200625 func_frame.accesses_kwargs = True
626 func_frame.identifiers.add_special('kwargs')
627 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200628 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200629 func_frame.accesses_varargs = True
630 func_frame.identifiers.add_special('varargs')
631 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200632 return func_frame
633
Armin Ronachere791c2a2008-04-07 18:39:54 +0200634 # -- Visitors
635
636 def visit_Template(self, node, frame=None):
637 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200638 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200639 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200640 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8edbe492008-04-10 20:43:43 +0200641
Armin Ronacher75cfb862008-04-11 13:47:22 +0200642 # do we have an extends tag at all? If not, we can save some
643 # overhead by just not processing any inheritance code.
644 have_extends = node.find(nodes.Extends) is not None
645
Armin Ronacher8edbe492008-04-10 20:43:43 +0200646 # find all blocks
647 for block in node.find_all(nodes.Block):
648 if block.name in self.blocks:
649 raise TemplateAssertionError('block %r defined twice' %
650 block.name, block.lineno,
Armin Ronacher66a93442008-05-11 23:42:19 +0200651 self.filename)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200652 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200653
Armin Ronacher023b5e92008-05-08 11:03:10 +0200654 # find all imports and import them
655 for import_ in node.find_all(nodes.ImportedName):
656 if import_.importname not in self.import_aliases:
657 imp = import_.importname
658 self.import_aliases[imp] = alias = self.temporary_identifier()
659 if '.' in imp:
660 module, obj = imp.rsplit('.', 1)
661 self.writeline('from %s import %s as %s' %
662 (module, obj, alias))
663 else:
664 self.writeline('import %s as %s' % (imp, alias))
665
666 # add the load name
Armin Ronacher66a93442008-05-11 23:42:19 +0200667 self.writeline('name = %r' % self.filename)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200668
Armin Ronacher8efc5222008-04-08 14:47:40 +0200669 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200670 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200671
672 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200673 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200674 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200675 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200676 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200677 if have_extends:
678 self.writeline('parent_template = None')
679 self.pull_locals(frame)
680 self.pull_dependencies(node.body)
681 if 'self' in find_undeclared(node.body, ('self',)):
682 frame.identifiers.add_special('self')
683 self.writeline('l_self = TemplateReference(context)')
684 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200685 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200686
Armin Ronacher8efc5222008-04-08 14:47:40 +0200687 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200688 if have_extends:
689 if not self.has_known_extends:
690 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200691 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200692 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200693 self.writeline('for event in parent_template.'
694 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200695 self.indent()
696 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200697 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200698
699 # at this point we now have the blocks collected and can visit them too.
700 for name, block in self.blocks.iteritems():
701 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200702 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200703 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200704 self.writeline('def block_%s(context, environment=environment):'
705 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200706 self.indent()
707 undeclared = find_undeclared(block.body, ('self', 'super'))
708 if 'self' in undeclared:
709 block_frame.identifiers.add_special('self')
710 self.writeline('l_self = TemplateReference(context)')
711 if 'super' in undeclared:
712 block_frame.identifiers.add_special('super')
713 self.writeline('l_super = context.super(%r, '
714 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200715 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200716 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200717 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200718 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200719
Armin Ronacher75cfb862008-04-11 13:47:22 +0200720 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200721 for x in self.blocks),
722 extra=1)
723
724 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200725 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
726 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200727
Armin Ronachere791c2a2008-04-07 18:39:54 +0200728 def visit_Block(self, node, frame):
729 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200730 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200731 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200732 # if we know that we are a child template, there is no need to
733 # check if we are one
734 if self.has_known_extends:
735 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200736 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200737 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200738 self.indent()
739 level += 1
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200740 self.writeline('for event in context.blocks[%r][0](context):' %
Armin Ronacherc9705c22008-04-27 21:28:03 +0200741 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200742 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200743 if frame.buffer is None:
744 self.writeline('yield event')
745 else:
746 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200747 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200748
749 def visit_Extends(self, node, frame):
750 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200751 if not frame.toplevel:
752 raise TemplateAssertionError('cannot use extend from a non '
753 'top-level scope', node.lineno,
Armin Ronacher66a93442008-05-11 23:42:19 +0200754 self.filename)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200755
Armin Ronacher7fb38972008-04-11 13:54:28 +0200756 # if the number of extends statements in general is zero so
757 # far, we don't have to add a check if something extended
758 # the template before this one.
759 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200760
Armin Ronacher7fb38972008-04-11 13:54:28 +0200761 # if we have a known extends we just add a template runtime
762 # error into the generated code. We could catch that at compile
763 # time too, but i welcome it not to confuse users by throwing the
764 # same error at different times just "because we can".
765 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200766 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200767 self.indent()
768 self.writeline('raise TemplateRuntimeError(%r)' %
769 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200770
Armin Ronacher7fb38972008-04-11 13:54:28 +0200771 # if we have a known extends already we don't need that code here
772 # as we know that the template execution will end here.
773 if self.has_known_extends:
774 raise CompilerExit()
775 self.outdent()
776
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200777 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200778 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200779 self.write(', %r)' % self.name)
780 self.writeline('for name, parent_block in parent_template.'
781 'blocks.iteritems():')
782 self.indent()
783 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200784 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200785 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200786
787 # if this extends statement was in the root level we can take
788 # advantage of that information and simplify the generated code
789 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200790 if frame.rootlevel:
791 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200792
Armin Ronacher7fb38972008-04-11 13:54:28 +0200793 # and now we have one more
794 self.extends_so_far += 1
795
Armin Ronacherf059ec12008-04-11 22:21:00 +0200796 def visit_Include(self, node, frame):
797 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200798 if node.with_context:
799 self.writeline('template = environment.get_template(', node)
800 self.visit(node.template, frame)
801 self.write(', %r)' % self.name)
802 self.writeline('for event in template.root_render_func('
803 'template.new_context(context.parent, True)):')
804 else:
805 self.writeline('for event in environment.get_template(', node)
806 self.visit(node.template, frame)
807 self.write(', %r).module._TemplateModule__body_stream:' %
808 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200809 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200810 if frame.buffer is None:
811 self.writeline('yield event')
812 else:
813 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200814 self.outdent()
815
Armin Ronacher0611e492008-04-25 23:44:14 +0200816 def visit_Import(self, node, frame):
817 """Visit regular imports."""
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200818 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200819 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200820 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200821 self.write('environment.get_template(')
822 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200823 self.write(', %r).' % self.name)
824 if node.with_context:
825 self.write('make_module(context.parent, True)')
826 else:
827 self.write('module')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200828 if frame.toplevel and not node.target.startswith('__'):
Armin Ronacher53042292008-04-26 18:30:19 +0200829 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200830
831 def visit_FromImport(self, node, frame):
832 """Visit named imports."""
833 self.newline(node)
834 self.write('included_template = environment.get_template(')
835 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200836 self.write(', %r).' % self.name)
837 if node.with_context:
838 self.write('make_module(context.parent, True)')
839 else:
840 self.write('module')
Armin Ronacher0611e492008-04-25 23:44:14 +0200841 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200842 if isinstance(name, tuple):
843 name, alias = name
844 else:
845 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200846 self.writeline('l_%s = getattr(included_template, '
847 '%r, missing)' % (alias, name))
848 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200849 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200850 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200851 'included_template.name, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200852 'name=%r)' %
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200853 (alias, 'the template %r does not export '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200854 'the requested name ' + repr(name), name))
Armin Ronacher0611e492008-04-25 23:44:14 +0200855 self.outdent()
856 if frame.toplevel:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200857 self.writeline('context.vars[%r] = l_%s' % (alias, alias))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200858 if not alias.startswith('__'):
859 self.writeline('context.exported_vars.discard(%r)' % alias)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200860
Armin Ronachere791c2a2008-04-07 18:39:54 +0200861 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200862 # when calculating the nodes for the inner frame we have to exclude
863 # the iterator contents from it
864 children = node.iter_child_nodes(exclude=('iter',))
865
866 if node.recursive:
867 loop_frame = self.function_scoping(node, frame, children,
868 find_special=False)
869 else:
870 loop_frame = frame.inner()
871 loop_frame.inspect(children)
872
873 extended_loop = node.recursive or node.else_ or \
Armin Ronachere791c2a2008-04-07 18:39:54 +0200874 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200875 if extended_loop:
876 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200877
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200878 # if we don't have an recursive loop we have to find the shadowed
879 # variables at that point
880 if not node.recursive:
881 aliases = self.collect_shadowed(loop_frame)
882
883 # otherwise we set up a buffer and add a function def
884 else:
885 loop_frame.buffer = buf = self.temporary_identifier()
886 self.writeline('def loop(reciter, loop_render_func):', node)
887 self.indent()
888 self.writeline('%s = []' % buf, node)
889 aliases = {}
890
Armin Ronacherc9705c22008-04-27 21:28:03 +0200891 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200892 if node.else_:
893 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200894
895 self.newline(node)
896 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200897 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200898 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200899
900 # the expression pointing to the parent loop. We make the
901 # undefined a bit more debug friendly at the same time.
902 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200903 or "environment.undefined(%r, name='loop')" % "'loop' " \
904 'is undefined. "the filter section of a loop as well ' \
905 'as the else block doesn\'t have access to the ' \
906 "special 'loop' variable of the current loop. " \
907 "Because there is no parent loop it's undefined."
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200908
909 # if we have an extened loop and a node test, we filter in the
910 # "outer frame".
911 if extended_loop and node.test is not None:
912 self.write('(')
913 self.visit(node.target, loop_frame)
914 self.write(' for ')
915 self.visit(node.target, loop_frame)
916 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200917 if node.recursive:
918 self.write('reciter')
919 else:
920 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200921 self.write(' if (')
922 test_frame = loop_frame.copy()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200923 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200924 self.visit(node.test, test_frame)
925 self.write('))')
926
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200927 elif node.recursive:
928 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200929 else:
930 self.visit(node.iter, loop_frame)
931
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200932 if node.recursive:
933 self.write(', recurse=loop_render_func):')
934 else:
935 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200936
937 # tests in not extended loops become a continue
938 if not extended_loop and node.test is not None:
939 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200940 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200941 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200942 self.write(':')
943 self.indent()
944 self.writeline('continue')
945 self.outdent(2)
946
Armin Ronacherc9705c22008-04-27 21:28:03 +0200947 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200948 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200949 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200950
951 if node.else_:
952 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200953 self.indent()
954 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher625215e2008-04-13 16:31:08 +0200955 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200956 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200957
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200958 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200959 for name, alias in aliases.iteritems():
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200960 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200961
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200962 # if the node was recursive we have to return the buffer contents
963 # and start the iteration code
964 if node.recursive:
965 if self.environment.autoescape:
966 self.writeline('return Markup(concat(%s))' % buf)
967 else:
968 self.writeline('return concat(%s)' % buf)
969 self.outdent()
970 if frame.buffer is None:
971 self.writeline('yield loop(', node)
972 else:
973 self.writeline('%s.append(loop(' % frame.buffer, node)
974 self.visit(node.iter, frame)
975 self.write(', loop)')
976 if frame.buffer is not None:
977 self.write(')')
978
Armin Ronachere791c2a2008-04-07 18:39:54 +0200979 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200980 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200981 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200982 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200983 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200984 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200985 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200986 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200987 if node.else_:
988 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200989 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200990 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200991 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200992
Armin Ronacher8efc5222008-04-08 14:47:40 +0200993 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200994 macro_frame = self.function_scoping(node, frame)
995 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200996 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200997 macro_frame.buffer = buf = self.temporary_identifier()
998 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200999 self.pull_locals(macro_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +02001000 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001001 self.blockvisit(node.body, macro_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001002 if self.environment.autoescape:
1003 self.writeline('return Markup(concat(%s))' % buf)
1004 else:
1005 self.writeline("return concat(%s)" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +02001006 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001007 self.newline()
1008 if frame.toplevel:
Armin Ronacherc9705c22008-04-27 21:28:03 +02001009 if not node.name.startswith('__'):
1010 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001011 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001012 arg_tuple = ', '.join(repr(x.name) for x in node.args)
1013 if len(node.args) == 1:
1014 arg_tuple += ','
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001015 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
1016 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +02001017 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +02001018 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +02001019 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +02001020 self.write('), %s, %s, %s)' % (
1021 macro_frame.accesses_kwargs and '1' or '0',
1022 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +02001023 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +02001024 ))
1025
1026 def visit_CallBlock(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001027 call_frame = self.function_scoping(node, frame, node.iter_child_nodes
1028 (exclude=('call',)))
Armin Ronacher71082072008-04-12 14:19:36 +02001029 args = call_frame.arguments
1030 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +02001031 call_frame.buffer = buf = self.temporary_identifier()
1032 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +02001033 self.pull_locals(call_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +02001034 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001035 self.blockvisit(node.body, call_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001036 if self.environment.autoescape:
1037 self.writeline("return Markup(concat(%s))" % buf)
1038 else:
1039 self.writeline('return concat(%s)' % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +02001040 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +02001041 arg_tuple = ', '.join(repr(x.name) for x in node.args)
1042 if len(node.args) == 1:
1043 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +02001044 self.writeline('caller = Macro(environment, call, None, (%s), (' %
1045 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +02001046 for arg in node.defaults:
Armin Ronacherc9705c22008-04-27 21:28:03 +02001047 self.visit(arg, call_frame)
Armin Ronacher71082072008-04-12 14:19:36 +02001048 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +02001049 self.write('), %s, %s, 0)' % (
1050 call_frame.accesses_kwargs and '1' or '0',
1051 call_frame.accesses_varargs and '1' or '0'
1052 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001053 if frame.buffer is None:
1054 self.writeline('yield ', node)
1055 else:
1056 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +02001057 self.visit_Call(node.call, call_frame,
1058 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001059 if frame.buffer is not None:
1060 self.write(')')
1061
1062 def visit_FilterBlock(self, node, frame):
1063 filter_frame = frame.inner()
1064 filter_frame.inspect(node.iter_child_nodes())
1065
1066 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001067 self.pull_locals(filter_frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001068 filter_frame.buffer = buf = self.temporary_identifier()
1069
1070 self.writeline('%s = []' % buf, node)
1071 for child in node.body:
1072 self.visit(child, filter_frame)
1073
1074 if frame.buffer is None:
1075 self.writeline('yield ', node)
1076 else:
1077 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacherde6bf712008-04-26 01:44:14 +02001078 self.visit_Filter(node.filter, filter_frame, 'concat(%s)' % buf)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001079 if frame.buffer is not None:
1080 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001081
Armin Ronachere791c2a2008-04-07 18:39:54 +02001082 def visit_ExprStmt(self, node, frame):
1083 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001084 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001085
1086 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001087 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +02001088 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001089 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001090
Armin Ronacher75cfb862008-04-11 13:47:22 +02001091 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001092
Armin Ronacher7fb38972008-04-11 13:54:28 +02001093 # if we are in the toplevel scope and there was already an extends
1094 # statement we have to add a check that disables our yield(s) here
1095 # so that they don't appear in the output.
1096 outdent_later = False
1097 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001098 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001099 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001100 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001101
Armin Ronachere791c2a2008-04-07 18:39:54 +02001102 # try to evaluate as many chunks as possible into a static
1103 # string at compile time.
1104 body = []
1105 for child in node.nodes:
1106 try:
1107 const = unicode(child.as_const())
1108 except:
1109 body.append(child)
1110 continue
1111 if body and isinstance(body[-1], list):
1112 body[-1].append(const)
1113 else:
1114 body.append([const])
1115
Armin Ronacher32a910f2008-04-26 23:21:03 +02001116 # if we have less than 3 nodes or less than 6 and a buffer we
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001117 # yield or extend/append
Armin Ronacher32a910f2008-04-26 23:21:03 +02001118 if len(body) < 3 or (frame.buffer is not None and len(body) < 6):
1119 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001120 # for one item we append, for more we extend
1121 if len(body) == 1:
1122 self.writeline('%s.append(' % frame.buffer)
1123 else:
1124 self.writeline('%s.extend((' % frame.buffer)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001125 for item in body:
1126 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001127 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001128 if frame.buffer is None:
1129 self.writeline('yield ' + val)
1130 else:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001131 self.write(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001132 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001133 if frame.buffer is None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001134 self.writeline('yield ')
Armin Ronacherd1342312008-04-28 12:20:12 +02001135 close = 1
1136 if self.environment.autoescape:
1137 self.write('escape(')
1138 else:
1139 self.write('unicode(')
1140 if self.environment.finalize is not None:
1141 self.write('environment.finalize(')
1142 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001143 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001144 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001145 if frame.buffer is not None:
1146 self.write(', ')
1147 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001148 # close the open parentheses
1149 self.write(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001150
1151 # otherwise we create a format string as this is faster in that case
1152 else:
1153 format = []
1154 arguments = []
1155 for item in body:
1156 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001157 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001158 else:
1159 format.append('%s')
1160 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001161 if frame.buffer is None:
1162 self.writeline('yield ')
1163 else:
1164 self.writeline('%s.append(' % frame.buffer)
Armin Ronacherde6bf712008-04-26 01:44:14 +02001165 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001166 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001167 self.indent()
1168 for argument in arguments:
1169 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001170 close = 0
1171 if self.environment.autoescape:
1172 self.write('escape(')
1173 close += 1
1174 if self.environment.finalize is not None:
1175 self.write('environment.finalize(')
1176 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001177 self.visit(argument, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001178 self.write(')' * close + ',')
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001179 self.outdent()
1180 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001181 if frame.buffer is not None:
1182 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001183
Armin Ronacher7fb38972008-04-11 13:54:28 +02001184 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001185 self.outdent()
1186
Armin Ronacher8efc5222008-04-08 14:47:40 +02001187 def visit_Assign(self, node, frame):
1188 self.newline(node)
1189 # toplevel assignments however go into the local namespace and
1190 # the current template's context. We create a copy of the frame
1191 # here and add a set so that the Name visitor can add the assigned
1192 # names here.
1193 if frame.toplevel:
1194 assignment_frame = frame.copy()
1195 assignment_frame.assigned_names = set()
1196 else:
1197 assignment_frame = frame
1198 self.visit(node.target, assignment_frame)
1199 self.write(' = ')
1200 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001201
1202 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001203 if frame.toplevel:
Armin Ronacher69e12db2008-05-12 09:00:03 +02001204 public_names = [x for x in assignment_frame.assigned_names
1205 if not x.startswith('__')]
1206 if len(assignment_frame.assigned_names) == 1:
1207 name = iter(assignment_frame.assigned_names).next()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001208 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001209 else:
1210 self.writeline('context.vars.update({')
1211 for idx, name in enumerate(assignment_frame.assigned_names):
1212 if idx:
1213 self.write(', ')
1214 self.write('%r: l_%s' % (name, name))
1215 self.write('})')
1216 if public_names:
1217 if len(public_names) == 1:
1218 self.writeline('context.exported_vars.add(%r)' %
1219 public_names[0])
1220 else:
1221 self.writeline('context.exported_vars.update((%s))' %
1222 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001223
Armin Ronachere791c2a2008-04-07 18:39:54 +02001224 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001225 if node.ctx == 'store' and frame.toplevel:
1226 frame.assigned_names.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001227 self.write('l_' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001228
Armin Ronacherd84ec462008-04-29 13:43:16 +02001229 def visit_MarkSafe(self, node, frame):
1230 self.write('Markup(')
1231 self.visit(node.expr, frame)
1232 self.write(')')
1233
Armin Ronacher023b5e92008-05-08 11:03:10 +02001234 def visit_EnvironmentAttribute(self, node, frame):
1235 self.write('environment.' + node.name)
1236
1237 def visit_ExtensionAttribute(self, node, frame):
1238 self.write('environment.extensions[%r].%s' % (node.identifier, node.attr))
1239
1240 def visit_ImportedName(self, node, frame):
1241 self.write(self.import_aliases[node.importname])
1242
1243 def visit_InternalName(self, node, frame):
1244 self.write(node.name)
1245
Armin Ronachere791c2a2008-04-07 18:39:54 +02001246 def visit_Const(self, node, frame):
1247 val = node.value
1248 if isinstance(val, float):
1249 # XXX: add checks for infinity and nan
1250 self.write(str(val))
1251 else:
1252 self.write(repr(val))
1253
Armin Ronacher8efc5222008-04-08 14:47:40 +02001254 def visit_Tuple(self, node, frame):
1255 self.write('(')
1256 idx = -1
1257 for idx, item in enumerate(node.items):
1258 if idx:
1259 self.write(', ')
1260 self.visit(item, frame)
1261 self.write(idx == 0 and ',)' or ')')
1262
Armin Ronacher8edbe492008-04-10 20:43:43 +02001263 def visit_List(self, node, frame):
1264 self.write('[')
1265 for idx, item in enumerate(node.items):
1266 if idx:
1267 self.write(', ')
1268 self.visit(item, frame)
1269 self.write(']')
1270
1271 def visit_Dict(self, node, frame):
1272 self.write('{')
1273 for idx, item in enumerate(node.items):
1274 if idx:
1275 self.write(', ')
1276 self.visit(item.key, frame)
1277 self.write(': ')
1278 self.visit(item.value, frame)
1279 self.write('}')
1280
Armin Ronachere791c2a2008-04-07 18:39:54 +02001281 def binop(operator):
1282 def visitor(self, node, frame):
1283 self.write('(')
1284 self.visit(node.left, frame)
1285 self.write(' %s ' % operator)
1286 self.visit(node.right, frame)
1287 self.write(')')
1288 return visitor
1289
1290 def uaop(operator):
1291 def visitor(self, node, frame):
1292 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001293 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001294 self.write(')')
1295 return visitor
1296
1297 visit_Add = binop('+')
1298 visit_Sub = binop('-')
1299 visit_Mul = binop('*')
1300 visit_Div = binop('/')
1301 visit_FloorDiv = binop('//')
1302 visit_Pow = binop('**')
1303 visit_Mod = binop('%')
1304 visit_And = binop('and')
1305 visit_Or = binop('or')
1306 visit_Pos = uaop('+')
1307 visit_Neg = uaop('-')
1308 visit_Not = uaop('not ')
1309 del binop, uaop
1310
Armin Ronacherd1342312008-04-28 12:20:12 +02001311 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001312 self.write('%s((' % (self.environment.autoescape and
1313 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001314 for arg in node.nodes:
1315 self.visit(arg, frame)
1316 self.write(', ')
1317 self.write('))')
1318
Armin Ronachere791c2a2008-04-07 18:39:54 +02001319 def visit_Compare(self, node, frame):
1320 self.visit(node.expr, frame)
1321 for op in node.ops:
1322 self.visit(op, frame)
1323
1324 def visit_Operand(self, node, frame):
1325 self.write(' %s ' % operators[node.op])
1326 self.visit(node.expr, frame)
1327
1328 def visit_Subscript(self, node, frame):
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +02001329 # subscripts can have overlays
1330 if self.overlay(node, frame):
1331 return
1332
Armin Ronacher08a6a3b2008-05-13 15:35:47 +02001333 # slices or integer subscriptions bypass the subscribe
1334 # method if we can determine that at compile time.
1335 if isinstance(node.arg, nodes.Slice) or \
1336 (isinstance(node.arg, nodes.Const) and
1337 isinstance(node.arg.value, (int, long))):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001338 self.visit(node.node, frame)
1339 self.write('[')
1340 self.visit(node.arg, frame)
1341 self.write(']')
1342 return
1343 try:
1344 const = node.arg.as_const()
1345 have_const = True
1346 except nodes.Impossible:
1347 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001348 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001349 self.visit(node.node, frame)
1350 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001351 if have_const:
1352 self.write(repr(const))
1353 else:
1354 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001355 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001356
1357 def visit_Slice(self, node, frame):
1358 if node.start is not None:
1359 self.visit(node.start, frame)
1360 self.write(':')
1361 if node.stop is not None:
1362 self.visit(node.stop, frame)
1363 if node.step is not None:
1364 self.write(':')
1365 self.visit(node.step, frame)
1366
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001367 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001368 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001369 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001370 if func is None:
1371 raise TemplateAssertionError('no filter named %r' % node.name,
1372 node.lineno, self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001373 if getattr(func, 'contextfilter', False):
1374 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001375 elif getattr(func, 'environmentfilter', False):
1376 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001377 if isinstance(node.node, nodes.Filter):
1378 self.visit_Filter(node.node, frame, initial)
1379 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001380 self.write(initial)
1381 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001382 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001383 self.signature(node, frame)
1384 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001385
1386 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001387 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001388 if node.name not in self.environment.tests:
1389 raise TemplateAssertionError('no test named %r' % node.name,
1390 node.lineno, self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001391 self.visit(node.node, frame)
1392 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001393 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001394
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001395 def visit_CondExpr(self, node, frame):
1396 if not have_condexpr:
1397 self.write('((')
1398 self.visit(node.test, frame)
1399 self.write(') and (')
1400 self.visit(node.expr1, frame)
1401 self.write(',) or (')
1402 self.visit(node.expr2, frame)
1403 self.write(',))[0]')
1404 else:
1405 self.write('(')
1406 self.visit(node.expr1, frame)
1407 self.write(' if ')
1408 self.visit(node.test, frame)
1409 self.write(' else ')
1410 self.visit(node.expr2, frame)
1411 self.write(')')
1412
Armin Ronacher71082072008-04-12 14:19:36 +02001413 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001414 if self.environment.sandboxed:
1415 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001416 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001417 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001418 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001419 self.write(')')
1420
1421 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001422 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001423 self.visit(node.value, frame)