blob: d643d39f1532638f956c4be1688ce362b9c8b6dc [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 Ronachere2244882008-05-19 09:25:57 +0200355 def fail(self, msg, lineno):
356 """Fail with a `TemplateAssertionError`."""
357 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
358
Armin Ronachere791c2a2008-04-07 18:39:54 +0200359 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200360 """Get a new unique identifier."""
361 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200362 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200363
Armin Ronachered1e0d42008-05-18 20:25:28 +0200364 def buffer(self, frame):
365 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200366 frame.buffer = self.temporary_identifier()
367 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200368
369 def return_buffer_contents(self, frame):
370 """Return the buffer contents of the frame."""
371 if self.environment.autoescape:
372 self.writeline('return Markup(concat(%s))' % frame.buffer)
373 else:
374 self.writeline('return concat(%s)' % frame.buffer)
375
Armin Ronachere791c2a2008-04-07 18:39:54 +0200376 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200377 """Indent by one."""
378 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200379
Armin Ronacher8efc5222008-04-08 14:47:40 +0200380 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200381 """Outdent by step."""
382 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200383
Armin Ronacherc9705c22008-04-27 21:28:03 +0200384 def blockvisit(self, nodes, frame, force_generator=True):
385 """Visit a list of nodes as block in a frame. If the current frame
386 is no buffer a dummy ``if 0: yield None`` is written automatically
387 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200388 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200389 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200390 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200391 try:
392 for node in nodes:
393 self.visit(node, frame)
394 except CompilerExit:
395 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200396
397 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200398 """Write a string into the output stream."""
399 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200400 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200401 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200402 self.code_lineno += self._new_lines
403 if self._write_debug_info is not None:
404 self.debug_info.append((self._write_debug_info,
405 self.code_lineno))
406 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200407 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200408 self.stream.write(' ' * self._indentation)
409 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200410 self.stream.write(x)
411
412 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200413 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200414 self.newline(node, extra)
415 self.write(x)
416
417 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200418 """Add one or more newlines before the next write."""
419 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200420 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200421 self._write_debug_info = node.lineno
422 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200423
Armin Ronacher71082072008-04-12 14:19:36 +0200424 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200425 """Writes a function call to the stream for the current node.
426 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200427 disabled by setting have_comma to False. The extra keyword
428 arguments may not include python keywords otherwise a syntax
429 error could occour. The extra keyword arguments should be given
430 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200431 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200432 have_comma = have_comma and [True] or []
433 def touch_comma():
434 if have_comma:
435 self.write(', ')
436 else:
437 have_comma.append(True)
438
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200439 # if any of the given keyword arguments is a python keyword
440 # we have to make sure that no invalid call is created.
441 kwarg_workaround = False
442 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
443 if iskeyword(kwarg):
444 kwarg_workaround = True
445 break
446
Armin Ronacher8efc5222008-04-08 14:47:40 +0200447 for arg in node.args:
448 touch_comma()
449 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200450
451 if not kwarg_workaround:
452 for kwarg in node.kwargs:
453 touch_comma()
454 self.visit(kwarg, frame)
455 if extra_kwargs is not None:
456 for key, value in extra_kwargs.iteritems():
457 touch_comma()
458 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200459 if node.dyn_args:
460 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200461 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200462 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200463
464 if kwarg_workaround:
465 touch_comma()
466 if node.dyn_kwargs is not None:
467 self.write('**dict({')
468 else:
469 self.write('**{')
470 for kwarg in node.kwargs:
471 self.write('%r: ' % kwarg.key)
472 self.visit(kwarg.value, frame)
473 self.write(', ')
474 if extra_kwargs is not None:
475 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200476 self.write('%r: %s, ' % (key, value))
477 if node.dyn_kwargs is not None:
478 self.write('}, **')
479 self.visit(node.dyn_kwargs, frame)
480 self.write(')')
481 else:
482 self.write('}')
483
484 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200485 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200486 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200487 self.visit(node.dyn_kwargs, frame)
488
Armin Ronacherc9705c22008-04-27 21:28:03 +0200489 def pull_locals(self, frame):
490 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200491 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200492 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200493
494 def pull_dependencies(self, nodes):
495 """Pull all the dependencies."""
496 visitor = DependencyFinderVisitor()
497 for node in nodes:
498 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200499 for dependency in 'filters', 'tests':
500 mapping = getattr(self, dependency)
501 for name in getattr(visitor, dependency):
502 if name not in mapping:
503 mapping[name] = self.temporary_identifier()
504 self.writeline('%s = environment.%s[%r]' %
505 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200506
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200507 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200508 """This function returns all the shadowed variables in a dict
509 in the form name: alias and will write the required assignments
510 into the current scope. No indentation takes place.
511 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200512 aliases = {}
513 for name in frame.identifiers.find_shadowed():
514 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200515 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200516 return aliases
517
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200518 def function_scoping(self, node, frame, children=None,
519 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200520 """In Jinja a few statements require the help of anonymous
521 functions. Those are currently macros and call blocks and in
522 the future also recursive loops. As there is currently
523 technical limitation that doesn't allow reading and writing a
524 variable in a scope where the initial value is coming from an
525 outer scope, this function tries to fall back with a common
526 error message. Additionally the frame passed is modified so
527 that the argumetns are collected and callers are looked up.
528
529 This will return the modified frame.
530 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200531 # we have to iterate twice over it, make sure that works
532 if children is None:
533 children = node.iter_child_nodes()
534 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200535 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200536 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200537
538 # variables that are undeclared (accessed before declaration) and
539 # declared locally *and* part of an outside scope raise a template
540 # assertion error. Reason: we can't generate reasonable code from
541 # it without aliasing all the variables. XXX: alias them ^^
542 overriden_closure_vars = (
543 func_frame.identifiers.undeclared &
544 func_frame.identifiers.declared &
545 (func_frame.identifiers.declared_locally |
546 func_frame.identifiers.declared_parameter)
547 )
548 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200549 self.fail('It\'s not possible to set and access variables '
550 'derived from an outer scope! (affects: %s' %
551 ', '.join(sorted(overriden_closure_vars)), node.lineno)
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:
Armin Ronachere2244882008-05-19 09:25:57 +0200600 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200601 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200602
Armin Ronacher023b5e92008-05-08 11:03:10 +0200603 # find all imports and import them
604 for import_ in node.find_all(nodes.ImportedName):
605 if import_.importname not in self.import_aliases:
606 imp = import_.importname
607 self.import_aliases[imp] = alias = self.temporary_identifier()
608 if '.' in imp:
609 module, obj = imp.rsplit('.', 1)
610 self.writeline('from %s import %s as %s' %
611 (module, obj, alias))
612 else:
613 self.writeline('import %s as %s' % (imp, alias))
614
615 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200616 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200617
Armin Ronacher8efc5222008-04-08 14:47:40 +0200618 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200619 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200620
621 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200622 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200623 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200624 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200625 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200626 if have_extends:
627 self.writeline('parent_template = None')
628 self.pull_locals(frame)
629 self.pull_dependencies(node.body)
630 if 'self' in find_undeclared(node.body, ('self',)):
631 frame.identifiers.add_special('self')
632 self.writeline('l_self = TemplateReference(context)')
633 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200634 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200635
Armin Ronacher8efc5222008-04-08 14:47:40 +0200636 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200637 if have_extends:
638 if not self.has_known_extends:
639 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200640 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200641 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200642 self.writeline('for event in parent_template.'
Armin Ronacher771c7502008-05-18 23:14:14 +0200643 '_root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200644 self.indent()
645 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200646 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200647
648 # at this point we now have the blocks collected and can visit them too.
649 for name, block in self.blocks.iteritems():
650 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200651 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200652 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200653 self.writeline('def block_%s(context, environment=environment):'
654 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200655 self.indent()
656 undeclared = find_undeclared(block.body, ('self', 'super'))
657 if 'self' in undeclared:
658 block_frame.identifiers.add_special('self')
659 self.writeline('l_self = TemplateReference(context)')
660 if 'super' in undeclared:
661 block_frame.identifiers.add_special('super')
662 self.writeline('l_super = context.super(%r, '
663 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200664 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200665 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200666 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200667 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200668
Armin Ronacher75cfb862008-04-11 13:47:22 +0200669 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200670 for x in self.blocks),
671 extra=1)
672
673 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200674 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
675 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200676
Armin Ronachere791c2a2008-04-07 18:39:54 +0200677 def visit_Block(self, node, frame):
678 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200679 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200680 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200681 # if we know that we are a child template, there is no need to
682 # check if we are one
683 if self.has_known_extends:
684 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200685 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200686 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200687 self.indent()
688 level += 1
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200689 self.writeline('for event in context.blocks[%r][0](context):' %
Armin Ronacherc9705c22008-04-27 21:28:03 +0200690 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200691 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200692 if frame.buffer is None:
693 self.writeline('yield event')
694 else:
695 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200696 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200697
698 def visit_Extends(self, node, frame):
699 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200700 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200701 self.fail('cannot use extend from a non top-level scope',
702 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200703
Armin Ronacher7fb38972008-04-11 13:54:28 +0200704 # if the number of extends statements in general is zero so
705 # far, we don't have to add a check if something extended
706 # the template before this one.
707 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200708
Armin Ronacher7fb38972008-04-11 13:54:28 +0200709 # if we have a known extends we just add a template runtime
710 # error into the generated code. We could catch that at compile
711 # time too, but i welcome it not to confuse users by throwing the
712 # same error at different times just "because we can".
713 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200714 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200715 self.indent()
716 self.writeline('raise TemplateRuntimeError(%r)' %
717 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200718
Armin Ronacher7fb38972008-04-11 13:54:28 +0200719 # if we have a known extends already we don't need that code here
720 # as we know that the template execution will end here.
721 if self.has_known_extends:
722 raise CompilerExit()
723 self.outdent()
724
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200725 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200726 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200727 self.write(', %r)' % self.name)
728 self.writeline('for name, parent_block in parent_template.'
729 'blocks.iteritems():')
730 self.indent()
731 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200732 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200733 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200734
735 # if this extends statement was in the root level we can take
736 # advantage of that information and simplify the generated code
737 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200738 if frame.rootlevel:
739 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200740
Armin Ronacher7fb38972008-04-11 13:54:28 +0200741 # and now we have one more
742 self.extends_so_far += 1
743
Armin Ronacherf059ec12008-04-11 22:21:00 +0200744 def visit_Include(self, node, frame):
745 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200746 if node.with_context:
747 self.writeline('template = environment.get_template(', node)
748 self.visit(node.template, frame)
749 self.write(', %r)' % self.name)
Armin Ronacher771c7502008-05-18 23:14:14 +0200750 self.writeline('for event in template._root_render_func('
Armin Ronacherea847c52008-05-02 20:04:32 +0200751 'template.new_context(context.parent, True)):')
752 else:
753 self.writeline('for event in environment.get_template(', node)
754 self.visit(node.template, frame)
Armin Ronacher771c7502008-05-18 23:14:14 +0200755 self.write(', %r).module._body_stream:' %
Armin Ronacherea847c52008-05-02 20:04:32 +0200756 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200757 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200758 if frame.buffer is None:
759 self.writeline('yield event')
760 else:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200761 self.writeline('%s(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200762 self.outdent()
763
Armin Ronacher0611e492008-04-25 23:44:14 +0200764 def visit_Import(self, node, frame):
765 """Visit regular imports."""
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200766 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200767 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200768 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200769 self.write('environment.get_template(')
770 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200771 self.write(', %r).' % self.name)
772 if node.with_context:
773 self.write('make_module(context.parent, True)')
774 else:
775 self.write('module')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200776 if frame.toplevel and not node.target.startswith('__'):
Armin Ronacher53042292008-04-26 18:30:19 +0200777 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200778
779 def visit_FromImport(self, node, frame):
780 """Visit named imports."""
781 self.newline(node)
782 self.write('included_template = environment.get_template(')
783 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200784 self.write(', %r).' % self.name)
785 if node.with_context:
786 self.write('make_module(context.parent, True)')
787 else:
788 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200789
790 var_names = []
791 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200792 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200793 if isinstance(name, tuple):
794 name, alias = name
795 else:
796 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200797 self.writeline('l_%s = getattr(included_template, '
798 '%r, missing)' % (alias, name))
799 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200800 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200801 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +0200802 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200803 'name=%r)' %
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200804 (alias, 'the template %r does not export '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200805 'the requested name ' + repr(name), name))
Armin Ronacher0611e492008-04-25 23:44:14 +0200806 self.outdent()
807 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +0200808 var_names.append(alias)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200809 if not alias.startswith('__'):
Armin Ronachera78d2762008-05-15 23:18:07 +0200810 discarded_names.append(alias)
811
812 if var_names:
813 if len(var_names) == 1:
814 name = var_names[0]
815 self.writeline('context.vars[%r] = l_%s' % (name, name))
816 else:
817 self.writeline('context.vars.update({%s})' % ', '.join(
818 '%r: l_%s' % (name, name) for name in var_names
819 ))
820 if discarded_names:
821 if len(discarded_names) == 1:
822 self.writeline('context.exported_vars.discard(%r)' %
823 discarded_names[0])
824 else:
825 self.writeline('context.exported_vars.difference_'
826 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200827
Armin Ronachere791c2a2008-04-07 18:39:54 +0200828 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200829 # when calculating the nodes for the inner frame we have to exclude
830 # the iterator contents from it
Armin Ronachere2244882008-05-19 09:25:57 +0200831 children = list(node.iter_child_nodes(exclude=('iter',)))
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200832
833 if node.recursive:
834 loop_frame = self.function_scoping(node, frame, children,
835 find_special=False)
836 else:
837 loop_frame = frame.inner()
838 loop_frame.inspect(children)
839
Armin Ronachere2244882008-05-19 09:25:57 +0200840 undeclared = find_undeclared(children, ('loop',))
841 extended_loop = node.recursive or node.else_ or 'loop' in undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200842 if extended_loop:
843 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200844
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200845 # if we don't have an recursive loop we have to find the shadowed
846 # variables at that point
847 if not node.recursive:
848 aliases = self.collect_shadowed(loop_frame)
849
850 # otherwise we set up a buffer and add a function def
851 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200852 self.writeline('def loop(reciter, loop_render_func):', node)
853 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +0200854 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200855 aliases = {}
856
Armin Ronacherc9705c22008-04-27 21:28:03 +0200857 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200858 if node.else_:
859 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200860
861 self.newline(node)
862 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200863 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200864 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200865
866 # the expression pointing to the parent loop. We make the
867 # undefined a bit more debug friendly at the same time.
868 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200869 or "environment.undefined(%r, name='loop')" % "'loop' " \
870 'is undefined. "the filter section of a loop as well ' \
871 'as the else block doesn\'t have access to the ' \
872 "special 'loop' variable of the current loop. " \
873 "Because there is no parent loop it's undefined."
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200874
875 # if we have an extened loop and a node test, we filter in the
876 # "outer frame".
877 if extended_loop and node.test is not None:
878 self.write('(')
879 self.visit(node.target, loop_frame)
880 self.write(' for ')
881 self.visit(node.target, loop_frame)
882 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200883 if node.recursive:
884 self.write('reciter')
885 else:
886 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200887 self.write(' if (')
888 test_frame = loop_frame.copy()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200889 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200890 self.visit(node.test, test_frame)
891 self.write('))')
892
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200893 elif node.recursive:
894 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200895 else:
896 self.visit(node.iter, loop_frame)
897
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200898 if node.recursive:
899 self.write(', recurse=loop_render_func):')
900 else:
901 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200902
903 # tests in not extended loops become a continue
904 if not extended_loop and node.test is not None:
905 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200906 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200907 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200908 self.write(':')
909 self.indent()
910 self.writeline('continue')
911 self.outdent(2)
912
Armin Ronacherc9705c22008-04-27 21:28:03 +0200913 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200914 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200915 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200916
917 if node.else_:
918 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200919 self.indent()
920 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher625215e2008-04-13 16:31:08 +0200921 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200922 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200923
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200924 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200925 for name, alias in aliases.iteritems():
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200926 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200927
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200928 # if the node was recursive we have to return the buffer contents
929 # and start the iteration code
930 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200931 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200932 self.outdent()
933 if frame.buffer is None:
934 self.writeline('yield loop(', node)
935 else:
936 self.writeline('%s.append(loop(' % frame.buffer, node)
937 self.visit(node.iter, frame)
938 self.write(', loop)')
939 if frame.buffer is not None:
940 self.write(')')
941
Armin Ronachere791c2a2008-04-07 18:39:54 +0200942 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200943 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200944 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200945 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200946 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200947 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200948 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200949 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200950 if node.else_:
951 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200952 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200953 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200954 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200955
Armin Ronacher8efc5222008-04-08 14:47:40 +0200956 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200957 macro_frame = self.function_scoping(node, frame)
958 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200959 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200960 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +0200961 self.buffer(macro_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200962 self.pull_locals(macro_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200963 self.blockvisit(node.body, macro_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200964 self.return_buffer_contents(macro_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200965 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200966 self.newline()
967 if frame.toplevel:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200968 if not node.name.startswith('__'):
969 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +0200970 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200971 arg_tuple = ', '.join(repr(x.name) for x in node.args)
972 if len(node.args) == 1:
973 arg_tuple += ','
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200974 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
975 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200976 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200977 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200978 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200979 self.write('), %s, %s, %s)' % (
980 macro_frame.accesses_kwargs and '1' or '0',
981 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200982 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200983 ))
984
985 def visit_CallBlock(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200986 call_frame = self.function_scoping(node, frame, node.iter_child_nodes
987 (exclude=('call',)))
Armin Ronacher71082072008-04-12 14:19:36 +0200988 args = call_frame.arguments
989 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200990 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200991 self.pull_locals(call_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200992 self.buffer(call_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200993 self.blockvisit(node.body, call_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200994 self.return_buffer_contents(call_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200995 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200996 arg_tuple = ', '.join(repr(x.name) for x in node.args)
997 if len(node.args) == 1:
998 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200999 self.writeline('caller = Macro(environment, call, None, (%s), (' %
1000 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +02001001 for arg in node.defaults:
Armin Ronacherc9705c22008-04-27 21:28:03 +02001002 self.visit(arg, call_frame)
Armin Ronacher71082072008-04-12 14:19:36 +02001003 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +02001004 self.write('), %s, %s, 0)' % (
1005 call_frame.accesses_kwargs and '1' or '0',
1006 call_frame.accesses_varargs and '1' or '0'
1007 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001008 if frame.buffer is None:
1009 self.writeline('yield ', node)
1010 else:
1011 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +02001012 self.visit_Call(node.call, call_frame,
1013 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001014 if frame.buffer is not None:
1015 self.write(')')
1016
1017 def visit_FilterBlock(self, node, frame):
1018 filter_frame = frame.inner()
1019 filter_frame.inspect(node.iter_child_nodes())
1020
1021 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001022 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001023 self.buffer(filter_frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001024
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001025 for child in node.body:
1026 self.visit(child, filter_frame)
1027
1028 if frame.buffer is None:
1029 self.writeline('yield ', node)
1030 else:
1031 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001032 self.visit_Filter(node.filter, filter_frame, 'concat(%s)'
1033 % filter_frame.buffer)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001034 if frame.buffer is not None:
1035 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001036
Armin Ronachere791c2a2008-04-07 18:39:54 +02001037 def visit_ExprStmt(self, node, frame):
1038 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001039 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001040
1041 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001042 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +02001043 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001044 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001045
Armin Ronacher75cfb862008-04-11 13:47:22 +02001046 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001047
Armin Ronacher7fb38972008-04-11 13:54:28 +02001048 # if we are in the toplevel scope and there was already an extends
1049 # statement we have to add a check that disables our yield(s) here
1050 # so that they don't appear in the output.
1051 outdent_later = False
1052 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001053 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001054 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001055 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001056
Armin Ronachere791c2a2008-04-07 18:39:54 +02001057 # try to evaluate as many chunks as possible into a static
1058 # string at compile time.
1059 body = []
1060 for child in node.nodes:
1061 try:
1062 const = unicode(child.as_const())
1063 except:
1064 body.append(child)
1065 continue
1066 if body and isinstance(body[-1], list):
1067 body[-1].append(const)
1068 else:
1069 body.append([const])
1070
Armin Ronachered1e0d42008-05-18 20:25:28 +02001071 # if we have less than 3 nodes or a buffer we yield or extend/append
1072 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001073 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001074 # for one item we append, for more we extend
1075 if len(body) == 1:
1076 self.writeline('%s.append(' % frame.buffer)
1077 else:
1078 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001079 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001080 for item in body:
1081 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001082 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001083 if frame.buffer is None:
1084 self.writeline('yield ' + val)
1085 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001086 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001087 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001088 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001089 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001090 else:
1091 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001092 close = 1
1093 if self.environment.autoescape:
1094 self.write('escape(')
1095 else:
1096 self.write('unicode(')
1097 if self.environment.finalize is not None:
1098 self.write('environment.finalize(')
1099 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001100 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001101 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001102 if frame.buffer is not None:
1103 self.write(', ')
1104 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001105 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001106 self.outdent()
1107 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001108
1109 # otherwise we create a format string as this is faster in that case
1110 else:
1111 format = []
1112 arguments = []
1113 for item in body:
1114 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001115 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001116 else:
1117 format.append('%s')
1118 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001119 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001120 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001121 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001122 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001123 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001124 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001125 close = 0
1126 if self.environment.autoescape:
1127 self.write('escape(')
1128 close += 1
1129 if self.environment.finalize is not None:
1130 self.write('environment.finalize(')
1131 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001132 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001133 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001134 self.outdent()
1135 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001136
Armin Ronacher7fb38972008-04-11 13:54:28 +02001137 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001138 self.outdent()
1139
Armin Ronacher8efc5222008-04-08 14:47:40 +02001140 def visit_Assign(self, node, frame):
1141 self.newline(node)
1142 # toplevel assignments however go into the local namespace and
1143 # the current template's context. We create a copy of the frame
1144 # here and add a set so that the Name visitor can add the assigned
1145 # names here.
1146 if frame.toplevel:
1147 assignment_frame = frame.copy()
1148 assignment_frame.assigned_names = set()
1149 else:
1150 assignment_frame = frame
1151 self.visit(node.target, assignment_frame)
1152 self.write(' = ')
1153 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001154
1155 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001156 if frame.toplevel:
Armin Ronacher69e12db2008-05-12 09:00:03 +02001157 public_names = [x for x in assignment_frame.assigned_names
1158 if not x.startswith('__')]
1159 if len(assignment_frame.assigned_names) == 1:
1160 name = iter(assignment_frame.assigned_names).next()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001161 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001162 else:
1163 self.writeline('context.vars.update({')
1164 for idx, name in enumerate(assignment_frame.assigned_names):
1165 if idx:
1166 self.write(', ')
1167 self.write('%r: l_%s' % (name, name))
1168 self.write('})')
1169 if public_names:
1170 if len(public_names) == 1:
1171 self.writeline('context.exported_vars.add(%r)' %
1172 public_names[0])
1173 else:
1174 self.writeline('context.exported_vars.update((%s))' %
1175 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001176
Armin Ronachere791c2a2008-04-07 18:39:54 +02001177 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001178 if node.ctx == 'store' and frame.toplevel:
1179 frame.assigned_names.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001180 self.write('l_' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001181
1182 def visit_Const(self, node, frame):
1183 val = node.value
1184 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001185 self.write(str(val))
1186 else:
1187 self.write(repr(val))
1188
Armin Ronacher8efc5222008-04-08 14:47:40 +02001189 def visit_Tuple(self, node, frame):
1190 self.write('(')
1191 idx = -1
1192 for idx, item in enumerate(node.items):
1193 if idx:
1194 self.write(', ')
1195 self.visit(item, frame)
1196 self.write(idx == 0 and ',)' or ')')
1197
Armin Ronacher8edbe492008-04-10 20:43:43 +02001198 def visit_List(self, node, frame):
1199 self.write('[')
1200 for idx, item in enumerate(node.items):
1201 if idx:
1202 self.write(', ')
1203 self.visit(item, frame)
1204 self.write(']')
1205
1206 def visit_Dict(self, node, frame):
1207 self.write('{')
1208 for idx, item in enumerate(node.items):
1209 if idx:
1210 self.write(', ')
1211 self.visit(item.key, frame)
1212 self.write(': ')
1213 self.visit(item.value, frame)
1214 self.write('}')
1215
Armin Ronachere791c2a2008-04-07 18:39:54 +02001216 def binop(operator):
1217 def visitor(self, node, frame):
1218 self.write('(')
1219 self.visit(node.left, frame)
1220 self.write(' %s ' % operator)
1221 self.visit(node.right, frame)
1222 self.write(')')
1223 return visitor
1224
1225 def uaop(operator):
1226 def visitor(self, node, frame):
1227 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001228 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001229 self.write(')')
1230 return visitor
1231
1232 visit_Add = binop('+')
1233 visit_Sub = binop('-')
1234 visit_Mul = binop('*')
1235 visit_Div = binop('/')
1236 visit_FloorDiv = binop('//')
1237 visit_Pow = binop('**')
1238 visit_Mod = binop('%')
1239 visit_And = binop('and')
1240 visit_Or = binop('or')
1241 visit_Pos = uaop('+')
1242 visit_Neg = uaop('-')
1243 visit_Not = uaop('not ')
1244 del binop, uaop
1245
Armin Ronacherd1342312008-04-28 12:20:12 +02001246 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001247 self.write('%s((' % (self.environment.autoescape and
1248 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001249 for arg in node.nodes:
1250 self.visit(arg, frame)
1251 self.write(', ')
1252 self.write('))')
1253
Armin Ronachere791c2a2008-04-07 18:39:54 +02001254 def visit_Compare(self, node, frame):
1255 self.visit(node.expr, frame)
1256 for op in node.ops:
1257 self.visit(op, frame)
1258
1259 def visit_Operand(self, node, frame):
1260 self.write(' %s ' % operators[node.op])
1261 self.visit(node.expr, frame)
1262
1263 def visit_Subscript(self, node, frame):
Armin Ronacher08a6a3b2008-05-13 15:35:47 +02001264 # slices or integer subscriptions bypass the subscribe
1265 # method if we can determine that at compile time.
1266 if isinstance(node.arg, nodes.Slice) or \
1267 (isinstance(node.arg, nodes.Const) and
1268 isinstance(node.arg.value, (int, long))):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001269 self.visit(node.node, frame)
1270 self.write('[')
1271 self.visit(node.arg, frame)
1272 self.write(']')
1273 return
Armin Ronacherc63243e2008-04-14 22:53:58 +02001274 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001275 self.visit(node.node, frame)
1276 self.write(', ')
Armin Ronacherab5ad8c2008-05-17 00:34:11 +02001277 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001278 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001279
1280 def visit_Slice(self, node, frame):
1281 if node.start is not None:
1282 self.visit(node.start, frame)
1283 self.write(':')
1284 if node.stop is not None:
1285 self.visit(node.stop, frame)
1286 if node.step is not None:
1287 self.write(':')
1288 self.visit(node.step, frame)
1289
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001290 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001291 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001292 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001293 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001294 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001295 if getattr(func, 'contextfilter', False):
1296 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001297 elif getattr(func, 'environmentfilter', False):
1298 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001299 if isinstance(node.node, nodes.Filter):
1300 self.visit_Filter(node.node, frame, initial)
1301 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001302 self.write(initial)
1303 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001304 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001305 self.signature(node, frame)
1306 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001307
1308 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001309 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001310 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001311 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001312 self.visit(node.node, frame)
1313 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001314 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001315
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001316 def visit_CondExpr(self, node, frame):
1317 if not have_condexpr:
1318 self.write('((')
1319 self.visit(node.test, frame)
1320 self.write(') and (')
1321 self.visit(node.expr1, frame)
1322 self.write(',) or (')
1323 self.visit(node.expr2, frame)
1324 self.write(',))[0]')
1325 else:
1326 self.write('(')
1327 self.visit(node.expr1, frame)
1328 self.write(' if ')
1329 self.visit(node.test, frame)
1330 self.write(' else ')
1331 self.visit(node.expr2, frame)
1332 self.write(')')
1333
Armin Ronacher71082072008-04-12 14:19:36 +02001334 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001335 if self.environment.sandboxed:
1336 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001337 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001338 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001339 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001340 self.write(')')
1341
1342 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001343 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001344 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001345
1346 # Unused nodes for extensions
1347
1348 def visit_MarkSafe(self, node, frame):
1349 self.write('Markup(')
1350 self.visit(node.expr, frame)
1351 self.write(')')
1352
1353 def visit_EnvironmentAttribute(self, node, frame):
1354 self.write('environment.' + node.name)
1355
1356 def visit_ExtensionAttribute(self, node, frame):
1357 self.write('environment.extensions[%r].%s' % (node.identifier, node.attr))
1358
1359 def visit_ImportedName(self, node, frame):
1360 self.write(self.import_aliases[node.importname])
1361
1362 def visit_InternalName(self, node, frame):
1363 self.write(node.name)
1364
1365 def visit_Continue(self, node, frame):
1366 self.writeline('continue', node)
1367
1368 def visit_Break(self, node, frame):
1369 self.writeline('break', node)