blob: e0f02f314769f64739f318363a033e32924f5e1d [file] [log] [blame]
Armin Ronachere791c2a2008-04-07 18:39:54 +02001# -*- coding: utf-8 -*-
2"""
3 jinja2.compiler
4 ~~~~~~~~~~~~~~~
5
6 Compiles nodes into python code.
7
8 :copyright: Copyright 2008 by Armin Ronacher.
9 :license: GNU GPL.
10"""
Armin Ronacher32a910f2008-04-26 23:21:03 +020011from time import time
Armin Ronacher8efc5222008-04-08 14:47:40 +020012from copy import copy
Armin Ronachere791c2a2008-04-07 18:39:54 +020013from random import randrange
Armin Ronacher2feed1d2008-04-26 16:26:52 +020014from keyword import iskeyword
Armin Ronachere791c2a2008-04-07 18:39:54 +020015from cStringIO import StringIO
Armin Ronacherd1ff8582008-05-11 00:30:43 +020016from itertools import chain
Armin Ronachere791c2a2008-04-07 18:39:54 +020017from jinja2 import nodes
18from jinja2.visitor import NodeVisitor, NodeTransformer
19from jinja2.exceptions import TemplateAssertionError
Armin Ronacher7ceced52008-05-03 10:15:31 +020020from jinja2.utils import Markup, concat
Armin Ronachere791c2a2008-04-07 18:39:54 +020021
22
23operators = {
24 'eq': '==',
25 'ne': '!=',
26 'gt': '>',
27 'gteq': '>=',
28 'lt': '<',
29 'lteq': '<=',
30 'in': 'in',
31 'notin': 'not in'
32}
33
Armin Ronacher3d8b7842008-04-13 13:16:50 +020034try:
35 exec '(0 if 0 else 0)'
36except SyntaxError:
37 have_condexpr = False
38else:
39 have_condexpr = True
40
41
Armin Ronacher8e8d0712008-04-16 23:10:49 +020042def generate(node, environment, name, filename, stream=None):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020043 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020044 if not isinstance(node, nodes.Template):
45 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher69e12db2008-05-12 09:00:03 +020046 node.freeze()
Armin Ronacher8e8d0712008-04-16 23:10:49 +020047 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020048 generator.visit(node)
49 if stream is None:
50 return generator.stream.getvalue()
51
52
Armin Ronacher4dfc9752008-04-09 15:03:29 +020053def has_safe_repr(value):
54 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020055 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020056 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020057 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher32a910f2008-04-26 23:21:03 +020058 xrange, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020059 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020060 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020061 for item in value:
62 if not has_safe_repr(item):
63 return False
64 return True
65 elif isinstance(value, dict):
66 for key, value in value.iteritems():
67 if not has_safe_repr(key):
68 return False
69 if not has_safe_repr(value):
70 return False
71 return True
72 return False
73
74
Armin Ronacherc9705c22008-04-27 21:28:03 +020075def find_undeclared(nodes, names):
76 """Check if the names passed are accessed undeclared. The return value
77 is a set of all the undeclared names from the sequence of names found.
78 """
79 visitor = UndeclaredNameVisitor(names)
80 try:
81 for node in nodes:
82 visitor.visit(node)
83 except VisitorExit:
84 pass
85 return visitor.undeclared
86
87
Armin Ronachere791c2a2008-04-07 18:39:54 +020088class Identifiers(object):
89 """Tracks the status of identifiers in frames."""
90
91 def __init__(self):
92 # variables that are known to be declared (probably from outer
93 # frames or because they are special for the frame)
94 self.declared = set()
95
Armin Ronacher10f3ba22008-04-18 11:30:37 +020096 # undeclared variables from outer scopes
97 self.outer_undeclared = set()
98
Armin Ronachere791c2a2008-04-07 18:39:54 +020099 # names that are accessed without being explicitly declared by
100 # this one or any of the outer scopes. Names can appear both in
101 # declared and undeclared.
102 self.undeclared = set()
103
104 # names that are declared locally
105 self.declared_locally = set()
106
107 # names that are declared by parameters
108 self.declared_parameter = set()
109
110 def add_special(self, name):
111 """Register a special name like `loop`."""
112 self.undeclared.discard(name)
113 self.declared.add(name)
114
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200115 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200116 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200117 if name in self.declared_locally or name in self.declared_parameter:
118 return True
119 if local_only:
120 return False
121 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200122
123 def find_shadowed(self):
124 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200125 return (self.declared | self.outer_undeclared) & \
126 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200127
128
129class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200130 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200131
132 def __init__(self, parent=None):
133 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200134
Armin Ronacher75cfb862008-04-11 13:47:22 +0200135 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200136 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200137
Armin Ronacher75cfb862008-04-11 13:47:22 +0200138 # the root frame is basically just the outermost frame, so no if
139 # conditions. This information is used to optimize inheritance
140 # situations.
141 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200142
143 # inside some tags we are using a buffer rather than yield statements.
144 # this for example affects {% filter %} or {% macro %}. If a frame
145 # is buffered this variable points to the name of the list used as
146 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200147 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200148
Armin Ronacherfed44b52008-04-13 19:42:53 +0200149 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200150 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200151
152 # the parent of this frame
153 self.parent = parent
154
Armin Ronachere791c2a2008-04-07 18:39:54 +0200155 if parent is not None:
156 self.identifiers.declared.update(
157 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200158 parent.identifiers.declared_locally |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200159 parent.identifiers.declared_parameter |
160 parent.identifiers.undeclared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200161 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200162 self.identifiers.outer_undeclared.update(
163 parent.identifiers.undeclared -
164 self.identifiers.declared
165 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200166 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200167
Armin Ronacher8efc5222008-04-08 14:47:40 +0200168 def copy(self):
169 """Create a copy of the current one."""
170 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200171 rv.identifiers = copy(self.identifiers)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200172 return rv
173
Armin Ronacherc9705c22008-04-27 21:28:03 +0200174 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200175 """Walk the node and check for identifiers. If the scope is hard (eg:
176 enforce on a python level) overrides from outer scopes are tracked
177 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200178 """
179 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200180 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200181 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200182
183 def inner(self):
184 """Return an inner frame."""
185 return Frame(self)
186
Armin Ronacher75cfb862008-04-11 13:47:22 +0200187 def soft(self):
188 """Return a soft frame. A soft frame may not be modified as
189 standalone thing as it shares the resources with the frame it
190 was created of, but it's not a rootlevel frame any longer.
191 """
192 rv = copy(self)
193 rv.rootlevel = False
194 return rv
195
Armin Ronachere791c2a2008-04-07 18:39:54 +0200196
Armin Ronacherc9705c22008-04-27 21:28:03 +0200197class VisitorExit(RuntimeError):
198 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
199
200
201class DependencyFinderVisitor(NodeVisitor):
202 """A visitor that collects filter and test calls."""
203
204 def __init__(self):
205 self.filters = set()
206 self.tests = set()
207
208 def visit_Filter(self, node):
209 self.generic_visit(node)
210 self.filters.add(node.name)
211
212 def visit_Test(self, node):
213 self.generic_visit(node)
214 self.tests.add(node.name)
215
216 def visit_Block(self, node):
217 """Stop visiting at blocks."""
218
219
220class UndeclaredNameVisitor(NodeVisitor):
221 """A visitor that checks if a name is accessed without being
222 declared. This is different from the frame visitor as it will
223 not stop at closure frames.
224 """
225
226 def __init__(self, names):
227 self.names = set(names)
228 self.undeclared = set()
229
230 def visit_Name(self, node):
231 if node.ctx == 'load' and node.name in self.names:
232 self.undeclared.add(node.name)
233 if self.undeclared == self.names:
234 raise VisitorExit()
235 else:
236 self.names.discard(node.name)
237
238 def visit_Block(self, node):
239 """Stop visiting a blocks."""
240
241
Armin Ronachere791c2a2008-04-07 18:39:54 +0200242class FrameIdentifierVisitor(NodeVisitor):
243 """A visitor for `Frame.inspect`."""
244
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200245 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200246 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200247 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200248
Armin Ronacherc9705c22008-04-27 21:28:03 +0200249 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200250 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200251 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200252 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200253 elif node.ctx == 'param':
254 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200255 elif node.ctx == 'load' and not \
256 self.identifiers.is_declared(node.name, self.hard_scope):
257 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200258
Armin Ronacherc9705c22008-04-27 21:28:03 +0200259 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200260 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200261
Armin Ronacherc9705c22008-04-27 21:28:03 +0200262 def visit_Import(self, node):
263 self.generic_visit(node)
264 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200265
Armin Ronacherc9705c22008-04-27 21:28:03 +0200266 def visit_FromImport(self, node):
267 self.generic_visit(node)
268 for name in node.names:
269 if isinstance(name, tuple):
270 self.identifiers.declared_locally.add(name[1])
271 else:
272 self.identifiers.declared_locally.add(name)
273
274 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200275 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200276 self.visit(node.node)
277 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200278
Armin Ronacherc9705c22008-04-27 21:28:03 +0200279 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200280 """Visiting stops at for blocks. However the block sequence
281 is visited as part of the outer scope.
282 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200283 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200284
Armin Ronacherc9705c22008-04-27 21:28:03 +0200285 def visit_CallBlock(self, node):
286 for child in node.iter_child_nodes(exclude=('body',)):
287 self.visit(child)
288
289 def visit_FilterBlock(self, node):
290 self.visit(node.filter)
291
292 def visit_Block(self, node):
293 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200294
295
Armin Ronacher75cfb862008-04-11 13:47:22 +0200296class CompilerExit(Exception):
297 """Raised if the compiler encountered a situation where it just
298 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200299 raises such an exception is not further processed.
300 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200301
302
Armin Ronachere791c2a2008-04-07 18:39:54 +0200303class CodeGenerator(NodeVisitor):
304
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200305 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200306 if stream is None:
307 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200308 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200309 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200310 self.filename = filename
311 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200312
Armin Ronacher023b5e92008-05-08 11:03:10 +0200313 # aliases for imports
314 self.import_aliases = {}
315
Armin Ronacherfed44b52008-04-13 19:42:53 +0200316 # a registry for all blocks. Because blocks are moved out
317 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200318 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200319
320 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200321 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200322
323 # some templates have a rootlevel extends. In this case we
324 # can safely assume that we're a child template and do some
325 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200326 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200327
Armin Ronacherba3757b2008-04-16 19:43:16 +0200328 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200329 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200330
Armin Ronacherb9e78752008-05-10 23:36:28 +0200331 # registry of all filters and tests (global, not block local)
332 self.tests = {}
333 self.filters = {}
334
Armin Ronacherba3757b2008-04-16 19:43:16 +0200335 # the debug information
336 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200337 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200338
Armin Ronacherfed44b52008-04-13 19:42:53 +0200339 # the number of new lines before the next write()
340 self._new_lines = 0
341
342 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200343 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200344
345 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200346 self._first_write = True
347
Armin Ronacherfed44b52008-04-13 19:42:53 +0200348 # used by the `temporary_identifier` method to get new
349 # unique, temporary identifier
350 self._last_identifier = 0
351
352 # the current indentation
353 self._indentation = 0
354
Armin Ronachere791c2a2008-04-07 18:39:54 +0200355 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200356 """Get a new unique identifier."""
357 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200358 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200359
Armin Ronachered1e0d42008-05-18 20:25:28 +0200360 def buffer(self, frame):
361 """Enable buffering for the frame from that point onwards."""
362 frame.buffer = buf = self.temporary_identifier()
363 self.writeline('%s = []' % buf)
364 return buf
365
366 def return_buffer_contents(self, frame):
367 """Return the buffer contents of the frame."""
368 if self.environment.autoescape:
369 self.writeline('return Markup(concat(%s))' % frame.buffer)
370 else:
371 self.writeline('return concat(%s)' % frame.buffer)
372
Armin Ronachere791c2a2008-04-07 18:39:54 +0200373 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200374 """Indent by one."""
375 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200376
Armin Ronacher8efc5222008-04-08 14:47:40 +0200377 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200378 """Outdent by step."""
379 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200380
Armin Ronacherc9705c22008-04-27 21:28:03 +0200381 def blockvisit(self, nodes, frame, force_generator=True):
382 """Visit a list of nodes as block in a frame. If the current frame
383 is no buffer a dummy ``if 0: yield None`` is written automatically
384 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200385 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200386 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200387 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200388 try:
389 for node in nodes:
390 self.visit(node, frame)
391 except CompilerExit:
392 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200393
394 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200395 """Write a string into the output stream."""
396 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200397 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200398 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200399 self.code_lineno += self._new_lines
400 if self._write_debug_info is not None:
401 self.debug_info.append((self._write_debug_info,
402 self.code_lineno))
403 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200404 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200405 self.stream.write(' ' * self._indentation)
406 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200407 self.stream.write(x)
408
409 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200410 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200411 self.newline(node, extra)
412 self.write(x)
413
414 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200415 """Add one or more newlines before the next write."""
416 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200417 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200418 self._write_debug_info = node.lineno
419 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200420
Armin Ronacher71082072008-04-12 14:19:36 +0200421 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200422 """Writes a function call to the stream for the current node.
423 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200424 disabled by setting have_comma to False. The extra keyword
425 arguments may not include python keywords otherwise a syntax
426 error could occour. The extra keyword arguments should be given
427 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200428 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200429 have_comma = have_comma and [True] or []
430 def touch_comma():
431 if have_comma:
432 self.write(', ')
433 else:
434 have_comma.append(True)
435
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200436 # if any of the given keyword arguments is a python keyword
437 # we have to make sure that no invalid call is created.
438 kwarg_workaround = False
439 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
440 if iskeyword(kwarg):
441 kwarg_workaround = True
442 break
443
Armin Ronacher8efc5222008-04-08 14:47:40 +0200444 for arg in node.args:
445 touch_comma()
446 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200447
448 if not kwarg_workaround:
449 for kwarg in node.kwargs:
450 touch_comma()
451 self.visit(kwarg, frame)
452 if extra_kwargs is not None:
453 for key, value in extra_kwargs.iteritems():
454 touch_comma()
455 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200456 if node.dyn_args:
457 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200458 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200459 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200460
461 if kwarg_workaround:
462 touch_comma()
463 if node.dyn_kwargs is not None:
464 self.write('**dict({')
465 else:
466 self.write('**{')
467 for kwarg in node.kwargs:
468 self.write('%r: ' % kwarg.key)
469 self.visit(kwarg.value, frame)
470 self.write(', ')
471 if extra_kwargs is not None:
472 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200473 self.write('%r: %s, ' % (key, value))
474 if node.dyn_kwargs is not None:
475 self.write('}, **')
476 self.visit(node.dyn_kwargs, frame)
477 self.write(')')
478 else:
479 self.write('}')
480
481 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200482 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200483 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200484 self.visit(node.dyn_kwargs, frame)
485
Armin Ronacherc9705c22008-04-27 21:28:03 +0200486 def pull_locals(self, frame):
487 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200488 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200489 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200490
491 def pull_dependencies(self, nodes):
492 """Pull all the dependencies."""
493 visitor = DependencyFinderVisitor()
494 for node in nodes:
495 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200496 for dependency in 'filters', 'tests':
497 mapping = getattr(self, dependency)
498 for name in getattr(visitor, dependency):
499 if name not in mapping:
500 mapping[name] = self.temporary_identifier()
501 self.writeline('%s = environment.%s[%r]' %
502 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200503
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200504 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200505 """This function returns all the shadowed variables in a dict
506 in the form name: alias and will write the required assignments
507 into the current scope. No indentation takes place.
508 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200509 aliases = {}
510 for name in frame.identifiers.find_shadowed():
511 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200512 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200513 return aliases
514
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200515 def function_scoping(self, node, frame, children=None,
516 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200517 """In Jinja a few statements require the help of anonymous
518 functions. Those are currently macros and call blocks and in
519 the future also recursive loops. As there is currently
520 technical limitation that doesn't allow reading and writing a
521 variable in a scope where the initial value is coming from an
522 outer scope, this function tries to fall back with a common
523 error message. Additionally the frame passed is modified so
524 that the argumetns are collected and callers are looked up.
525
526 This will return the modified frame.
527 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200528 # we have to iterate twice over it, make sure that works
529 if children is None:
530 children = node.iter_child_nodes()
531 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200532 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200533 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200534
535 # variables that are undeclared (accessed before declaration) and
536 # declared locally *and* part of an outside scope raise a template
537 # assertion error. Reason: we can't generate reasonable code from
538 # it without aliasing all the variables. XXX: alias them ^^
539 overriden_closure_vars = (
540 func_frame.identifiers.undeclared &
541 func_frame.identifiers.declared &
542 (func_frame.identifiers.declared_locally |
543 func_frame.identifiers.declared_parameter)
544 )
545 if overriden_closure_vars:
546 vars = ', '.join(sorted(overriden_closure_vars))
547 raise TemplateAssertionError('It\'s not possible to set and '
548 'access variables derived from '
549 'an outer scope! (affects: %s' %
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200550 vars, node.lineno, self.name,
551 self.filename)
Armin Ronacher71082072008-04-12 14:19:36 +0200552
553 # remove variables from a closure from the frame's undeclared
554 # identifiers.
555 func_frame.identifiers.undeclared -= (
556 func_frame.identifiers.undeclared &
557 func_frame.identifiers.declared
558 )
559
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200560 # no special variables for this scope, abort early
561 if not find_special:
562 return func_frame
563
Armin Ronacher963f97d2008-04-25 11:44:59 +0200564 func_frame.accesses_kwargs = False
565 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200566 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200567 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200568
Armin Ronacherc9705c22008-04-27 21:28:03 +0200569 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
570
571 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200572 func_frame.accesses_caller = True
573 func_frame.identifiers.add_special('caller')
574 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200575 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200576 func_frame.accesses_kwargs = True
577 func_frame.identifiers.add_special('kwargs')
578 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200579 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200580 func_frame.accesses_varargs = True
581 func_frame.identifiers.add_special('varargs')
582 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200583 return func_frame
584
Armin Ronachere791c2a2008-04-07 18:39:54 +0200585 # -- Visitors
586
587 def visit_Template(self, node, frame=None):
588 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200589 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200590 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200591 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8edbe492008-04-10 20:43:43 +0200592
Armin Ronacher75cfb862008-04-11 13:47:22 +0200593 # do we have an extends tag at all? If not, we can save some
594 # overhead by just not processing any inheritance code.
595 have_extends = node.find(nodes.Extends) is not None
596
Armin Ronacher8edbe492008-04-10 20:43:43 +0200597 # find all blocks
598 for block in node.find_all(nodes.Block):
599 if block.name in self.blocks:
600 raise TemplateAssertionError('block %r defined twice' %
601 block.name, block.lineno,
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200602 self.name, self.filename)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200603 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200604
Armin Ronacher023b5e92008-05-08 11:03:10 +0200605 # find all imports and import them
606 for import_ in node.find_all(nodes.ImportedName):
607 if import_.importname not in self.import_aliases:
608 imp = import_.importname
609 self.import_aliases[imp] = alias = self.temporary_identifier()
610 if '.' in imp:
611 module, obj = imp.rsplit('.', 1)
612 self.writeline('from %s import %s as %s' %
613 (module, obj, alias))
614 else:
615 self.writeline('import %s as %s' % (imp, alias))
616
617 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200618 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200619
Armin Ronacher8efc5222008-04-08 14:47:40 +0200620 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200621 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200622
623 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200624 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200625 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200626 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200627 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200628 if have_extends:
629 self.writeline('parent_template = None')
630 self.pull_locals(frame)
631 self.pull_dependencies(node.body)
632 if 'self' in find_undeclared(node.body, ('self',)):
633 frame.identifiers.add_special('self')
634 self.writeline('l_self = TemplateReference(context)')
635 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200636 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200637
Armin Ronacher8efc5222008-04-08 14:47:40 +0200638 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200639 if have_extends:
640 if not self.has_known_extends:
641 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200642 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200643 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200644 self.writeline('for event in parent_template.'
Armin Ronacher771c7502008-05-18 23:14:14 +0200645 '_root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200646 self.indent()
647 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200648 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200649
650 # at this point we now have the blocks collected and can visit them too.
651 for name, block in self.blocks.iteritems():
652 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200653 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200654 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200655 self.writeline('def block_%s(context, environment=environment):'
656 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200657 self.indent()
658 undeclared = find_undeclared(block.body, ('self', 'super'))
659 if 'self' in undeclared:
660 block_frame.identifiers.add_special('self')
661 self.writeline('l_self = TemplateReference(context)')
662 if 'super' in undeclared:
663 block_frame.identifiers.add_special('super')
664 self.writeline('l_super = context.super(%r, '
665 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200666 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200667 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200668 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200669 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200670
Armin Ronacher75cfb862008-04-11 13:47:22 +0200671 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200672 for x in self.blocks),
673 extra=1)
674
675 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200676 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
677 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200678
Armin Ronachere791c2a2008-04-07 18:39:54 +0200679 def visit_Block(self, node, frame):
680 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200681 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200682 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200683 # if we know that we are a child template, there is no need to
684 # check if we are one
685 if self.has_known_extends:
686 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200687 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200688 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200689 self.indent()
690 level += 1
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200691 self.writeline('for event in context.blocks[%r][0](context):' %
Armin Ronacherc9705c22008-04-27 21:28:03 +0200692 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200693 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200694 if frame.buffer is None:
695 self.writeline('yield event')
696 else:
697 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200698 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200699
700 def visit_Extends(self, node, frame):
701 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200702 if not frame.toplevel:
703 raise TemplateAssertionError('cannot use extend from a non '
704 'top-level scope', node.lineno,
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200705 self.name, self.filename)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200706
Armin Ronacher7fb38972008-04-11 13:54:28 +0200707 # if the number of extends statements in general is zero so
708 # far, we don't have to add a check if something extended
709 # the template before this one.
710 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200711
Armin Ronacher7fb38972008-04-11 13:54:28 +0200712 # if we have a known extends we just add a template runtime
713 # error into the generated code. We could catch that at compile
714 # time too, but i welcome it not to confuse users by throwing the
715 # same error at different times just "because we can".
716 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200717 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200718 self.indent()
719 self.writeline('raise TemplateRuntimeError(%r)' %
720 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200721
Armin Ronacher7fb38972008-04-11 13:54:28 +0200722 # if we have a known extends already we don't need that code here
723 # as we know that the template execution will end here.
724 if self.has_known_extends:
725 raise CompilerExit()
726 self.outdent()
727
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200728 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200729 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200730 self.write(', %r)' % self.name)
731 self.writeline('for name, parent_block in parent_template.'
732 'blocks.iteritems():')
733 self.indent()
734 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200735 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200736 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200737
738 # if this extends statement was in the root level we can take
739 # advantage of that information and simplify the generated code
740 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200741 if frame.rootlevel:
742 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200743
Armin Ronacher7fb38972008-04-11 13:54:28 +0200744 # and now we have one more
745 self.extends_so_far += 1
746
Armin Ronacherf059ec12008-04-11 22:21:00 +0200747 def visit_Include(self, node, frame):
748 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200749 if node.with_context:
750 self.writeline('template = environment.get_template(', node)
751 self.visit(node.template, frame)
752 self.write(', %r)' % self.name)
Armin Ronacher771c7502008-05-18 23:14:14 +0200753 self.writeline('for event in template._root_render_func('
Armin Ronacherea847c52008-05-02 20:04:32 +0200754 'template.new_context(context.parent, True)):')
755 else:
756 self.writeline('for event in environment.get_template(', node)
757 self.visit(node.template, frame)
Armin Ronacher771c7502008-05-18 23:14:14 +0200758 self.write(', %r).module._body_stream:' %
Armin Ronacherea847c52008-05-02 20:04:32 +0200759 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200760 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200761 if frame.buffer is None:
762 self.writeline('yield event')
763 else:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200764 self.writeline('%s(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200765 self.outdent()
766
Armin Ronacher0611e492008-04-25 23:44:14 +0200767 def visit_Import(self, node, frame):
768 """Visit regular imports."""
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200769 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200770 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200771 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200772 self.write('environment.get_template(')
773 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200774 self.write(', %r).' % self.name)
775 if node.with_context:
776 self.write('make_module(context.parent, True)')
777 else:
778 self.write('module')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200779 if frame.toplevel and not node.target.startswith('__'):
Armin Ronacher53042292008-04-26 18:30:19 +0200780 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200781
782 def visit_FromImport(self, node, frame):
783 """Visit named imports."""
784 self.newline(node)
785 self.write('included_template = environment.get_template(')
786 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200787 self.write(', %r).' % self.name)
788 if node.with_context:
789 self.write('make_module(context.parent, True)')
790 else:
791 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200792
793 var_names = []
794 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200795 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200796 if isinstance(name, tuple):
797 name, alias = name
798 else:
799 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200800 self.writeline('l_%s = getattr(included_template, '
801 '%r, missing)' % (alias, name))
802 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200803 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200804 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +0200805 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200806 'name=%r)' %
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200807 (alias, 'the template %r does not export '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200808 'the requested name ' + repr(name), name))
Armin Ronacher0611e492008-04-25 23:44:14 +0200809 self.outdent()
810 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +0200811 var_names.append(alias)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200812 if not alias.startswith('__'):
Armin Ronachera78d2762008-05-15 23:18:07 +0200813 discarded_names.append(alias)
814
815 if var_names:
816 if len(var_names) == 1:
817 name = var_names[0]
818 self.writeline('context.vars[%r] = l_%s' % (name, name))
819 else:
820 self.writeline('context.vars.update({%s})' % ', '.join(
821 '%r: l_%s' % (name, name) for name in var_names
822 ))
823 if discarded_names:
824 if len(discarded_names) == 1:
825 self.writeline('context.exported_vars.discard(%r)' %
826 discarded_names[0])
827 else:
828 self.writeline('context.exported_vars.difference_'
829 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200830
Armin Ronachere791c2a2008-04-07 18:39:54 +0200831 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200832 # when calculating the nodes for the inner frame we have to exclude
833 # the iterator contents from it
834 children = node.iter_child_nodes(exclude=('iter',))
835
836 if node.recursive:
837 loop_frame = self.function_scoping(node, frame, children,
838 find_special=False)
839 else:
840 loop_frame = frame.inner()
841 loop_frame.inspect(children)
842
843 extended_loop = node.recursive or node.else_ or \
Armin Ronachere791c2a2008-04-07 18:39:54 +0200844 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200845 if extended_loop:
846 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200847
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200848 # if we don't have an recursive loop we have to find the shadowed
849 # variables at that point
850 if not node.recursive:
851 aliases = self.collect_shadowed(loop_frame)
852
853 # otherwise we set up a buffer and add a function def
854 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200855 self.writeline('def loop(reciter, loop_render_func):', node)
856 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +0200857 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200858 aliases = {}
859
Armin Ronacherc9705c22008-04-27 21:28:03 +0200860 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200861 if node.else_:
862 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200863
864 self.newline(node)
865 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200866 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200867 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200868
869 # the expression pointing to the parent loop. We make the
870 # undefined a bit more debug friendly at the same time.
871 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200872 or "environment.undefined(%r, name='loop')" % "'loop' " \
873 'is undefined. "the filter section of a loop as well ' \
874 'as the else block doesn\'t have access to the ' \
875 "special 'loop' variable of the current loop. " \
876 "Because there is no parent loop it's undefined."
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200877
878 # if we have an extened loop and a node test, we filter in the
879 # "outer frame".
880 if extended_loop and node.test is not None:
881 self.write('(')
882 self.visit(node.target, loop_frame)
883 self.write(' for ')
884 self.visit(node.target, loop_frame)
885 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200886 if node.recursive:
887 self.write('reciter')
888 else:
889 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200890 self.write(' if (')
891 test_frame = loop_frame.copy()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200892 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200893 self.visit(node.test, test_frame)
894 self.write('))')
895
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200896 elif node.recursive:
897 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200898 else:
899 self.visit(node.iter, loop_frame)
900
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200901 if node.recursive:
902 self.write(', recurse=loop_render_func):')
903 else:
904 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200905
906 # tests in not extended loops become a continue
907 if not extended_loop and node.test is not None:
908 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200909 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200910 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200911 self.write(':')
912 self.indent()
913 self.writeline('continue')
914 self.outdent(2)
915
Armin Ronacherc9705c22008-04-27 21:28:03 +0200916 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200917 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200918 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200919
920 if node.else_:
921 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200922 self.indent()
923 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher625215e2008-04-13 16:31:08 +0200924 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200925 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200926
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200927 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200928 for name, alias in aliases.iteritems():
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200929 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200930
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200931 # if the node was recursive we have to return the buffer contents
932 # and start the iteration code
933 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200934 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200935 self.outdent()
936 if frame.buffer is None:
937 self.writeline('yield loop(', node)
938 else:
939 self.writeline('%s.append(loop(' % frame.buffer, node)
940 self.visit(node.iter, frame)
941 self.write(', loop)')
942 if frame.buffer is not None:
943 self.write(')')
944
Armin Ronachere791c2a2008-04-07 18:39:54 +0200945 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200946 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200947 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200948 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200949 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200950 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200951 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200952 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200953 if node.else_:
954 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200955 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200956 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200957 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200958
Armin Ronacher8efc5222008-04-08 14:47:40 +0200959 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200960 macro_frame = self.function_scoping(node, frame)
961 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200962 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200963 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +0200964 self.buffer(macro_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200965 self.pull_locals(macro_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200966 self.blockvisit(node.body, macro_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200967 self.return_buffer_contents(macro_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200968 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200969 self.newline()
970 if frame.toplevel:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200971 if not node.name.startswith('__'):
972 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +0200973 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200974 arg_tuple = ', '.join(repr(x.name) for x in node.args)
975 if len(node.args) == 1:
976 arg_tuple += ','
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200977 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
978 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200979 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200980 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200981 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200982 self.write('), %s, %s, %s)' % (
983 macro_frame.accesses_kwargs and '1' or '0',
984 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200985 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200986 ))
987
988 def visit_CallBlock(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200989 call_frame = self.function_scoping(node, frame, node.iter_child_nodes
990 (exclude=('call',)))
Armin Ronacher71082072008-04-12 14:19:36 +0200991 args = call_frame.arguments
992 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200993 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200994 self.pull_locals(call_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200995 self.buffer(call_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200996 self.blockvisit(node.body, call_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200997 self.return_buffer_contents(call_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200998 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200999 arg_tuple = ', '.join(repr(x.name) for x in node.args)
1000 if len(node.args) == 1:
1001 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +02001002 self.writeline('caller = Macro(environment, call, None, (%s), (' %
1003 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +02001004 for arg in node.defaults:
Armin Ronacherc9705c22008-04-27 21:28:03 +02001005 self.visit(arg, call_frame)
Armin Ronacher71082072008-04-12 14:19:36 +02001006 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +02001007 self.write('), %s, %s, 0)' % (
1008 call_frame.accesses_kwargs and '1' or '0',
1009 call_frame.accesses_varargs and '1' or '0'
1010 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001011 if frame.buffer is None:
1012 self.writeline('yield ', node)
1013 else:
1014 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +02001015 self.visit_Call(node.call, call_frame,
1016 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001017 if frame.buffer is not None:
1018 self.write(')')
1019
1020 def visit_FilterBlock(self, node, frame):
1021 filter_frame = frame.inner()
1022 filter_frame.inspect(node.iter_child_nodes())
1023
1024 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001025 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001026 self.buffer(filter_frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001027
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001028 for child in node.body:
1029 self.visit(child, filter_frame)
1030
1031 if frame.buffer is None:
1032 self.writeline('yield ', node)
1033 else:
1034 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001035 self.visit_Filter(node.filter, filter_frame, 'concat(%s)'
1036 % filter_frame.buffer)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001037 if frame.buffer is not None:
1038 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001039
Armin Ronachere791c2a2008-04-07 18:39:54 +02001040 def visit_ExprStmt(self, node, frame):
1041 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001042 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001043
1044 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001045 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +02001046 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001047 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001048
Armin Ronacher75cfb862008-04-11 13:47:22 +02001049 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001050
Armin Ronacher7fb38972008-04-11 13:54:28 +02001051 # if we are in the toplevel scope and there was already an extends
1052 # statement we have to add a check that disables our yield(s) here
1053 # so that they don't appear in the output.
1054 outdent_later = False
1055 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001056 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001057 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001058 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001059
Armin Ronachere791c2a2008-04-07 18:39:54 +02001060 # try to evaluate as many chunks as possible into a static
1061 # string at compile time.
1062 body = []
1063 for child in node.nodes:
1064 try:
1065 const = unicode(child.as_const())
1066 except:
1067 body.append(child)
1068 continue
1069 if body and isinstance(body[-1], list):
1070 body[-1].append(const)
1071 else:
1072 body.append([const])
1073
Armin Ronachered1e0d42008-05-18 20:25:28 +02001074 # if we have less than 3 nodes or a buffer we yield or extend/append
1075 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001076 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001077 # for one item we append, for more we extend
1078 if len(body) == 1:
1079 self.writeline('%s.append(' % frame.buffer)
1080 else:
1081 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001082 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001083 for item in body:
1084 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001085 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001086 if frame.buffer is None:
1087 self.writeline('yield ' + val)
1088 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001089 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001090 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001091 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001092 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001093 else:
1094 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001095 close = 1
1096 if self.environment.autoescape:
1097 self.write('escape(')
1098 else:
1099 self.write('unicode(')
1100 if self.environment.finalize is not None:
1101 self.write('environment.finalize(')
1102 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001103 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001104 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001105 if frame.buffer is not None:
1106 self.write(', ')
1107 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001108 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001109 self.outdent()
1110 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001111
1112 # otherwise we create a format string as this is faster in that case
1113 else:
1114 format = []
1115 arguments = []
1116 for item in body:
1117 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001118 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001119 else:
1120 format.append('%s')
1121 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001122 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001123 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001124 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001125 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001126 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001127 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001128 close = 0
1129 if self.environment.autoescape:
1130 self.write('escape(')
1131 close += 1
1132 if self.environment.finalize is not None:
1133 self.write('environment.finalize(')
1134 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001135 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001136 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001137 self.outdent()
1138 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001139
Armin Ronacher7fb38972008-04-11 13:54:28 +02001140 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001141 self.outdent()
1142
Armin Ronacher8efc5222008-04-08 14:47:40 +02001143 def visit_Assign(self, node, frame):
1144 self.newline(node)
1145 # toplevel assignments however go into the local namespace and
1146 # the current template's context. We create a copy of the frame
1147 # here and add a set so that the Name visitor can add the assigned
1148 # names here.
1149 if frame.toplevel:
1150 assignment_frame = frame.copy()
1151 assignment_frame.assigned_names = set()
1152 else:
1153 assignment_frame = frame
1154 self.visit(node.target, assignment_frame)
1155 self.write(' = ')
1156 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001157
1158 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001159 if frame.toplevel:
Armin Ronacher69e12db2008-05-12 09:00:03 +02001160 public_names = [x for x in assignment_frame.assigned_names
1161 if not x.startswith('__')]
1162 if len(assignment_frame.assigned_names) == 1:
1163 name = iter(assignment_frame.assigned_names).next()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001164 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001165 else:
1166 self.writeline('context.vars.update({')
1167 for idx, name in enumerate(assignment_frame.assigned_names):
1168 if idx:
1169 self.write(', ')
1170 self.write('%r: l_%s' % (name, name))
1171 self.write('})')
1172 if public_names:
1173 if len(public_names) == 1:
1174 self.writeline('context.exported_vars.add(%r)' %
1175 public_names[0])
1176 else:
1177 self.writeline('context.exported_vars.update((%s))' %
1178 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001179
Armin Ronachere791c2a2008-04-07 18:39:54 +02001180 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001181 if node.ctx == 'store' and frame.toplevel:
1182 frame.assigned_names.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001183 self.write('l_' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001184
1185 def visit_Const(self, node, frame):
1186 val = node.value
1187 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001188 self.write(str(val))
1189 else:
1190 self.write(repr(val))
1191
Armin Ronacher8efc5222008-04-08 14:47:40 +02001192 def visit_Tuple(self, node, frame):
1193 self.write('(')
1194 idx = -1
1195 for idx, item in enumerate(node.items):
1196 if idx:
1197 self.write(', ')
1198 self.visit(item, frame)
1199 self.write(idx == 0 and ',)' or ')')
1200
Armin Ronacher8edbe492008-04-10 20:43:43 +02001201 def visit_List(self, node, frame):
1202 self.write('[')
1203 for idx, item in enumerate(node.items):
1204 if idx:
1205 self.write(', ')
1206 self.visit(item, frame)
1207 self.write(']')
1208
1209 def visit_Dict(self, node, frame):
1210 self.write('{')
1211 for idx, item in enumerate(node.items):
1212 if idx:
1213 self.write(', ')
1214 self.visit(item.key, frame)
1215 self.write(': ')
1216 self.visit(item.value, frame)
1217 self.write('}')
1218
Armin Ronachere791c2a2008-04-07 18:39:54 +02001219 def binop(operator):
1220 def visitor(self, node, frame):
1221 self.write('(')
1222 self.visit(node.left, frame)
1223 self.write(' %s ' % operator)
1224 self.visit(node.right, frame)
1225 self.write(')')
1226 return visitor
1227
1228 def uaop(operator):
1229 def visitor(self, node, frame):
1230 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001231 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001232 self.write(')')
1233 return visitor
1234
1235 visit_Add = binop('+')
1236 visit_Sub = binop('-')
1237 visit_Mul = binop('*')
1238 visit_Div = binop('/')
1239 visit_FloorDiv = binop('//')
1240 visit_Pow = binop('**')
1241 visit_Mod = binop('%')
1242 visit_And = binop('and')
1243 visit_Or = binop('or')
1244 visit_Pos = uaop('+')
1245 visit_Neg = uaop('-')
1246 visit_Not = uaop('not ')
1247 del binop, uaop
1248
Armin Ronacherd1342312008-04-28 12:20:12 +02001249 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001250 self.write('%s((' % (self.environment.autoescape and
1251 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001252 for arg in node.nodes:
1253 self.visit(arg, frame)
1254 self.write(', ')
1255 self.write('))')
1256
Armin Ronachere791c2a2008-04-07 18:39:54 +02001257 def visit_Compare(self, node, frame):
1258 self.visit(node.expr, frame)
1259 for op in node.ops:
1260 self.visit(op, frame)
1261
1262 def visit_Operand(self, node, frame):
1263 self.write(' %s ' % operators[node.op])
1264 self.visit(node.expr, frame)
1265
1266 def visit_Subscript(self, node, frame):
Armin Ronacher08a6a3b2008-05-13 15:35:47 +02001267 # slices or integer subscriptions bypass the subscribe
1268 # method if we can determine that at compile time.
1269 if isinstance(node.arg, nodes.Slice) or \
1270 (isinstance(node.arg, nodes.Const) and
1271 isinstance(node.arg.value, (int, long))):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001272 self.visit(node.node, frame)
1273 self.write('[')
1274 self.visit(node.arg, frame)
1275 self.write(']')
1276 return
Armin Ronacherc63243e2008-04-14 22:53:58 +02001277 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001278 self.visit(node.node, frame)
1279 self.write(', ')
Armin Ronacherab5ad8c2008-05-17 00:34:11 +02001280 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001281 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001282
1283 def visit_Slice(self, node, frame):
1284 if node.start is not None:
1285 self.visit(node.start, frame)
1286 self.write(':')
1287 if node.stop is not None:
1288 self.visit(node.stop, frame)
1289 if node.step is not None:
1290 self.write(':')
1291 self.visit(node.step, frame)
1292
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001293 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001294 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001295 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001296 if func is None:
1297 raise TemplateAssertionError('no filter named %r' % node.name,
Armin Ronacher7f15ef82008-05-16 09:11:39 +02001298 node.lineno, self.name,
1299 self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001300 if getattr(func, 'contextfilter', False):
1301 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001302 elif getattr(func, 'environmentfilter', False):
1303 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001304 if isinstance(node.node, nodes.Filter):
1305 self.visit_Filter(node.node, frame, initial)
1306 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001307 self.write(initial)
1308 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001309 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001310 self.signature(node, frame)
1311 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001312
1313 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001314 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001315 if node.name not in self.environment.tests:
1316 raise TemplateAssertionError('no test named %r' % node.name,
Armin Ronacher7f15ef82008-05-16 09:11:39 +02001317 node.lineno, self.name,
1318 self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001319 self.visit(node.node, frame)
1320 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001321 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001322
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001323 def visit_CondExpr(self, node, frame):
1324 if not have_condexpr:
1325 self.write('((')
1326 self.visit(node.test, frame)
1327 self.write(') and (')
1328 self.visit(node.expr1, frame)
1329 self.write(',) or (')
1330 self.visit(node.expr2, frame)
1331 self.write(',))[0]')
1332 else:
1333 self.write('(')
1334 self.visit(node.expr1, frame)
1335 self.write(' if ')
1336 self.visit(node.test, frame)
1337 self.write(' else ')
1338 self.visit(node.expr2, frame)
1339 self.write(')')
1340
Armin Ronacher71082072008-04-12 14:19:36 +02001341 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001342 if self.environment.sandboxed:
1343 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001344 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001345 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001346 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001347 self.write(')')
1348
1349 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001350 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001351 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001352
1353 # Unused nodes for extensions
1354
1355 def visit_MarkSafe(self, node, frame):
1356 self.write('Markup(')
1357 self.visit(node.expr, frame)
1358 self.write(')')
1359
1360 def visit_EnvironmentAttribute(self, node, frame):
1361 self.write('environment.' + node.name)
1362
1363 def visit_ExtensionAttribute(self, node, frame):
1364 self.write('environment.extensions[%r].%s' % (node.identifier, node.attr))
1365
1366 def visit_ImportedName(self, node, frame):
1367 self.write(self.import_aliases[node.importname])
1368
1369 def visit_InternalName(self, node, frame):
1370 self.write(node.name)
1371
1372 def visit_Continue(self, node, frame):
1373 self.writeline('continue', node)
1374
1375 def visit_Break(self, node, frame):
1376 self.writeline('break', node)