blob: 9bf00445b94290a13097d5f58eb897ab22af9849 [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 Ronacher8efc5222008-04-08 14:47:40 +020011from copy import copy
Armin Ronacher2feed1d2008-04-26 16:26:52 +020012from keyword import iskeyword
Armin Ronachere791c2a2008-04-07 18:39:54 +020013from cStringIO import StringIO
Armin Ronacherd1ff8582008-05-11 00:30:43 +020014from itertools import chain
Armin Ronachere791c2a2008-04-07 18:39:54 +020015from jinja2 import nodes
16from jinja2.visitor import NodeVisitor, NodeTransformer
17from jinja2.exceptions import TemplateAssertionError
Armin Ronacher7ceced52008-05-03 10:15:31 +020018from jinja2.utils import Markup, concat
Armin Ronachere791c2a2008-04-07 18:39:54 +020019
20
21operators = {
22 'eq': '==',
23 'ne': '!=',
24 'gt': '>',
25 'gteq': '>=',
26 'lt': '<',
27 'lteq': '<=',
28 'in': 'in',
29 'notin': 'not in'
30}
31
Armin Ronacher3d8b7842008-04-13 13:16:50 +020032try:
33 exec '(0 if 0 else 0)'
34except SyntaxError:
35 have_condexpr = False
36else:
37 have_condexpr = True
38
39
Armin Ronacher8e8d0712008-04-16 23:10:49 +020040def generate(node, environment, name, filename, stream=None):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020041 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020042 if not isinstance(node, nodes.Template):
43 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher69e12db2008-05-12 09:00:03 +020044 node.freeze()
Armin Ronacher8e8d0712008-04-16 23:10:49 +020045 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020046 generator.visit(node)
47 if stream is None:
48 return generator.stream.getvalue()
49
50
Armin Ronacher4dfc9752008-04-09 15:03:29 +020051def has_safe_repr(value):
52 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020053 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020054 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020055 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher32a910f2008-04-26 23:21:03 +020056 xrange, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020057 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020058 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020059 for item in value:
60 if not has_safe_repr(item):
61 return False
62 return True
63 elif isinstance(value, dict):
64 for key, value in value.iteritems():
65 if not has_safe_repr(key):
66 return False
67 if not has_safe_repr(value):
68 return False
69 return True
70 return False
71
72
Armin Ronacherc9705c22008-04-27 21:28:03 +020073def find_undeclared(nodes, names):
74 """Check if the names passed are accessed undeclared. The return value
75 is a set of all the undeclared names from the sequence of names found.
76 """
77 visitor = UndeclaredNameVisitor(names)
78 try:
79 for node in nodes:
80 visitor.visit(node)
81 except VisitorExit:
82 pass
83 return visitor.undeclared
84
85
Armin Ronachere791c2a2008-04-07 18:39:54 +020086class Identifiers(object):
87 """Tracks the status of identifiers in frames."""
88
89 def __init__(self):
90 # variables that are known to be declared (probably from outer
91 # frames or because they are special for the frame)
92 self.declared = set()
93
Armin Ronacher10f3ba22008-04-18 11:30:37 +020094 # undeclared variables from outer scopes
95 self.outer_undeclared = set()
96
Armin Ronachere791c2a2008-04-07 18:39:54 +020097 # names that are accessed without being explicitly declared by
98 # this one or any of the outer scopes. Names can appear both in
99 # declared and undeclared.
100 self.undeclared = set()
101
102 # names that are declared locally
103 self.declared_locally = set()
104
105 # names that are declared by parameters
106 self.declared_parameter = set()
107
108 def add_special(self, name):
109 """Register a special name like `loop`."""
110 self.undeclared.discard(name)
111 self.declared.add(name)
112
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200113 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200114 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200115 if name in self.declared_locally or name in self.declared_parameter:
116 return True
117 if local_only:
118 return False
119 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200120
121 def find_shadowed(self):
122 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200123 return (self.declared | self.outer_undeclared) & \
124 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200125
126
127class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200128 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200129
130 def __init__(self, parent=None):
131 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200132
Armin Ronacher75cfb862008-04-11 13:47:22 +0200133 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200134 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200135
Armin Ronacher75cfb862008-04-11 13:47:22 +0200136 # the root frame is basically just the outermost frame, so no if
137 # conditions. This information is used to optimize inheritance
138 # situations.
139 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200140
141 # inside some tags we are using a buffer rather than yield statements.
142 # this for example affects {% filter %} or {% macro %}. If a frame
143 # is buffered this variable points to the name of the list used as
144 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200145 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200146
Armin Ronacherfed44b52008-04-13 19:42:53 +0200147 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200148 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200149
150 # the parent of this frame
151 self.parent = parent
152
Armin Ronachere791c2a2008-04-07 18:39:54 +0200153 if parent is not None:
154 self.identifiers.declared.update(
155 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200156 parent.identifiers.declared_locally |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200157 parent.identifiers.declared_parameter |
158 parent.identifiers.undeclared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200159 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200160 self.identifiers.outer_undeclared.update(
161 parent.identifiers.undeclared -
162 self.identifiers.declared
163 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200164 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200165
Armin Ronacher8efc5222008-04-08 14:47:40 +0200166 def copy(self):
167 """Create a copy of the current one."""
168 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200169 rv.identifiers = copy(self.identifiers)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200170 return rv
171
Armin Ronacherc9705c22008-04-27 21:28:03 +0200172 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200173 """Walk the node and check for identifiers. If the scope is hard (eg:
174 enforce on a python level) overrides from outer scopes are tracked
175 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200176 """
177 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200178 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200179 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200180
181 def inner(self):
182 """Return an inner frame."""
183 return Frame(self)
184
Armin Ronacher75cfb862008-04-11 13:47:22 +0200185 def soft(self):
186 """Return a soft frame. A soft frame may not be modified as
187 standalone thing as it shares the resources with the frame it
188 was created of, but it's not a rootlevel frame any longer.
189 """
190 rv = copy(self)
191 rv.rootlevel = False
192 return rv
193
Armin Ronachere791c2a2008-04-07 18:39:54 +0200194
Armin Ronacherc9705c22008-04-27 21:28:03 +0200195class VisitorExit(RuntimeError):
196 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
197
198
199class DependencyFinderVisitor(NodeVisitor):
200 """A visitor that collects filter and test calls."""
201
202 def __init__(self):
203 self.filters = set()
204 self.tests = set()
205
206 def visit_Filter(self, node):
207 self.generic_visit(node)
208 self.filters.add(node.name)
209
210 def visit_Test(self, node):
211 self.generic_visit(node)
212 self.tests.add(node.name)
213
214 def visit_Block(self, node):
215 """Stop visiting at blocks."""
216
217
218class UndeclaredNameVisitor(NodeVisitor):
219 """A visitor that checks if a name is accessed without being
220 declared. This is different from the frame visitor as it will
221 not stop at closure frames.
222 """
223
224 def __init__(self, names):
225 self.names = set(names)
226 self.undeclared = set()
227
228 def visit_Name(self, node):
229 if node.ctx == 'load' and node.name in self.names:
230 self.undeclared.add(node.name)
231 if self.undeclared == self.names:
232 raise VisitorExit()
233 else:
234 self.names.discard(node.name)
235
236 def visit_Block(self, node):
237 """Stop visiting a blocks."""
238
239
Armin Ronachere791c2a2008-04-07 18:39:54 +0200240class FrameIdentifierVisitor(NodeVisitor):
241 """A visitor for `Frame.inspect`."""
242
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200243 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200244 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200245 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200246
Armin Ronacherc9705c22008-04-27 21:28:03 +0200247 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200248 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200249 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200250 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200251 elif node.ctx == 'param':
252 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200253 elif node.ctx == 'load' and not \
254 self.identifiers.is_declared(node.name, self.hard_scope):
255 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200256
Armin Ronacherc9705c22008-04-27 21:28:03 +0200257 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200258 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200259
Armin Ronacherc9705c22008-04-27 21:28:03 +0200260 def visit_Import(self, node):
261 self.generic_visit(node)
262 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200263
Armin Ronacherc9705c22008-04-27 21:28:03 +0200264 def visit_FromImport(self, node):
265 self.generic_visit(node)
266 for name in node.names:
267 if isinstance(name, tuple):
268 self.identifiers.declared_locally.add(name[1])
269 else:
270 self.identifiers.declared_locally.add(name)
271
272 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200273 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200274 self.visit(node.node)
275 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200276
Armin Ronacherc9705c22008-04-27 21:28:03 +0200277 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200278 """Visiting stops at for blocks. However the block sequence
279 is visited as part of the outer scope.
280 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200281 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200282
Armin Ronacherc9705c22008-04-27 21:28:03 +0200283 def visit_CallBlock(self, node):
284 for child in node.iter_child_nodes(exclude=('body',)):
285 self.visit(child)
286
287 def visit_FilterBlock(self, node):
288 self.visit(node.filter)
289
290 def visit_Block(self, node):
291 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200292
293
Armin Ronacher75cfb862008-04-11 13:47:22 +0200294class CompilerExit(Exception):
295 """Raised if the compiler encountered a situation where it just
296 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200297 raises such an exception is not further processed.
298 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200299
300
Armin Ronachere791c2a2008-04-07 18:39:54 +0200301class CodeGenerator(NodeVisitor):
302
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200303 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200304 if stream is None:
305 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200306 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200307 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200308 self.filename = filename
309 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200310
Armin Ronacher023b5e92008-05-08 11:03:10 +0200311 # aliases for imports
312 self.import_aliases = {}
313
Armin Ronacherfed44b52008-04-13 19:42:53 +0200314 # a registry for all blocks. Because blocks are moved out
315 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200316 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200317
318 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200319 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200320
321 # some templates have a rootlevel extends. In this case we
322 # can safely assume that we're a child template and do some
323 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200324 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200325
Armin Ronacherba3757b2008-04-16 19:43:16 +0200326 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200327 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200328
Armin Ronacherb9e78752008-05-10 23:36:28 +0200329 # registry of all filters and tests (global, not block local)
330 self.tests = {}
331 self.filters = {}
332
Armin Ronacherba3757b2008-04-16 19:43:16 +0200333 # the debug information
334 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200335 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200336
Armin Ronacherfed44b52008-04-13 19:42:53 +0200337 # the number of new lines before the next write()
338 self._new_lines = 0
339
340 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200341 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200342
343 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200344 self._first_write = True
345
Armin Ronacherfed44b52008-04-13 19:42:53 +0200346 # used by the `temporary_identifier` method to get new
347 # unique, temporary identifier
348 self._last_identifier = 0
349
350 # the current indentation
351 self._indentation = 0
352
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200353 # -- Various compilation helpers
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 Ronachera2eb77d2008-05-22 20:28:21 +0200384 def start_write(self, frame, node=None):
385 """Yield or write into the frame buffer."""
386 if frame.buffer is None:
387 self.writeline('yield ', node)
388 else:
389 self.writeline('%s.append(' % frame.buffer, node)
390
391 def end_write(self, frame):
392 """End the writing process started by `start_write`."""
393 if frame.buffer is not None:
394 self.write(')')
395
396 def simple_write(self, s, frame, node=None):
397 """Simple shortcut for start_write + write + end_write."""
398 self.start_write(frame, node)
399 self.write(s)
400 self.end_write(frame)
401
Armin Ronacherc9705c22008-04-27 21:28:03 +0200402 def blockvisit(self, nodes, frame, force_generator=True):
403 """Visit a list of nodes as block in a frame. If the current frame
404 is no buffer a dummy ``if 0: yield None`` is written automatically
405 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200406 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200407 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200408 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200409 try:
410 for node in nodes:
411 self.visit(node, frame)
412 except CompilerExit:
413 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200414
415 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200416 """Write a string into the output stream."""
417 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200418 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200419 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200420 self.code_lineno += self._new_lines
421 if self._write_debug_info is not None:
422 self.debug_info.append((self._write_debug_info,
423 self.code_lineno))
424 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200425 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200426 self.stream.write(' ' * self._indentation)
427 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200428 self.stream.write(x)
429
430 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200431 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200432 self.newline(node, extra)
433 self.write(x)
434
435 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200436 """Add one or more newlines before the next write."""
437 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200438 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200439 self._write_debug_info = node.lineno
440 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200441
Armin Ronacher71082072008-04-12 14:19:36 +0200442 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200443 """Writes a function call to the stream for the current node.
444 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200445 disabled by setting have_comma to False. The extra keyword
446 arguments may not include python keywords otherwise a syntax
447 error could occour. The extra keyword arguments should be given
448 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200449 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200450 have_comma = have_comma and [True] or []
451 def touch_comma():
452 if have_comma:
453 self.write(', ')
454 else:
455 have_comma.append(True)
456
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200457 # if any of the given keyword arguments is a python keyword
458 # we have to make sure that no invalid call is created.
459 kwarg_workaround = False
460 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
461 if iskeyword(kwarg):
462 kwarg_workaround = True
463 break
464
Armin Ronacher8efc5222008-04-08 14:47:40 +0200465 for arg in node.args:
466 touch_comma()
467 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200468
469 if not kwarg_workaround:
470 for kwarg in node.kwargs:
471 touch_comma()
472 self.visit(kwarg, frame)
473 if extra_kwargs is not None:
474 for key, value in extra_kwargs.iteritems():
475 touch_comma()
476 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200477 if node.dyn_args:
478 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200479 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200480 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200481
482 if kwarg_workaround:
483 touch_comma()
484 if node.dyn_kwargs is not None:
485 self.write('**dict({')
486 else:
487 self.write('**{')
488 for kwarg in node.kwargs:
489 self.write('%r: ' % kwarg.key)
490 self.visit(kwarg.value, frame)
491 self.write(', ')
492 if extra_kwargs is not None:
493 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200494 self.write('%r: %s, ' % (key, value))
495 if node.dyn_kwargs is not None:
496 self.write('}, **')
497 self.visit(node.dyn_kwargs, frame)
498 self.write(')')
499 else:
500 self.write('}')
501
502 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200503 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200504 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200505 self.visit(node.dyn_kwargs, frame)
506
Armin Ronacherc9705c22008-04-27 21:28:03 +0200507 def pull_locals(self, frame):
508 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200509 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200510 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200511
512 def pull_dependencies(self, nodes):
513 """Pull all the dependencies."""
514 visitor = DependencyFinderVisitor()
515 for node in nodes:
516 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200517 for dependency in 'filters', 'tests':
518 mapping = getattr(self, dependency)
519 for name in getattr(visitor, dependency):
520 if name not in mapping:
521 mapping[name] = self.temporary_identifier()
522 self.writeline('%s = environment.%s[%r]' %
523 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200524
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200525 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200526 """This function returns all the shadowed variables in a dict
527 in the form name: alias and will write the required assignments
528 into the current scope. No indentation takes place.
529 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200530 aliases = {}
531 for name in frame.identifiers.find_shadowed():
532 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200533 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200534 return aliases
535
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200536 def restore_shadowed(self, aliases):
537 """Restore all aliases."""
538 for name, alias in aliases.iteritems():
539 self.writeline('l_%s = %s' % (name, alias))
540
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200541 def function_scoping(self, node, frame, children=None,
542 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200543 """In Jinja a few statements require the help of anonymous
544 functions. Those are currently macros and call blocks and in
545 the future also recursive loops. As there is currently
546 technical limitation that doesn't allow reading and writing a
547 variable in a scope where the initial value is coming from an
548 outer scope, this function tries to fall back with a common
549 error message. Additionally the frame passed is modified so
550 that the argumetns are collected and callers are looked up.
551
552 This will return the modified frame.
553 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200554 # we have to iterate twice over it, make sure that works
555 if children is None:
556 children = node.iter_child_nodes()
557 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200558 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200559 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200560
561 # variables that are undeclared (accessed before declaration) and
562 # declared locally *and* part of an outside scope raise a template
563 # assertion error. Reason: we can't generate reasonable code from
564 # it without aliasing all the variables. XXX: alias them ^^
565 overriden_closure_vars = (
566 func_frame.identifiers.undeclared &
567 func_frame.identifiers.declared &
568 (func_frame.identifiers.declared_locally |
569 func_frame.identifiers.declared_parameter)
570 )
571 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200572 self.fail('It\'s not possible to set and access variables '
573 'derived from an outer scope! (affects: %s' %
574 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200575
576 # remove variables from a closure from the frame's undeclared
577 # identifiers.
578 func_frame.identifiers.undeclared -= (
579 func_frame.identifiers.undeclared &
580 func_frame.identifiers.declared
581 )
582
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200583 # no special variables for this scope, abort early
584 if not find_special:
585 return func_frame
586
Armin Ronacher963f97d2008-04-25 11:44:59 +0200587 func_frame.accesses_kwargs = False
588 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200589 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200590 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200591
Armin Ronacherc9705c22008-04-27 21:28:03 +0200592 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
593
594 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200595 func_frame.accesses_caller = True
596 func_frame.identifiers.add_special('caller')
597 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200598 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200599 func_frame.accesses_kwargs = True
600 func_frame.identifiers.add_special('kwargs')
601 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200602 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200603 func_frame.accesses_varargs = True
604 func_frame.identifiers.add_special('varargs')
605 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200606 return func_frame
607
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200608 def macro_body(self, node, frame, children=None):
609 """Dump the function def of a macro or call block."""
610 frame = self.function_scoping(node, frame, children)
611 args = frame.arguments
612 self.writeline('def macro(%s):' % ', '.join(args), node)
613 self.indent()
614 self.buffer(frame)
615 self.pull_locals(frame)
616 self.blockvisit(node.body, frame)
617 self.return_buffer_contents(frame)
618 self.outdent()
619 return frame
620
621 def macro_def(self, node, frame):
622 """Dump the macro definition for the def created by macro_body."""
623 arg_tuple = ', '.join(repr(x.name) for x in node.args)
624 name = getattr(node, 'name', None)
625 if len(node.args) == 1:
626 arg_tuple += ','
627 self.write('Macro(environment, macro, %r, (%s), (' %
628 (name, arg_tuple))
629 for arg in node.defaults:
630 self.visit(arg, frame)
631 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200632 self.write('), %r, %r, %r)' % (
633 bool(frame.accesses_kwargs),
634 bool(frame.accesses_varargs),
635 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200636 ))
637
638 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200639
640 def visit_Template(self, node, frame=None):
641 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200642 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200643 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200644 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8edbe492008-04-10 20:43:43 +0200645
Armin Ronacher75cfb862008-04-11 13:47:22 +0200646 # do we have an extends tag at all? If not, we can save some
647 # overhead by just not processing any inheritance code.
648 have_extends = node.find(nodes.Extends) is not None
649
Armin Ronacher8edbe492008-04-10 20:43:43 +0200650 # find all blocks
651 for block in node.find_all(nodes.Block):
652 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200653 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200654 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200655
Armin Ronacher023b5e92008-05-08 11:03:10 +0200656 # find all imports and import them
657 for import_ in node.find_all(nodes.ImportedName):
658 if import_.importname not in self.import_aliases:
659 imp = import_.importname
660 self.import_aliases[imp] = alias = self.temporary_identifier()
661 if '.' in imp:
662 module, obj = imp.rsplit('.', 1)
663 self.writeline('from %s import %s as %s' %
664 (module, obj, alias))
665 else:
666 self.writeline('import %s as %s' % (imp, alias))
667
668 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200669 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200670
Armin Ronacher8efc5222008-04-08 14:47:40 +0200671 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200672 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200673
674 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200675 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200676 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200677 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200678 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200679 if have_extends:
680 self.writeline('parent_template = None')
681 self.pull_locals(frame)
682 self.pull_dependencies(node.body)
683 if 'self' in find_undeclared(node.body, ('self',)):
684 frame.identifiers.add_special('self')
685 self.writeline('l_self = TemplateReference(context)')
686 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200687 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200688
Armin Ronacher8efc5222008-04-08 14:47:40 +0200689 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200690 if have_extends:
691 if not self.has_known_extends:
692 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200693 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200694 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200695 self.writeline('for event in parent_template.'
Armin Ronacher771c7502008-05-18 23:14:14 +0200696 '_root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200697 self.indent()
698 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200699 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200700
701 # at this point we now have the blocks collected and can visit them too.
702 for name, block in self.blocks.iteritems():
703 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200704 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200705 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200706 self.writeline('def block_%s(context, environment=environment):'
707 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200708 self.indent()
709 undeclared = find_undeclared(block.body, ('self', 'super'))
710 if 'self' in undeclared:
711 block_frame.identifiers.add_special('self')
712 self.writeline('l_self = TemplateReference(context)')
713 if 'super' in undeclared:
714 block_frame.identifiers.add_special('super')
715 self.writeline('l_super = context.super(%r, '
716 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200717 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200718 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200719 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200720 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200721
Armin Ronacher75cfb862008-04-11 13:47:22 +0200722 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200723 for x in self.blocks),
724 extra=1)
725
726 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200727 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
728 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200729
Armin Ronachere791c2a2008-04-07 18:39:54 +0200730 def visit_Block(self, node, frame):
731 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200732 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200733 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200734 # if we know that we are a child template, there is no need to
735 # check if we are one
736 if self.has_known_extends:
737 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200738 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200739 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200740 self.indent()
741 level += 1
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200742 self.writeline('for event in context.blocks[%r][0](context):' %
Armin Ronacherc9705c22008-04-27 21:28:03 +0200743 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200744 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200745 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200746 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200747
748 def visit_Extends(self, node, frame):
749 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200750 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200751 self.fail('cannot use extend from a non top-level scope',
752 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200753
Armin Ronacher7fb38972008-04-11 13:54:28 +0200754 # if the number of extends statements in general is zero so
755 # far, we don't have to add a check if something extended
756 # the template before this one.
757 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200758
Armin Ronacher7fb38972008-04-11 13:54:28 +0200759 # if we have a known extends we just add a template runtime
760 # error into the generated code. We could catch that at compile
761 # time too, but i welcome it not to confuse users by throwing the
762 # same error at different times just "because we can".
763 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200764 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200765 self.indent()
766 self.writeline('raise TemplateRuntimeError(%r)' %
767 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200768
Armin Ronacher7fb38972008-04-11 13:54:28 +0200769 # if we have a known extends already we don't need that code here
770 # as we know that the template execution will end here.
771 if self.has_known_extends:
772 raise CompilerExit()
773 self.outdent()
774
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200775 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200776 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200777 self.write(', %r)' % self.name)
778 self.writeline('for name, parent_block in parent_template.'
779 'blocks.iteritems():')
780 self.indent()
781 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200782 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200783 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200784
785 # if this extends statement was in the root level we can take
786 # advantage of that information and simplify the generated code
787 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200788 if frame.rootlevel:
789 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200790
Armin Ronacher7fb38972008-04-11 13:54:28 +0200791 # and now we have one more
792 self.extends_so_far += 1
793
Armin Ronacherf059ec12008-04-11 22:21:00 +0200794 def visit_Include(self, node, frame):
795 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200796 if node.with_context:
797 self.writeline('template = environment.get_template(', node)
798 self.visit(node.template, frame)
799 self.write(', %r)' % self.name)
Armin Ronacher771c7502008-05-18 23:14:14 +0200800 self.writeline('for event in template._root_render_func('
Armin Ronacherea847c52008-05-02 20:04:32 +0200801 'template.new_context(context.parent, True)):')
802 else:
803 self.writeline('for event in environment.get_template(', node)
804 self.visit(node.template, frame)
Armin Ronacher771c7502008-05-18 23:14:14 +0200805 self.write(', %r).module._body_stream:' %
Armin Ronacherea847c52008-05-02 20:04:32 +0200806 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200807 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200808 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200809 self.outdent()
810
Armin Ronacher0611e492008-04-25 23:44:14 +0200811 def visit_Import(self, node, frame):
812 """Visit regular imports."""
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200813 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200814 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200815 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200816 self.write('environment.get_template(')
817 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200818 self.write(', %r).' % self.name)
819 if node.with_context:
820 self.write('make_module(context.parent, True)')
821 else:
822 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200823 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200824 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200825
826 def visit_FromImport(self, node, frame):
827 """Visit named imports."""
828 self.newline(node)
829 self.write('included_template = environment.get_template(')
830 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200831 self.write(', %r).' % self.name)
832 if node.with_context:
833 self.write('make_module(context.parent, True)')
834 else:
835 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200836
837 var_names = []
838 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200839 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200840 if isinstance(name, tuple):
841 name, alias = name
842 else:
843 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200844 self.writeline('l_%s = getattr(included_template, '
845 '%r, missing)' % (alias, name))
846 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200847 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200848 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +0200849 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200850 'name=%r)' %
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200851 (alias, 'the template %r does not export '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200852 'the requested name ' + repr(name), name))
Armin Ronacher0611e492008-04-25 23:44:14 +0200853 self.outdent()
854 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +0200855 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +0200856 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +0200857 discarded_names.append(alias)
858
859 if var_names:
860 if len(var_names) == 1:
861 name = var_names[0]
862 self.writeline('context.vars[%r] = l_%s' % (name, name))
863 else:
864 self.writeline('context.vars.update({%s})' % ', '.join(
865 '%r: l_%s' % (name, name) for name in var_names
866 ))
867 if discarded_names:
868 if len(discarded_names) == 1:
869 self.writeline('context.exported_vars.discard(%r)' %
870 discarded_names[0])
871 else:
872 self.writeline('context.exported_vars.difference_'
873 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200874
Armin Ronachere791c2a2008-04-07 18:39:54 +0200875 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200876 # when calculating the nodes for the inner frame we have to exclude
877 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200878 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200879 if node.recursive:
880 loop_frame = self.function_scoping(node, frame, children,
881 find_special=False)
882 else:
883 loop_frame = frame.inner()
884 loop_frame.inspect(children)
885
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200886 # try to figure out if we have an extended loop. An extended loop
887 # is necessary if the loop is in recursive mode if the special loop
888 # variable is accessed in the body.
889 extended_loop = node.recursive or 'loop' in \
890 find_undeclared(node.iter_child_nodes(
891 only=('body',)), ('loop',))
892
893 # make sure the loop variable is a special one and raise a template
894 # assertion error if a loop tries to write to loop
895 loop_frame.identifiers.add_special('loop')
896 for name in node.find_all(nodes.Name):
897 if name.ctx == 'store' and name.name == 'loop':
898 self.fail('Can\'t assign to special loop variable '
899 'in for-loop target', name.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200900
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200901 # if we don't have an recursive loop we have to find the shadowed
902 # variables at that point
903 if not node.recursive:
904 aliases = self.collect_shadowed(loop_frame)
905
906 # otherwise we set up a buffer and add a function def
907 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200908 self.writeline('def loop(reciter, loop_render_func):', node)
909 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +0200910 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200911 aliases = {}
912
Armin Ronacherc9705c22008-04-27 21:28:03 +0200913 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200914 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200915 iteration_indicator = self.temporary_identifier()
916 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200917
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200918 # Create a fake parent loop if the else or test section of a
919 # loop is accessing the special loop variable and no parent loop
920 # exists.
921 if 'loop' not in aliases and 'loop' in find_undeclared(
922 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
923 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
924 "'loop' is undefined. the filter section of a loop as well " \
925 "as the else block doesn't have access to the special 'loop' "
926 "variable of the current loop. Because there is no parent "
927 "loop it's undefined.")
928
929 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200930 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200931 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200932
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200933 # if we have an extened loop and a node test, we filter in the
934 # "outer frame".
935 if extended_loop and node.test is not None:
936 self.write('(')
937 self.visit(node.target, loop_frame)
938 self.write(' for ')
939 self.visit(node.target, loop_frame)
940 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200941 if node.recursive:
942 self.write('reciter')
943 else:
944 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200945 self.write(' if (')
946 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200947 self.visit(node.test, test_frame)
948 self.write('))')
949
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200950 elif node.recursive:
951 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200952 else:
953 self.visit(node.iter, loop_frame)
954
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200955 if node.recursive:
956 self.write(', recurse=loop_render_func):')
957 else:
958 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200959
960 # tests in not extended loops become a continue
961 if not extended_loop and node.test is not None:
962 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200963 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200964 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200965 self.write(':')
966 self.indent()
967 self.writeline('continue')
968 self.outdent(2)
969
Armin Ronacherc9705c22008-04-27 21:28:03 +0200970 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200971 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200972 if node.else_:
973 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200974 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200975
976 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200977 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200978 self.indent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200979 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200980 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200981
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200982 # reset the aliases if there are any.
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200983 self.restore_shadowed(aliases)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200984
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200985 # if the node was recursive we have to return the buffer contents
986 # and start the iteration code
987 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200988 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200989 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200990 self.start_write(frame, node)
991 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200992 self.visit(node.iter, frame)
993 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200994 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200995
Armin Ronachere791c2a2008-04-07 18:39:54 +0200996 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200997 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200998 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200999 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001000 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001001 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001002 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001003 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001004 if node.else_:
1005 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001006 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001007 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001008 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001009
Armin Ronacher8efc5222008-04-08 14:47:40 +02001010 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001011 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001012 self.newline()
1013 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001014 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001015 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001016 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001017 self.write('l_%s = ' % node.name)
1018 self.macro_def(node, macro_frame)
Armin Ronacher71082072008-04-12 14:19:36 +02001019
1020 def visit_CallBlock(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001021 call_frame = self.macro_body(node, frame, node.iter_child_nodes
1022 (exclude=('call',)))
1023 self.writeline('caller = ')
1024 self.macro_def(node, call_frame)
1025 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001026 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001027 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001028
1029 def visit_FilterBlock(self, node, frame):
1030 filter_frame = frame.inner()
1031 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001032 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001033 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001034 self.buffer(filter_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001035 self.blockvisit(node.body, filter_frame, force_generator=False)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001036 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001037 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001038 self.end_write(frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001039 self.restore_shadowed(aliases)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001040
Armin Ronachere791c2a2008-04-07 18:39:54 +02001041 def visit_ExprStmt(self, node, frame):
1042 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001043 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001044
1045 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001046 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +02001047 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001048 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001049
Armin Ronacher75cfb862008-04-11 13:47:22 +02001050 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001051
Armin Ronacher7fb38972008-04-11 13:54:28 +02001052 # if we are in the toplevel scope and there was already an extends
1053 # statement we have to add a check that disables our yield(s) here
1054 # so that they don't appear in the output.
1055 outdent_later = False
1056 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001057 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001058 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001059 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001060
Armin Ronachere791c2a2008-04-07 18:39:54 +02001061 # try to evaluate as many chunks as possible into a static
1062 # string at compile time.
1063 body = []
1064 for child in node.nodes:
1065 try:
1066 const = unicode(child.as_const())
1067 except:
1068 body.append(child)
1069 continue
1070 if body and isinstance(body[-1], list):
1071 body[-1].append(const)
1072 else:
1073 body.append([const])
1074
Armin Ronachered1e0d42008-05-18 20:25:28 +02001075 # if we have less than 3 nodes or a buffer we yield or extend/append
1076 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001077 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001078 # for one item we append, for more we extend
1079 if len(body) == 1:
1080 self.writeline('%s.append(' % frame.buffer)
1081 else:
1082 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001083 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001084 for item in body:
1085 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001086 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001087 if frame.buffer is None:
1088 self.writeline('yield ' + val)
1089 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001090 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001091 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001092 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001093 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001094 else:
1095 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001096 close = 1
1097 if self.environment.autoescape:
1098 self.write('escape(')
1099 else:
1100 self.write('unicode(')
1101 if self.environment.finalize is not None:
1102 self.write('environment.finalize(')
1103 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001104 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001105 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001106 if frame.buffer is not None:
1107 self.write(', ')
1108 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001109 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001110 self.outdent()
1111 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001112
1113 # otherwise we create a format string as this is faster in that case
1114 else:
1115 format = []
1116 arguments = []
1117 for item in body:
1118 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001119 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001120 else:
1121 format.append('%s')
1122 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001123 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001124 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001125 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001126 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001127 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001128 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001129 close = 0
1130 if self.environment.autoescape:
1131 self.write('escape(')
1132 close += 1
1133 if self.environment.finalize is not None:
1134 self.write('environment.finalize(')
1135 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001136 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001137 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001138 self.outdent()
1139 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001140
Armin Ronacher7fb38972008-04-11 13:54:28 +02001141 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001142 self.outdent()
1143
Armin Ronacher8efc5222008-04-08 14:47:40 +02001144 def visit_Assign(self, node, frame):
1145 self.newline(node)
1146 # toplevel assignments however go into the local namespace and
1147 # the current template's context. We create a copy of the frame
1148 # here and add a set so that the Name visitor can add the assigned
1149 # names here.
1150 if frame.toplevel:
1151 assignment_frame = frame.copy()
1152 assignment_frame.assigned_names = set()
1153 else:
1154 assignment_frame = frame
1155 self.visit(node.target, assignment_frame)
1156 self.write(' = ')
1157 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001158
1159 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001160 if frame.toplevel:
Armin Ronacher69e12db2008-05-12 09:00:03 +02001161 public_names = [x for x in assignment_frame.assigned_names
Armin Ronacher903d1682008-05-23 00:51:58 +02001162 if not x.startswith('_')]
Armin Ronacher69e12db2008-05-12 09:00:03 +02001163 if len(assignment_frame.assigned_names) == 1:
1164 name = iter(assignment_frame.assigned_names).next()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001165 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001166 else:
1167 self.writeline('context.vars.update({')
1168 for idx, name in enumerate(assignment_frame.assigned_names):
1169 if idx:
1170 self.write(', ')
1171 self.write('%r: l_%s' % (name, name))
1172 self.write('})')
1173 if public_names:
1174 if len(public_names) == 1:
1175 self.writeline('context.exported_vars.add(%r)' %
1176 public_names[0])
1177 else:
1178 self.writeline('context.exported_vars.update((%s))' %
1179 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001180
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001181 # -- Expression Visitors
1182
Armin Ronachere791c2a2008-04-07 18:39:54 +02001183 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001184 if node.ctx == 'store' and frame.toplevel:
1185 frame.assigned_names.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001186 self.write('l_' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001187
1188 def visit_Const(self, node, frame):
1189 val = node.value
1190 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001191 self.write(str(val))
1192 else:
1193 self.write(repr(val))
1194
Armin Ronacher8efc5222008-04-08 14:47:40 +02001195 def visit_Tuple(self, node, frame):
1196 self.write('(')
1197 idx = -1
1198 for idx, item in enumerate(node.items):
1199 if idx:
1200 self.write(', ')
1201 self.visit(item, frame)
1202 self.write(idx == 0 and ',)' or ')')
1203
Armin Ronacher8edbe492008-04-10 20:43:43 +02001204 def visit_List(self, node, frame):
1205 self.write('[')
1206 for idx, item in enumerate(node.items):
1207 if idx:
1208 self.write(', ')
1209 self.visit(item, frame)
1210 self.write(']')
1211
1212 def visit_Dict(self, node, frame):
1213 self.write('{')
1214 for idx, item in enumerate(node.items):
1215 if idx:
1216 self.write(', ')
1217 self.visit(item.key, frame)
1218 self.write(': ')
1219 self.visit(item.value, frame)
1220 self.write('}')
1221
Armin Ronachere791c2a2008-04-07 18:39:54 +02001222 def binop(operator):
1223 def visitor(self, node, frame):
1224 self.write('(')
1225 self.visit(node.left, frame)
1226 self.write(' %s ' % operator)
1227 self.visit(node.right, frame)
1228 self.write(')')
1229 return visitor
1230
1231 def uaop(operator):
1232 def visitor(self, node, frame):
1233 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001234 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001235 self.write(')')
1236 return visitor
1237
1238 visit_Add = binop('+')
1239 visit_Sub = binop('-')
1240 visit_Mul = binop('*')
1241 visit_Div = binop('/')
1242 visit_FloorDiv = binop('//')
1243 visit_Pow = binop('**')
1244 visit_Mod = binop('%')
1245 visit_And = binop('and')
1246 visit_Or = binop('or')
1247 visit_Pos = uaop('+')
1248 visit_Neg = uaop('-')
1249 visit_Not = uaop('not ')
1250 del binop, uaop
1251
Armin Ronacherd1342312008-04-28 12:20:12 +02001252 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001253 self.write('%s((' % (self.environment.autoescape and
1254 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001255 for arg in node.nodes:
1256 self.visit(arg, frame)
1257 self.write(', ')
1258 self.write('))')
1259
Armin Ronachere791c2a2008-04-07 18:39:54 +02001260 def visit_Compare(self, node, frame):
1261 self.visit(node.expr, frame)
1262 for op in node.ops:
1263 self.visit(op, frame)
1264
1265 def visit_Operand(self, node, frame):
1266 self.write(' %s ' % operators[node.op])
1267 self.visit(node.expr, frame)
1268
1269 def visit_Subscript(self, node, frame):
Armin Ronacher08a6a3b2008-05-13 15:35:47 +02001270 # slices or integer subscriptions bypass the subscribe
1271 # method if we can determine that at compile time.
1272 if isinstance(node.arg, nodes.Slice) or \
1273 (isinstance(node.arg, nodes.Const) and
1274 isinstance(node.arg.value, (int, long))):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001275 self.visit(node.node, frame)
1276 self.write('[')
1277 self.visit(node.arg, frame)
1278 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001279 else:
1280 self.write('environment.subscribe(')
1281 self.visit(node.node, frame)
1282 self.write(', ')
1283 self.visit(node.arg, frame)
1284 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001285
1286 def visit_Slice(self, node, frame):
1287 if node.start is not None:
1288 self.visit(node.start, frame)
1289 self.write(':')
1290 if node.stop is not None:
1291 self.visit(node.stop, frame)
1292 if node.step is not None:
1293 self.write(':')
1294 self.visit(node.step, frame)
1295
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001296 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001297 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001298 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001299 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001300 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001301 if getattr(func, 'contextfilter', False):
1302 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001303 elif getattr(func, 'environmentfilter', False):
1304 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001305
1306 # if the filter node is None we are inside a filter block
1307 # and want to write to the current buffer
1308 if node.node is None:
1309 if self.environment.autoescape:
1310 tmpl = 'Markup(concat(%s))'
1311 else:
1312 tmpl = 'concat(%s)'
1313 self.write(tmpl % frame.buffer)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001314 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001315 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001316 self.signature(node, frame)
1317 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001318
1319 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001320 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001321 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001322 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001323 self.visit(node.node, frame)
1324 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001325 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001326
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001327 def visit_CondExpr(self, node, frame):
1328 if not have_condexpr:
1329 self.write('((')
1330 self.visit(node.test, frame)
1331 self.write(') and (')
1332 self.visit(node.expr1, frame)
1333 self.write(',) or (')
1334 self.visit(node.expr2, frame)
1335 self.write(',))[0]')
1336 else:
1337 self.write('(')
1338 self.visit(node.expr1, frame)
1339 self.write(' if ')
1340 self.visit(node.test, frame)
1341 self.write(' else ')
1342 self.visit(node.expr2, frame)
1343 self.write(')')
1344
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001345 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001346 if self.environment.sandboxed:
1347 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001348 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001349 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001350 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacher71082072008-04-12 14:19:36 +02001351 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001352 self.write(')')
1353
1354 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001355 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001356 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001357
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001358 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001359
1360 def visit_MarkSafe(self, node, frame):
1361 self.write('Markup(')
1362 self.visit(node.expr, frame)
1363 self.write(')')
1364
1365 def visit_EnvironmentAttribute(self, node, frame):
1366 self.write('environment.' + node.name)
1367
1368 def visit_ExtensionAttribute(self, node, frame):
1369 self.write('environment.extensions[%r].%s' % (node.identifier, node.attr))
1370
1371 def visit_ImportedName(self, node, frame):
1372 self.write(self.import_aliases[node.importname])
1373
1374 def visit_InternalName(self, node, frame):
1375 self.write(node.name)
1376
1377 def visit_Continue(self, node, frame):
1378 self.writeline('continue', node)
1379
1380 def visit_Break(self, node, frame):
1381 self.writeline('break', node)