blob: 9f99045bbac37756198b80918b75114cbc8573e7 [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 Ronachere9411b42008-05-15 16:22:07 +0200257 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200258 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200259 elif node.ctx == 'param':
260 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200261 elif node.ctx == 'load' and not \
262 self.identifiers.is_declared(node.name, self.hard_scope):
263 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200264
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200265 def visit_Subscript(self, node):
266 """Under some circumstances subscripts are aliased with local names:
267
268 - the subscript node is either already aliased or a name that was not
269 reassigned.
270 - and the subscription argument is a constant string.
271 """
272 self.generic_visit(node)
273 if isinstance(node.arg, nodes.Const) and \
274 isinstance(node.arg.value, basestring) and \
Armin Ronacher151418d2008-05-15 15:00:45 +0200275 ((isinstance(node.node, nodes.Name) and
Armin Ronacherdc02b642008-05-15 22:47:27 +0200276 # this code ignores parameter declared names as the may only
277 # occour at the very beginning of a scope and we pull the
278 # attributes afterwards.
Armin Ronachere9411b42008-05-15 16:22:07 +0200279 node.node.name not in (self.identifiers.declared_locally)) or
Armin Ronacher151418d2008-05-15 15:00:45 +0200280 node.node in self.identifiers.static_subscribes):
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200281 if node in self.identifiers.static_subscribes:
282 self.identifiers.static_subscribes[node] += 1
283 else:
284 self.identifiers.static_subscribes[node] = 1
285
Armin Ronacherc9705c22008-04-27 21:28:03 +0200286 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200287 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200288
Armin Ronacherc9705c22008-04-27 21:28:03 +0200289 def visit_Import(self, node):
290 self.generic_visit(node)
291 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200292
Armin Ronacherc9705c22008-04-27 21:28:03 +0200293 def visit_FromImport(self, node):
294 self.generic_visit(node)
295 for name in node.names:
296 if isinstance(name, tuple):
297 self.identifiers.declared_locally.add(name[1])
298 else:
299 self.identifiers.declared_locally.add(name)
300
301 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200302 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200303 self.visit(node.node)
304 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200305
Armin Ronacherc9705c22008-04-27 21:28:03 +0200306 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200307 """Visiting stops at for blocks. However the block sequence
308 is visited as part of the outer scope.
309 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200310 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200311
Armin Ronacherc9705c22008-04-27 21:28:03 +0200312 def visit_CallBlock(self, node):
313 for child in node.iter_child_nodes(exclude=('body',)):
314 self.visit(child)
315
316 def visit_FilterBlock(self, node):
317 self.visit(node.filter)
318
319 def visit_Block(self, node):
320 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200321
322
Armin Ronacher75cfb862008-04-11 13:47:22 +0200323class CompilerExit(Exception):
324 """Raised if the compiler encountered a situation where it just
325 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200326 raises such an exception is not further processed.
327 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200328
329
Armin Ronachere791c2a2008-04-07 18:39:54 +0200330class CodeGenerator(NodeVisitor):
331
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200332 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200333 if stream is None:
334 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200335 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200336 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200337 self.filename = filename
338 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200339
Armin Ronacher023b5e92008-05-08 11:03:10 +0200340 # aliases for imports
341 self.import_aliases = {}
342
Armin Ronacherfed44b52008-04-13 19:42:53 +0200343 # a registry for all blocks. Because blocks are moved out
344 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200345 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200346
347 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200348 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200349
350 # some templates have a rootlevel extends. In this case we
351 # can safely assume that we're a child template and do some
352 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200353 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200354
Armin Ronacherba3757b2008-04-16 19:43:16 +0200355 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200356 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200357
Armin Ronacherb9e78752008-05-10 23:36:28 +0200358 # registry of all filters and tests (global, not block local)
359 self.tests = {}
360 self.filters = {}
361
Armin Ronacherba3757b2008-04-16 19:43:16 +0200362 # the debug information
363 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200364 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200365
Armin Ronacherfed44b52008-04-13 19:42:53 +0200366 # the number of new lines before the next write()
367 self._new_lines = 0
368
369 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200370 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200371
372 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200373 self._first_write = True
374
Armin Ronacherfed44b52008-04-13 19:42:53 +0200375 # used by the `temporary_identifier` method to get new
376 # unique, temporary identifier
377 self._last_identifier = 0
378
379 # the current indentation
380 self._indentation = 0
381
Armin Ronachere791c2a2008-04-07 18:39:54 +0200382 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200383 """Get a new unique identifier."""
384 self._last_identifier += 1
385 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200386
387 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200388 """Indent by one."""
389 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200390
Armin Ronacher8efc5222008-04-08 14:47:40 +0200391 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200392 """Outdent by step."""
393 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200394
Armin Ronacherc9705c22008-04-27 21:28:03 +0200395 def blockvisit(self, nodes, frame, force_generator=True):
396 """Visit a list of nodes as block in a frame. If the current frame
397 is no buffer a dummy ``if 0: yield None`` is written automatically
398 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200399 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200400 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200401 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200402 try:
403 for node in nodes:
404 self.visit(node, frame)
405 except CompilerExit:
406 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200407
408 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200409 """Write a string into the output stream."""
410 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200411 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200412 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200413 self.code_lineno += self._new_lines
414 if self._write_debug_info is not None:
415 self.debug_info.append((self._write_debug_info,
416 self.code_lineno))
417 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200418 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200419 self.stream.write(' ' * self._indentation)
420 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200421 self.stream.write(x)
422
423 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200424 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200425 self.newline(node, extra)
426 self.write(x)
427
428 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200429 """Add one or more newlines before the next write."""
430 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200431 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200432 self._write_debug_info = node.lineno
433 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200434
Armin Ronacher71082072008-04-12 14:19:36 +0200435 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200436 """Writes a function call to the stream for the current node.
437 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200438 disabled by setting have_comma to False. The extra keyword
439 arguments may not include python keywords otherwise a syntax
440 error could occour. The extra keyword arguments should be given
441 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200442 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200443 have_comma = have_comma and [True] or []
444 def touch_comma():
445 if have_comma:
446 self.write(', ')
447 else:
448 have_comma.append(True)
449
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200450 # if any of the given keyword arguments is a python keyword
451 # we have to make sure that no invalid call is created.
452 kwarg_workaround = False
453 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
454 if iskeyword(kwarg):
455 kwarg_workaround = True
456 break
457
Armin Ronacher8efc5222008-04-08 14:47:40 +0200458 for arg in node.args:
459 touch_comma()
460 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200461
462 if not kwarg_workaround:
463 for kwarg in node.kwargs:
464 touch_comma()
465 self.visit(kwarg, frame)
466 if extra_kwargs is not None:
467 for key, value in extra_kwargs.iteritems():
468 touch_comma()
469 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200470 if node.dyn_args:
471 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200472 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200473 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200474
475 if kwarg_workaround:
476 touch_comma()
477 if node.dyn_kwargs is not None:
478 self.write('**dict({')
479 else:
480 self.write('**{')
481 for kwarg in node.kwargs:
482 self.write('%r: ' % kwarg.key)
483 self.visit(kwarg.value, frame)
484 self.write(', ')
485 if extra_kwargs is not None:
486 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200487 self.write('%r: %s, ' % (key, value))
488 if node.dyn_kwargs is not None:
489 self.write('}, **')
490 self.visit(node.dyn_kwargs, frame)
491 self.write(')')
492 else:
493 self.write('}')
494
495 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200496 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200497 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200498 self.visit(node.dyn_kwargs, frame)
499
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200500 def overlay(self, node, frame):
501 """Visit an overlay and return `True` or `False` if the overlay
502 does not exist or is exhausted. An overlay is used to replace a
503 node with another one (or an identifier) N times. This is for
504 example used to replace static subscribes before reassignments
505 of a name that occour more than one time. If a node has overlays
506 it's important that this method is called, otherwise the count
507 will be out of sync and the generated code is broken.
508 """
509 if node not in frame.overlays:
510 return False
511 overlay, count = frame.overlays[node]
512 if count is not None and count <= 0:
513 return False
514 if isinstance(overlay, basestring):
515 self.write(overlay)
516 else:
517 self.visit(overlay, frame)
518 frame.overlays[node] = (overlay, count - 1)
519 return True
520
Armin Ronacherc9705c22008-04-27 21:28:03 +0200521 def pull_locals(self, frame):
522 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200523 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200524 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200525
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200526 # find all the static subscribes with a count > 2 and
527 # order them properly so that subscribes depending on other
528 # subscribes are handled later.
529 static_subscribes = [(node, count) for node, count in
530 frame.identifiers.static_subscribes.items() if
531 count >= 2]
532 if static_subscribes:
533 static_subscribes.sort(key=lambda x: type(x[0].node)
534 is nodes.Subscript)
535 for node, count in static_subscribes:
536 ident = self.temporary_identifier()
Armin Ronachera7f016d2008-05-16 00:22:40 +0200537 self.writeline(ident + ' = ', node)
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200538 self.visit(node, frame)
539 frame.overlays[node] = (ident, count)
540
Armin Ronacherc9705c22008-04-27 21:28:03 +0200541 def pull_dependencies(self, nodes):
542 """Pull all the dependencies."""
543 visitor = DependencyFinderVisitor()
544 for node in nodes:
545 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200546 for dependency in 'filters', 'tests':
547 mapping = getattr(self, dependency)
548 for name in getattr(visitor, dependency):
549 if name not in mapping:
550 mapping[name] = self.temporary_identifier()
551 self.writeline('%s = environment.%s[%r]' %
552 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200553
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200554 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200555 """This function returns all the shadowed variables in a dict
556 in the form name: alias and will write the required assignments
557 into the current scope. No indentation takes place.
558 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200559 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 Ronacherdc02b642008-05-15 22:47:27 +0200667 self.writeline('name = %r' % self.name)
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 Ronachera78d2762008-05-15 23:18:07 +0200841
842 var_names = []
843 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200844 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200845 if isinstance(name, tuple):
846 name, alias = name
847 else:
848 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200849 self.writeline('l_%s = getattr(included_template, '
850 '%r, missing)' % (alias, name))
851 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200852 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200853 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +0200854 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200855 'name=%r)' %
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200856 (alias, 'the template %r does not export '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200857 'the requested name ' + repr(name), name))
Armin Ronacher0611e492008-04-25 23:44:14 +0200858 self.outdent()
859 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +0200860 var_names.append(alias)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200861 if not alias.startswith('__'):
Armin Ronachera78d2762008-05-15 23:18:07 +0200862 discarded_names.append(alias)
863
864 if var_names:
865 if len(var_names) == 1:
866 name = var_names[0]
867 self.writeline('context.vars[%r] = l_%s' % (name, name))
868 else:
869 self.writeline('context.vars.update({%s})' % ', '.join(
870 '%r: l_%s' % (name, name) for name in var_names
871 ))
872 if discarded_names:
873 if len(discarded_names) == 1:
874 self.writeline('context.exported_vars.discard(%r)' %
875 discarded_names[0])
876 else:
877 self.writeline('context.exported_vars.difference_'
878 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200879
Armin Ronachere791c2a2008-04-07 18:39:54 +0200880 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200881 # when calculating the nodes for the inner frame we have to exclude
882 # the iterator contents from it
883 children = node.iter_child_nodes(exclude=('iter',))
884
885 if node.recursive:
886 loop_frame = self.function_scoping(node, frame, children,
887 find_special=False)
888 else:
889 loop_frame = frame.inner()
890 loop_frame.inspect(children)
891
892 extended_loop = node.recursive or node.else_ or \
Armin Ronachere791c2a2008-04-07 18:39:54 +0200893 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200894 if extended_loop:
895 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200896
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200897 # if we don't have an recursive loop we have to find the shadowed
898 # variables at that point
899 if not node.recursive:
900 aliases = self.collect_shadowed(loop_frame)
901
902 # otherwise we set up a buffer and add a function def
903 else:
904 loop_frame.buffer = buf = self.temporary_identifier()
905 self.writeline('def loop(reciter, loop_render_func):', node)
906 self.indent()
907 self.writeline('%s = []' % buf, node)
908 aliases = {}
909
Armin Ronacherc9705c22008-04-27 21:28:03 +0200910 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200911 if node.else_:
912 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200913
914 self.newline(node)
915 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200916 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200917 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200918
919 # the expression pointing to the parent loop. We make the
920 # undefined a bit more debug friendly at the same time.
921 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200922 or "environment.undefined(%r, name='loop')" % "'loop' " \
923 'is undefined. "the filter section of a loop as well ' \
924 'as the else block doesn\'t have access to the ' \
925 "special 'loop' variable of the current loop. " \
926 "Because there is no parent loop it's undefined."
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200927
928 # if we have an extened loop and a node test, we filter in the
929 # "outer frame".
930 if extended_loop and node.test is not None:
931 self.write('(')
932 self.visit(node.target, loop_frame)
933 self.write(' for ')
934 self.visit(node.target, loop_frame)
935 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200936 if node.recursive:
937 self.write('reciter')
938 else:
939 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200940 self.write(' if (')
941 test_frame = loop_frame.copy()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200942 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200943 self.visit(node.test, test_frame)
944 self.write('))')
945
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200946 elif node.recursive:
947 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200948 else:
949 self.visit(node.iter, loop_frame)
950
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200951 if node.recursive:
952 self.write(', recurse=loop_render_func):')
953 else:
954 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200955
956 # tests in not extended loops become a continue
957 if not extended_loop and node.test is not None:
958 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200959 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200960 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200961 self.write(':')
962 self.indent()
963 self.writeline('continue')
964 self.outdent(2)
965
Armin Ronacherc9705c22008-04-27 21:28:03 +0200966 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200967 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200968 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200969
970 if node.else_:
971 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200972 self.indent()
973 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher625215e2008-04-13 16:31:08 +0200974 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200975 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200976
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200977 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200978 for name, alias in aliases.iteritems():
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200979 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200980
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200981 # if the node was recursive we have to return the buffer contents
982 # and start the iteration code
983 if node.recursive:
984 if self.environment.autoescape:
985 self.writeline('return Markup(concat(%s))' % buf)
986 else:
987 self.writeline('return concat(%s)' % buf)
988 self.outdent()
989 if frame.buffer is None:
990 self.writeline('yield loop(', node)
991 else:
992 self.writeline('%s.append(loop(' % frame.buffer, node)
993 self.visit(node.iter, frame)
994 self.write(', loop)')
995 if frame.buffer is not None:
996 self.write(')')
997
Armin Ronachere791c2a2008-04-07 18:39:54 +0200998 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200999 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001000 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001001 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001002 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001003 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001004 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001005 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001006 if node.else_:
1007 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001008 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001009 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001010 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001011
Armin Ronacher8efc5222008-04-08 14:47:40 +02001012 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +02001013 macro_frame = self.function_scoping(node, frame)
1014 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +02001015 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +02001016 macro_frame.buffer = buf = self.temporary_identifier()
1017 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +02001018 self.pull_locals(macro_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +02001019 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001020 self.blockvisit(node.body, macro_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001021 if self.environment.autoescape:
1022 self.writeline('return Markup(concat(%s))' % buf)
1023 else:
1024 self.writeline("return concat(%s)" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +02001025 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001026 self.newline()
1027 if frame.toplevel:
Armin Ronacherc9705c22008-04-27 21:28:03 +02001028 if not node.name.startswith('__'):
1029 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001030 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001031 arg_tuple = ', '.join(repr(x.name) for x in node.args)
1032 if len(node.args) == 1:
1033 arg_tuple += ','
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001034 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
1035 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +02001036 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +02001037 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +02001038 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +02001039 self.write('), %s, %s, %s)' % (
1040 macro_frame.accesses_kwargs and '1' or '0',
1041 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +02001042 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +02001043 ))
1044
1045 def visit_CallBlock(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001046 call_frame = self.function_scoping(node, frame, node.iter_child_nodes
1047 (exclude=('call',)))
Armin Ronacher71082072008-04-12 14:19:36 +02001048 args = call_frame.arguments
1049 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +02001050 call_frame.buffer = buf = self.temporary_identifier()
1051 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +02001052 self.pull_locals(call_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +02001053 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001054 self.blockvisit(node.body, call_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001055 if self.environment.autoescape:
1056 self.writeline("return Markup(concat(%s))" % buf)
1057 else:
1058 self.writeline('return concat(%s)' % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +02001059 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +02001060 arg_tuple = ', '.join(repr(x.name) for x in node.args)
1061 if len(node.args) == 1:
1062 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +02001063 self.writeline('caller = Macro(environment, call, None, (%s), (' %
1064 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +02001065 for arg in node.defaults:
Armin Ronacherc9705c22008-04-27 21:28:03 +02001066 self.visit(arg, call_frame)
Armin Ronacher71082072008-04-12 14:19:36 +02001067 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +02001068 self.write('), %s, %s, 0)' % (
1069 call_frame.accesses_kwargs and '1' or '0',
1070 call_frame.accesses_varargs and '1' or '0'
1071 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001072 if frame.buffer is None:
1073 self.writeline('yield ', node)
1074 else:
1075 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +02001076 self.visit_Call(node.call, call_frame,
1077 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001078 if frame.buffer is not None:
1079 self.write(')')
1080
1081 def visit_FilterBlock(self, node, frame):
1082 filter_frame = frame.inner()
1083 filter_frame.inspect(node.iter_child_nodes())
1084
1085 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001086 self.pull_locals(filter_frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001087 filter_frame.buffer = buf = self.temporary_identifier()
1088
1089 self.writeline('%s = []' % buf, node)
1090 for child in node.body:
1091 self.visit(child, filter_frame)
1092
1093 if frame.buffer is None:
1094 self.writeline('yield ', node)
1095 else:
1096 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacherde6bf712008-04-26 01:44:14 +02001097 self.visit_Filter(node.filter, filter_frame, 'concat(%s)' % buf)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001098 if frame.buffer is not None:
1099 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001100
Armin Ronachere791c2a2008-04-07 18:39:54 +02001101 def visit_ExprStmt(self, node, frame):
1102 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001103 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001104
1105 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001106 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +02001107 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001108 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001109
Armin Ronacher75cfb862008-04-11 13:47:22 +02001110 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001111
Armin Ronacher7fb38972008-04-11 13:54:28 +02001112 # if we are in the toplevel scope and there was already an extends
1113 # statement we have to add a check that disables our yield(s) here
1114 # so that they don't appear in the output.
1115 outdent_later = False
1116 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001117 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001118 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001119 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001120
Armin Ronachere791c2a2008-04-07 18:39:54 +02001121 # try to evaluate as many chunks as possible into a static
1122 # string at compile time.
1123 body = []
1124 for child in node.nodes:
1125 try:
1126 const = unicode(child.as_const())
1127 except:
1128 body.append(child)
1129 continue
1130 if body and isinstance(body[-1], list):
1131 body[-1].append(const)
1132 else:
1133 body.append([const])
1134
Armin Ronacher32a910f2008-04-26 23:21:03 +02001135 # if we have less than 3 nodes or less than 6 and a buffer we
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001136 # yield or extend/append
Armin Ronacher32a910f2008-04-26 23:21:03 +02001137 if len(body) < 3 or (frame.buffer is not None and len(body) < 6):
1138 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001139 # for one item we append, for more we extend
1140 if len(body) == 1:
1141 self.writeline('%s.append(' % frame.buffer)
1142 else:
1143 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001144 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001145 for item in body:
1146 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001147 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001148 if frame.buffer is None:
1149 self.writeline('yield ' + val)
1150 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001151 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001152 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001153 if frame.buffer is None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001154 self.writeline('yield ')
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001155 else:
1156 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001157 close = 1
1158 if self.environment.autoescape:
1159 self.write('escape(')
1160 else:
1161 self.write('unicode(')
1162 if self.environment.finalize is not None:
1163 self.write('environment.finalize(')
1164 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001165 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001166 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001167 if frame.buffer is not None:
1168 self.write(', ')
1169 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001170 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001171 self.outdent()
1172 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001173
1174 # otherwise we create a format string as this is faster in that case
1175 else:
1176 format = []
1177 arguments = []
1178 for item in body:
1179 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001180 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001181 else:
1182 format.append('%s')
1183 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001184 if frame.buffer is None:
1185 self.writeline('yield ')
1186 else:
1187 self.writeline('%s.append(' % frame.buffer)
Armin Ronacherde6bf712008-04-26 01:44:14 +02001188 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001189 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001190 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001191 for argument in arguments:
Armin Ronachera7f016d2008-05-16 00:22:40 +02001192 self.newline()
Armin Ronacherd1342312008-04-28 12:20:12 +02001193 close = 0
1194 if self.environment.autoescape:
1195 self.write('escape(')
1196 close += 1
1197 if self.environment.finalize is not None:
1198 self.write('environment.finalize(')
1199 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001200 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001201 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001202 self.outdent()
1203 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001204 if frame.buffer is not None:
1205 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001206
Armin Ronacher7fb38972008-04-11 13:54:28 +02001207 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001208 self.outdent()
1209
Armin Ronacher8efc5222008-04-08 14:47:40 +02001210 def visit_Assign(self, node, frame):
1211 self.newline(node)
1212 # toplevel assignments however go into the local namespace and
1213 # the current template's context. We create a copy of the frame
1214 # here and add a set so that the Name visitor can add the assigned
1215 # names here.
1216 if frame.toplevel:
1217 assignment_frame = frame.copy()
1218 assignment_frame.assigned_names = set()
1219 else:
1220 assignment_frame = frame
1221 self.visit(node.target, assignment_frame)
1222 self.write(' = ')
1223 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001224
1225 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001226 if frame.toplevel:
Armin Ronacher69e12db2008-05-12 09:00:03 +02001227 public_names = [x for x in assignment_frame.assigned_names
1228 if not x.startswith('__')]
1229 if len(assignment_frame.assigned_names) == 1:
1230 name = iter(assignment_frame.assigned_names).next()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001231 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001232 else:
1233 self.writeline('context.vars.update({')
1234 for idx, name in enumerate(assignment_frame.assigned_names):
1235 if idx:
1236 self.write(', ')
1237 self.write('%r: l_%s' % (name, name))
1238 self.write('})')
1239 if public_names:
1240 if len(public_names) == 1:
1241 self.writeline('context.exported_vars.add(%r)' %
1242 public_names[0])
1243 else:
1244 self.writeline('context.exported_vars.update((%s))' %
1245 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001246
Armin Ronachere791c2a2008-04-07 18:39:54 +02001247 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001248 if node.ctx == 'store' and frame.toplevel:
1249 frame.assigned_names.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001250 self.write('l_' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001251
Armin Ronacherd84ec462008-04-29 13:43:16 +02001252 def visit_MarkSafe(self, node, frame):
1253 self.write('Markup(')
1254 self.visit(node.expr, frame)
1255 self.write(')')
1256
Armin Ronacher023b5e92008-05-08 11:03:10 +02001257 def visit_EnvironmentAttribute(self, node, frame):
1258 self.write('environment.' + node.name)
1259
1260 def visit_ExtensionAttribute(self, node, frame):
1261 self.write('environment.extensions[%r].%s' % (node.identifier, node.attr))
1262
1263 def visit_ImportedName(self, node, frame):
1264 self.write(self.import_aliases[node.importname])
1265
1266 def visit_InternalName(self, node, frame):
1267 self.write(node.name)
1268
Armin Ronachere791c2a2008-04-07 18:39:54 +02001269 def visit_Const(self, node, frame):
1270 val = node.value
1271 if isinstance(val, float):
1272 # XXX: add checks for infinity and nan
1273 self.write(str(val))
1274 else:
1275 self.write(repr(val))
1276
Armin Ronacher8efc5222008-04-08 14:47:40 +02001277 def visit_Tuple(self, node, frame):
1278 self.write('(')
1279 idx = -1
1280 for idx, item in enumerate(node.items):
1281 if idx:
1282 self.write(', ')
1283 self.visit(item, frame)
1284 self.write(idx == 0 and ',)' or ')')
1285
Armin Ronacher8edbe492008-04-10 20:43:43 +02001286 def visit_List(self, node, frame):
1287 self.write('[')
1288 for idx, item in enumerate(node.items):
1289 if idx:
1290 self.write(', ')
1291 self.visit(item, frame)
1292 self.write(']')
1293
1294 def visit_Dict(self, node, frame):
1295 self.write('{')
1296 for idx, item in enumerate(node.items):
1297 if idx:
1298 self.write(', ')
1299 self.visit(item.key, frame)
1300 self.write(': ')
1301 self.visit(item.value, frame)
1302 self.write('}')
1303
Armin Ronachere791c2a2008-04-07 18:39:54 +02001304 def binop(operator):
1305 def visitor(self, node, frame):
1306 self.write('(')
1307 self.visit(node.left, frame)
1308 self.write(' %s ' % operator)
1309 self.visit(node.right, frame)
1310 self.write(')')
1311 return visitor
1312
1313 def uaop(operator):
1314 def visitor(self, node, frame):
1315 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001316 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001317 self.write(')')
1318 return visitor
1319
1320 visit_Add = binop('+')
1321 visit_Sub = binop('-')
1322 visit_Mul = binop('*')
1323 visit_Div = binop('/')
1324 visit_FloorDiv = binop('//')
1325 visit_Pow = binop('**')
1326 visit_Mod = binop('%')
1327 visit_And = binop('and')
1328 visit_Or = binop('or')
1329 visit_Pos = uaop('+')
1330 visit_Neg = uaop('-')
1331 visit_Not = uaop('not ')
1332 del binop, uaop
1333
Armin Ronacherd1342312008-04-28 12:20:12 +02001334 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001335 self.write('%s((' % (self.environment.autoescape and
1336 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001337 for arg in node.nodes:
1338 self.visit(arg, frame)
1339 self.write(', ')
1340 self.write('))')
1341
Armin Ronachere791c2a2008-04-07 18:39:54 +02001342 def visit_Compare(self, node, frame):
1343 self.visit(node.expr, frame)
1344 for op in node.ops:
1345 self.visit(op, frame)
1346
1347 def visit_Operand(self, node, frame):
1348 self.write(' %s ' % operators[node.op])
1349 self.visit(node.expr, frame)
1350
1351 def visit_Subscript(self, node, frame):
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +02001352 # subscripts can have overlays
1353 if self.overlay(node, frame):
1354 return
1355
Armin Ronacher08a6a3b2008-05-13 15:35:47 +02001356 # slices or integer subscriptions bypass the subscribe
1357 # method if we can determine that at compile time.
1358 if isinstance(node.arg, nodes.Slice) or \
1359 (isinstance(node.arg, nodes.Const) and
1360 isinstance(node.arg.value, (int, long))):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001361 self.visit(node.node, frame)
1362 self.write('[')
1363 self.visit(node.arg, frame)
1364 self.write(']')
1365 return
1366 try:
1367 const = node.arg.as_const()
1368 have_const = True
1369 except nodes.Impossible:
1370 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001371 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001372 self.visit(node.node, frame)
1373 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001374 if have_const:
1375 self.write(repr(const))
1376 else:
1377 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001378 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001379
1380 def visit_Slice(self, node, frame):
1381 if node.start is not None:
1382 self.visit(node.start, frame)
1383 self.write(':')
1384 if node.stop is not None:
1385 self.visit(node.stop, frame)
1386 if node.step is not None:
1387 self.write(':')
1388 self.visit(node.step, frame)
1389
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001390 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001391 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001392 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001393 if func is None:
1394 raise TemplateAssertionError('no filter named %r' % node.name,
1395 node.lineno, self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001396 if getattr(func, 'contextfilter', False):
1397 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001398 elif getattr(func, 'environmentfilter', False):
1399 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001400 if isinstance(node.node, nodes.Filter):
1401 self.visit_Filter(node.node, frame, initial)
1402 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001403 self.write(initial)
1404 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001405 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001406 self.signature(node, frame)
1407 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001408
1409 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001410 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001411 if node.name not in self.environment.tests:
1412 raise TemplateAssertionError('no test named %r' % node.name,
1413 node.lineno, self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001414 self.visit(node.node, frame)
1415 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001416 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001417
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001418 def visit_CondExpr(self, node, frame):
1419 if not have_condexpr:
1420 self.write('((')
1421 self.visit(node.test, frame)
1422 self.write(') and (')
1423 self.visit(node.expr1, frame)
1424 self.write(',) or (')
1425 self.visit(node.expr2, frame)
1426 self.write(',))[0]')
1427 else:
1428 self.write('(')
1429 self.visit(node.expr1, frame)
1430 self.write(' if ')
1431 self.visit(node.test, frame)
1432 self.write(' else ')
1433 self.visit(node.expr2, frame)
1434 self.write(')')
1435
Armin Ronacher71082072008-04-12 14:19:36 +02001436 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001437 if self.environment.sandboxed:
1438 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001439 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001440 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001441 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001442 self.write(')')
1443
1444 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001445 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001446 self.visit(node.value, frame)