blob: a90526ce05ae6d4ea565b1cc17a8f0d2dadf6a04 [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 Ronacher9cf95912008-05-24 19:54:43 +020018from jinja2.utils import Markup, concat, escape
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 Ronacher8e8d0712008-04-16 23:10:49 +020044 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020045 generator.visit(node)
46 if stream is None:
47 return generator.stream.getvalue()
48
49
Armin Ronacher4dfc9752008-04-09 15:03:29 +020050def has_safe_repr(value):
51 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020052 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020053 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020054 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher32a910f2008-04-26 23:21:03 +020055 xrange, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020056 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020057 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020058 for item in value:
59 if not has_safe_repr(item):
60 return False
61 return True
62 elif isinstance(value, dict):
63 for key, value in value.iteritems():
64 if not has_safe_repr(key):
65 return False
66 if not has_safe_repr(value):
67 return False
68 return True
69 return False
70
71
Armin Ronacherc9705c22008-04-27 21:28:03 +020072def find_undeclared(nodes, names):
73 """Check if the names passed are accessed undeclared. The return value
74 is a set of all the undeclared names from the sequence of names found.
75 """
76 visitor = UndeclaredNameVisitor(names)
77 try:
78 for node in nodes:
79 visitor.visit(node)
80 except VisitorExit:
81 pass
82 return visitor.undeclared
83
84
Armin Ronachere791c2a2008-04-07 18:39:54 +020085class Identifiers(object):
86 """Tracks the status of identifiers in frames."""
87
88 def __init__(self):
89 # variables that are known to be declared (probably from outer
90 # frames or because they are special for the frame)
91 self.declared = set()
92
Armin Ronacher10f3ba22008-04-18 11:30:37 +020093 # undeclared variables from outer scopes
94 self.outer_undeclared = set()
95
Armin Ronachere791c2a2008-04-07 18:39:54 +020096 # names that are accessed without being explicitly declared by
97 # this one or any of the outer scopes. Names can appear both in
98 # declared and undeclared.
99 self.undeclared = set()
100
101 # names that are declared locally
102 self.declared_locally = set()
103
104 # names that are declared by parameters
105 self.declared_parameter = set()
106
107 def add_special(self, name):
108 """Register a special name like `loop`."""
109 self.undeclared.discard(name)
110 self.declared.add(name)
111
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200112 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200113 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200114 if name in self.declared_locally or name in self.declared_parameter:
115 return True
116 if local_only:
117 return False
118 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200119
120 def find_shadowed(self):
121 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200122 return (self.declared | self.outer_undeclared) & \
123 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200124
125
126class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200127 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200128
129 def __init__(self, parent=None):
130 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200131
Armin Ronacher75cfb862008-04-11 13:47:22 +0200132 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200133 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200134
Armin Ronacher75cfb862008-04-11 13:47:22 +0200135 # the root frame is basically just the outermost frame, so no if
136 # conditions. This information is used to optimize inheritance
137 # situations.
138 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200139
140 # inside some tags we are using a buffer rather than yield statements.
141 # this for example affects {% filter %} or {% macro %}. If a frame
142 # is buffered this variable points to the name of the list used as
143 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200144 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200145
Armin Ronacherfed44b52008-04-13 19:42:53 +0200146 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200147 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200148
149 # the parent of this frame
150 self.parent = parent
151
Armin Ronachere791c2a2008-04-07 18:39:54 +0200152 if parent is not None:
153 self.identifiers.declared.update(
154 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200155 parent.identifiers.declared_locally |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200156 parent.identifiers.declared_parameter |
157 parent.identifiers.undeclared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200158 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200159 self.identifiers.outer_undeclared.update(
160 parent.identifiers.undeclared -
161 self.identifiers.declared
162 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200163 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200164
Armin Ronacher8efc5222008-04-08 14:47:40 +0200165 def copy(self):
166 """Create a copy of the current one."""
167 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200168 rv.identifiers = copy(self.identifiers)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200169 return rv
170
Armin Ronacherc9705c22008-04-27 21:28:03 +0200171 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200172 """Walk the node and check for identifiers. If the scope is hard (eg:
173 enforce on a python level) overrides from outer scopes are tracked
174 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200175 """
176 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200177 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200178 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200179
180 def inner(self):
181 """Return an inner frame."""
182 return Frame(self)
183
Armin Ronacher75cfb862008-04-11 13:47:22 +0200184 def soft(self):
185 """Return a soft frame. A soft frame may not be modified as
186 standalone thing as it shares the resources with the frame it
187 was created of, but it's not a rootlevel frame any longer.
188 """
189 rv = copy(self)
190 rv.rootlevel = False
191 return rv
192
Armin Ronachere791c2a2008-04-07 18:39:54 +0200193
Armin Ronacherc9705c22008-04-27 21:28:03 +0200194class VisitorExit(RuntimeError):
195 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
196
197
198class DependencyFinderVisitor(NodeVisitor):
199 """A visitor that collects filter and test calls."""
200
201 def __init__(self):
202 self.filters = set()
203 self.tests = set()
204
205 def visit_Filter(self, node):
206 self.generic_visit(node)
207 self.filters.add(node.name)
208
209 def visit_Test(self, node):
210 self.generic_visit(node)
211 self.tests.add(node.name)
212
213 def visit_Block(self, node):
214 """Stop visiting at blocks."""
215
216
217class UndeclaredNameVisitor(NodeVisitor):
218 """A visitor that checks if a name is accessed without being
219 declared. This is different from the frame visitor as it will
220 not stop at closure frames.
221 """
222
223 def __init__(self, names):
224 self.names = set(names)
225 self.undeclared = set()
226
227 def visit_Name(self, node):
228 if node.ctx == 'load' and node.name in self.names:
229 self.undeclared.add(node.name)
230 if self.undeclared == self.names:
231 raise VisitorExit()
232 else:
233 self.names.discard(node.name)
234
235 def visit_Block(self, node):
236 """Stop visiting a blocks."""
237
238
Armin Ronachere791c2a2008-04-07 18:39:54 +0200239class FrameIdentifierVisitor(NodeVisitor):
240 """A visitor for `Frame.inspect`."""
241
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200242 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200243 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200244 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200245
Armin Ronacherc9705c22008-04-27 21:28:03 +0200246 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200247 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200248 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200249 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200250 elif node.ctx == 'param':
251 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200252 elif node.ctx == 'load' and not \
253 self.identifiers.is_declared(node.name, self.hard_scope):
254 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200255
Armin Ronacherc9705c22008-04-27 21:28:03 +0200256 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200257 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200258
Armin Ronacherc9705c22008-04-27 21:28:03 +0200259 def visit_Import(self, node):
260 self.generic_visit(node)
261 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200262
Armin Ronacherc9705c22008-04-27 21:28:03 +0200263 def visit_FromImport(self, node):
264 self.generic_visit(node)
265 for name in node.names:
266 if isinstance(name, tuple):
267 self.identifiers.declared_locally.add(name[1])
268 else:
269 self.identifiers.declared_locally.add(name)
270
271 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200272 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200273 self.visit(node.node)
274 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200275
Armin Ronacherc9705c22008-04-27 21:28:03 +0200276 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200277 """Visiting stops at for blocks. However the block sequence
278 is visited as part of the outer scope.
279 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200280 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200281
Armin Ronacherc9705c22008-04-27 21:28:03 +0200282 def visit_CallBlock(self, node):
283 for child in node.iter_child_nodes(exclude=('body',)):
284 self.visit(child)
285
286 def visit_FilterBlock(self, node):
287 self.visit(node.filter)
288
289 def visit_Block(self, node):
290 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200291
292
Armin Ronacher75cfb862008-04-11 13:47:22 +0200293class CompilerExit(Exception):
294 """Raised if the compiler encountered a situation where it just
295 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200296 raises such an exception is not further processed.
297 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200298
299
Armin Ronachere791c2a2008-04-07 18:39:54 +0200300class CodeGenerator(NodeVisitor):
301
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200302 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200303 if stream is None:
304 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200305 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200306 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200307 self.filename = filename
308 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200309
Armin Ronacher023b5e92008-05-08 11:03:10 +0200310 # aliases for imports
311 self.import_aliases = {}
312
Armin Ronacherfed44b52008-04-13 19:42:53 +0200313 # a registry for all blocks. Because blocks are moved out
314 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200315 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200316
317 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200318 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200319
320 # some templates have a rootlevel extends. In this case we
321 # can safely assume that we're a child template and do some
322 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200323 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200324
Armin Ronacherba3757b2008-04-16 19:43:16 +0200325 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200326 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200327
Armin Ronacherb9e78752008-05-10 23:36:28 +0200328 # registry of all filters and tests (global, not block local)
329 self.tests = {}
330 self.filters = {}
331
Armin Ronacherba3757b2008-04-16 19:43:16 +0200332 # the debug information
333 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200334 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200335
Armin Ronacherfed44b52008-04-13 19:42:53 +0200336 # the number of new lines before the next write()
337 self._new_lines = 0
338
339 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200340 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200341
342 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200343 self._first_write = True
344
Armin Ronacherfed44b52008-04-13 19:42:53 +0200345 # used by the `temporary_identifier` method to get new
346 # unique, temporary identifier
347 self._last_identifier = 0
348
349 # the current indentation
350 self._indentation = 0
351
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200352 # -- Various compilation helpers
353
Armin Ronachere2244882008-05-19 09:25:57 +0200354 def fail(self, msg, lineno):
355 """Fail with a `TemplateAssertionError`."""
356 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
357
Armin Ronachere791c2a2008-04-07 18:39:54 +0200358 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200359 """Get a new unique identifier."""
360 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200361 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200362
Armin Ronachered1e0d42008-05-18 20:25:28 +0200363 def buffer(self, frame):
364 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200365 frame.buffer = self.temporary_identifier()
366 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200367
368 def return_buffer_contents(self, frame):
369 """Return the buffer contents of the frame."""
370 if self.environment.autoescape:
371 self.writeline('return Markup(concat(%s))' % frame.buffer)
372 else:
373 self.writeline('return concat(%s)' % frame.buffer)
374
Armin Ronachere791c2a2008-04-07 18:39:54 +0200375 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200376 """Indent by one."""
377 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200378
Armin Ronacher8efc5222008-04-08 14:47:40 +0200379 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200380 """Outdent by step."""
381 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200382
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200383 def start_write(self, frame, node=None):
384 """Yield or write into the frame buffer."""
385 if frame.buffer is None:
386 self.writeline('yield ', node)
387 else:
388 self.writeline('%s.append(' % frame.buffer, node)
389
390 def end_write(self, frame):
391 """End the writing process started by `start_write`."""
392 if frame.buffer is not None:
393 self.write(')')
394
395 def simple_write(self, s, frame, node=None):
396 """Simple shortcut for start_write + write + end_write."""
397 self.start_write(frame, node)
398 self.write(s)
399 self.end_write(frame)
400
Armin Ronacherc9705c22008-04-27 21:28:03 +0200401 def blockvisit(self, nodes, frame, force_generator=True):
402 """Visit a list of nodes as block in a frame. If the current frame
403 is no buffer a dummy ``if 0: yield None`` is written automatically
404 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200405 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200406 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200407 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200408 try:
409 for node in nodes:
410 self.visit(node, frame)
411 except CompilerExit:
412 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200413
414 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200415 """Write a string into the output stream."""
416 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200417 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200418 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200419 self.code_lineno += self._new_lines
420 if self._write_debug_info is not None:
421 self.debug_info.append((self._write_debug_info,
422 self.code_lineno))
423 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200424 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200425 self.stream.write(' ' * self._indentation)
426 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200427 self.stream.write(x)
428
429 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200430 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200431 self.newline(node, extra)
432 self.write(x)
433
434 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200435 """Add one or more newlines before the next write."""
436 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200437 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200438 self._write_debug_info = node.lineno
439 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200440
Armin Ronacherfd310492008-05-25 00:16:51 +0200441 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200442 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200443 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200444 arguments may not include python keywords otherwise a syntax
445 error could occour. The extra keyword arguments should be given
446 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200447 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200448 # if any of the given keyword arguments is a python keyword
449 # we have to make sure that no invalid call is created.
450 kwarg_workaround = False
451 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
452 if iskeyword(kwarg):
453 kwarg_workaround = True
454 break
455
Armin Ronacher8efc5222008-04-08 14:47:40 +0200456 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200457 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200458 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200459
460 if not kwarg_workaround:
461 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200462 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200463 self.visit(kwarg, frame)
464 if extra_kwargs is not None:
465 for key, value in extra_kwargs.iteritems():
Armin Ronacherfd310492008-05-25 00:16:51 +0200466 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200467 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200468 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200469 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200470
471 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200472 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200473 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200474 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200475 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200476 for kwarg in node.kwargs:
477 self.write('%r: ' % kwarg.key)
478 self.visit(kwarg.value, frame)
479 self.write(', ')
480 if extra_kwargs is not None:
481 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200482 self.write('%r: %s, ' % (key, value))
483 if node.dyn_kwargs is not None:
484 self.write('}, **')
485 self.visit(node.dyn_kwargs, frame)
486 self.write(')')
487 else:
488 self.write('}')
489
490 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200491 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200492 self.visit(node.dyn_kwargs, frame)
493
Armin Ronacherc9705c22008-04-27 21:28:03 +0200494 def pull_locals(self, frame):
495 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200496 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200497 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200498
499 def pull_dependencies(self, nodes):
500 """Pull all the dependencies."""
501 visitor = DependencyFinderVisitor()
502 for node in nodes:
503 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200504 for dependency in 'filters', 'tests':
505 mapping = getattr(self, dependency)
506 for name in getattr(visitor, dependency):
507 if name not in mapping:
508 mapping[name] = self.temporary_identifier()
509 self.writeline('%s = environment.%s[%r]' %
510 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200511
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200512 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200513 """This function returns all the shadowed variables in a dict
514 in the form name: alias and will write the required assignments
515 into the current scope. No indentation takes place.
516 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200517 aliases = {}
518 for name in frame.identifiers.find_shadowed():
519 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200520 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200521 return aliases
522
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200523 def restore_shadowed(self, aliases):
524 """Restore all aliases."""
525 for name, alias in aliases.iteritems():
526 self.writeline('l_%s = %s' % (name, alias))
527
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200528 def function_scoping(self, node, frame, children=None,
529 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200530 """In Jinja a few statements require the help of anonymous
531 functions. Those are currently macros and call blocks and in
532 the future also recursive loops. As there is currently
533 technical limitation that doesn't allow reading and writing a
534 variable in a scope where the initial value is coming from an
535 outer scope, this function tries to fall back with a common
536 error message. Additionally the frame passed is modified so
537 that the argumetns are collected and callers are looked up.
538
539 This will return the modified frame.
540 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200541 # we have to iterate twice over it, make sure that works
542 if children is None:
543 children = node.iter_child_nodes()
544 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200545 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200546 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200547
548 # variables that are undeclared (accessed before declaration) and
549 # declared locally *and* part of an outside scope raise a template
550 # assertion error. Reason: we can't generate reasonable code from
551 # it without aliasing all the variables. XXX: alias them ^^
552 overriden_closure_vars = (
553 func_frame.identifiers.undeclared &
554 func_frame.identifiers.declared &
555 (func_frame.identifiers.declared_locally |
556 func_frame.identifiers.declared_parameter)
557 )
558 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200559 self.fail('It\'s not possible to set and access variables '
560 'derived from an outer scope! (affects: %s' %
561 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200562
563 # remove variables from a closure from the frame's undeclared
564 # identifiers.
565 func_frame.identifiers.undeclared -= (
566 func_frame.identifiers.undeclared &
567 func_frame.identifiers.declared
568 )
569
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200570 # no special variables for this scope, abort early
571 if not find_special:
572 return func_frame
573
Armin Ronacher963f97d2008-04-25 11:44:59 +0200574 func_frame.accesses_kwargs = False
575 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200576 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200577 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200578
Armin Ronacherc9705c22008-04-27 21:28:03 +0200579 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
580
581 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200582 func_frame.accesses_caller = True
583 func_frame.identifiers.add_special('caller')
584 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200585 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200586 func_frame.accesses_kwargs = True
587 func_frame.identifiers.add_special('kwargs')
588 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200589 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200590 func_frame.accesses_varargs = True
591 func_frame.identifiers.add_special('varargs')
592 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200593 return func_frame
594
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200595 def macro_body(self, node, frame, children=None):
596 """Dump the function def of a macro or call block."""
597 frame = self.function_scoping(node, frame, children)
598 args = frame.arguments
599 self.writeline('def macro(%s):' % ', '.join(args), node)
600 self.indent()
601 self.buffer(frame)
602 self.pull_locals(frame)
603 self.blockvisit(node.body, frame)
604 self.return_buffer_contents(frame)
605 self.outdent()
606 return frame
607
608 def macro_def(self, node, frame):
609 """Dump the macro definition for the def created by macro_body."""
610 arg_tuple = ', '.join(repr(x.name) for x in node.args)
611 name = getattr(node, 'name', None)
612 if len(node.args) == 1:
613 arg_tuple += ','
614 self.write('Macro(environment, macro, %r, (%s), (' %
615 (name, arg_tuple))
616 for arg in node.defaults:
617 self.visit(arg, frame)
618 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200619 self.write('), %r, %r, %r)' % (
620 bool(frame.accesses_kwargs),
621 bool(frame.accesses_varargs),
622 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200623 ))
624
Armin Ronacher547d0b62008-07-04 16:35:10 +0200625 def position(self, node):
626 """Return a human readable position for the node."""
627 rv = 'line %d' % node.lineno
628 if self.name is not None:
629 rv += ' in' + repr(self.name)
630 return rv
631
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200632 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200633
634 def visit_Template(self, node, frame=None):
635 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200636 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200637 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200638 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8edbe492008-04-10 20:43:43 +0200639
Armin Ronacher75cfb862008-04-11 13:47:22 +0200640 # do we have an extends tag at all? If not, we can save some
641 # overhead by just not processing any inheritance code.
642 have_extends = node.find(nodes.Extends) is not None
643
Armin Ronacher8edbe492008-04-10 20:43:43 +0200644 # find all blocks
645 for block in node.find_all(nodes.Block):
646 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200647 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200648 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200649
Armin Ronacher023b5e92008-05-08 11:03:10 +0200650 # find all imports and import them
651 for import_ in node.find_all(nodes.ImportedName):
652 if import_.importname not in self.import_aliases:
653 imp = import_.importname
654 self.import_aliases[imp] = alias = self.temporary_identifier()
655 if '.' in imp:
656 module, obj = imp.rsplit('.', 1)
657 self.writeline('from %s import %s as %s' %
658 (module, obj, alias))
659 else:
660 self.writeline('import %s as %s' % (imp, alias))
661
662 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200663 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200664
Armin Ronacher8efc5222008-04-08 14:47:40 +0200665 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200666 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200667
668 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200669 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200670 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200671 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200672 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200673 if have_extends:
674 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200675 if 'self' in find_undeclared(node.body, ('self',)):
676 frame.identifiers.add_special('self')
677 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200678 self.pull_locals(frame)
679 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200680 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200681 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200682
Armin Ronacher8efc5222008-04-08 14:47:40 +0200683 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200684 if have_extends:
685 if not self.has_known_extends:
686 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200687 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200688 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200689 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200690 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200691 self.indent()
692 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200693 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200694
695 # at this point we now have the blocks collected and can visit them too.
696 for name, block in self.blocks.iteritems():
697 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200698 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200699 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200700 self.writeline('def block_%s(context, environment=environment):'
701 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200702 self.indent()
703 undeclared = find_undeclared(block.body, ('self', 'super'))
704 if 'self' in undeclared:
705 block_frame.identifiers.add_special('self')
706 self.writeline('l_self = TemplateReference(context)')
707 if 'super' in undeclared:
708 block_frame.identifiers.add_special('super')
709 self.writeline('l_super = context.super(%r, '
710 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200711 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200712 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200713 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200714 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200715
Armin Ronacher75cfb862008-04-11 13:47:22 +0200716 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200717 for x in self.blocks),
718 extra=1)
719
720 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200721 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
722 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200723
Armin Ronachere791c2a2008-04-07 18:39:54 +0200724 def visit_Block(self, node, frame):
725 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200726 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200727 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200728 # if we know that we are a child template, there is no need to
729 # check if we are one
730 if self.has_known_extends:
731 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200732 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200733 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200734 self.indent()
735 level += 1
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200736 self.writeline('for event in context.blocks[%r][0](context):' %
Armin Ronacherc9705c22008-04-27 21:28:03 +0200737 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200738 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200739 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200740 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200741
742 def visit_Extends(self, node, frame):
743 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200744 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200745 self.fail('cannot use extend from a non top-level scope',
746 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200747
Armin Ronacher7fb38972008-04-11 13:54:28 +0200748 # if the number of extends statements in general is zero so
749 # far, we don't have to add a check if something extended
750 # the template before this one.
751 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200752
Armin Ronacher7fb38972008-04-11 13:54:28 +0200753 # if we have a known extends we just add a template runtime
754 # error into the generated code. We could catch that at compile
755 # time too, but i welcome it not to confuse users by throwing the
756 # same error at different times just "because we can".
757 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200758 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200759 self.indent()
760 self.writeline('raise TemplateRuntimeError(%r)' %
761 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200762
Armin Ronacher7fb38972008-04-11 13:54:28 +0200763 # if we have a known extends already we don't need that code here
764 # as we know that the template execution will end here.
765 if self.has_known_extends:
766 raise CompilerExit()
767 self.outdent()
768
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200769 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200770 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200771 self.write(', %r)' % self.name)
772 self.writeline('for name, parent_block in parent_template.'
773 'blocks.iteritems():')
774 self.indent()
775 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200776 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200777 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200778
779 # if this extends statement was in the root level we can take
780 # advantage of that information and simplify the generated code
781 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200782 if frame.rootlevel:
783 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200784
Armin Ronacher7fb38972008-04-11 13:54:28 +0200785 # and now we have one more
786 self.extends_so_far += 1
787
Armin Ronacherf059ec12008-04-11 22:21:00 +0200788 def visit_Include(self, node, frame):
789 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200790 if node.with_context:
791 self.writeline('template = environment.get_template(', node)
792 self.visit(node.template, frame)
793 self.write(', %r)' % self.name)
Armin Ronacher5411ce72008-05-25 11:36:22 +0200794 self.writeline('for event in template.root_render_func('
Armin Ronacherea847c52008-05-02 20:04:32 +0200795 'template.new_context(context.parent, True)):')
796 else:
797 self.writeline('for event in environment.get_template(', node)
798 self.visit(node.template, frame)
Armin Ronacher771c7502008-05-18 23:14:14 +0200799 self.write(', %r).module._body_stream:' %
Armin Ronacherea847c52008-05-02 20:04:32 +0200800 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200801 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200802 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200803 self.outdent()
804
Armin Ronacher0611e492008-04-25 23:44:14 +0200805 def visit_Import(self, node, frame):
806 """Visit regular imports."""
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200807 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200808 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200809 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200810 self.write('environment.get_template(')
811 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200812 self.write(', %r).' % self.name)
813 if node.with_context:
814 self.write('make_module(context.parent, True)')
815 else:
816 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200817 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200818 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200819
820 def visit_FromImport(self, node, frame):
821 """Visit named imports."""
822 self.newline(node)
823 self.write('included_template = environment.get_template(')
824 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200825 self.write(', %r).' % self.name)
826 if node.with_context:
827 self.write('make_module(context.parent, True)')
828 else:
829 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200830
831 var_names = []
832 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200833 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200834 if isinstance(name, tuple):
835 name, alias = name
836 else:
837 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200838 self.writeline('l_%s = getattr(included_template, '
839 '%r, missing)' % (alias, name))
840 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200841 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200842 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +0200843 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200844 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +0200845 (alias, 'the template %%r (imported on %s) does '
846 'not export the requested name %s' % (
847 self.position(node),
848 repr(name)
849 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +0200850 self.outdent()
851 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +0200852 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +0200853 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +0200854 discarded_names.append(alias)
855
856 if var_names:
857 if len(var_names) == 1:
858 name = var_names[0]
859 self.writeline('context.vars[%r] = l_%s' % (name, name))
860 else:
861 self.writeline('context.vars.update({%s})' % ', '.join(
862 '%r: l_%s' % (name, name) for name in var_names
863 ))
864 if discarded_names:
865 if len(discarded_names) == 1:
866 self.writeline('context.exported_vars.discard(%r)' %
867 discarded_names[0])
868 else:
869 self.writeline('context.exported_vars.difference_'
870 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200871
Armin Ronachere791c2a2008-04-07 18:39:54 +0200872 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200873 # when calculating the nodes for the inner frame we have to exclude
874 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200875 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200876 if node.recursive:
877 loop_frame = self.function_scoping(node, frame, children,
878 find_special=False)
879 else:
880 loop_frame = frame.inner()
881 loop_frame.inspect(children)
882
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200883 # try to figure out if we have an extended loop. An extended loop
884 # is necessary if the loop is in recursive mode if the special loop
885 # variable is accessed in the body.
886 extended_loop = node.recursive or 'loop' in \
887 find_undeclared(node.iter_child_nodes(
888 only=('body',)), ('loop',))
889
890 # make sure the loop variable is a special one and raise a template
891 # assertion error if a loop tries to write to loop
892 loop_frame.identifiers.add_special('loop')
893 for name in node.find_all(nodes.Name):
894 if name.ctx == 'store' and name.name == 'loop':
895 self.fail('Can\'t assign to special loop variable '
896 'in for-loop target', name.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200897
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200898 # if we don't have an recursive loop we have to find the shadowed
899 # variables at that point
900 if not node.recursive:
901 aliases = self.collect_shadowed(loop_frame)
902
903 # otherwise we set up a buffer and add a function def
904 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200905 self.writeline('def loop(reciter, loop_render_func):', node)
906 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +0200907 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200908 aliases = {}
909
Armin Ronacherc9705c22008-04-27 21:28:03 +0200910 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200911 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200912 iteration_indicator = self.temporary_identifier()
913 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200914
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200915 # Create a fake parent loop if the else or test section of a
916 # loop is accessing the special loop variable and no parent loop
917 # exists.
918 if 'loop' not in aliases and 'loop' in find_undeclared(
919 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
920 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +0200921 ("'loop' is undefined. the filter section of a loop as well "
922 "as the else block doesn't have access to the special 'loop'"
923 " variable of the current loop. Because there is no parent "
924 "loop it's undefined. Happened in loop on %s" %
925 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200926
927 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200928 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200929 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200930
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200931 # if we have an extened loop and a node test, we filter in the
932 # "outer frame".
933 if extended_loop and node.test is not None:
934 self.write('(')
935 self.visit(node.target, loop_frame)
936 self.write(' for ')
937 self.visit(node.target, loop_frame)
938 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200939 if node.recursive:
940 self.write('reciter')
941 else:
942 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200943 self.write(' if (')
944 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200945 self.visit(node.test, test_frame)
946 self.write('))')
947
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200948 elif node.recursive:
949 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200950 else:
951 self.visit(node.iter, loop_frame)
952
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200953 if node.recursive:
954 self.write(', recurse=loop_render_func):')
955 else:
956 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200957
958 # tests in not extended loops become a continue
959 if not extended_loop and node.test is not None:
960 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200961 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200962 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200963 self.write(':')
964 self.indent()
965 self.writeline('continue')
966 self.outdent(2)
967
Armin Ronacherc9705c22008-04-27 21:28:03 +0200968 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200969 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200970 if node.else_:
971 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200972 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200973
974 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200975 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200976 self.indent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200977 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200978 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200979
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200980 # reset the aliases if there are any.
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200981 self.restore_shadowed(aliases)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200982
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200983 # if the node was recursive we have to return the buffer contents
984 # and start the iteration code
985 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200986 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200987 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200988 self.start_write(frame, node)
989 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200990 self.visit(node.iter, frame)
991 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200992 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200993
Armin Ronachere791c2a2008-04-07 18:39:54 +0200994 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200995 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200996 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200997 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200998 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200999 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001000 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001001 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001002 if node.else_:
1003 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001004 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001005 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001006 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001007
Armin Ronacher8efc5222008-04-08 14:47:40 +02001008 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001009 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001010 self.newline()
1011 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001012 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001013 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001014 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001015 self.write('l_%s = ' % node.name)
1016 self.macro_def(node, macro_frame)
Armin Ronacher71082072008-04-12 14:19:36 +02001017
1018 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001019 children = node.iter_child_nodes(exclude=('call',))
1020 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001021 self.writeline('caller = ')
1022 self.macro_def(node, call_frame)
1023 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001024 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001025 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001026
1027 def visit_FilterBlock(self, node, frame):
1028 filter_frame = frame.inner()
1029 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001030 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001031 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001032 self.buffer(filter_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001033 self.blockvisit(node.body, filter_frame, force_generator=False)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001034 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001035 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001036 self.end_write(frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001037 self.restore_shadowed(aliases)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001038
Armin Ronachere791c2a2008-04-07 18:39:54 +02001039 def visit_ExprStmt(self, node, frame):
1040 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001041 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001042
1043 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001044 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +02001045 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001046 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001047
Armin Ronacher75cfb862008-04-11 13:47:22 +02001048 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001049
Armin Ronacher7fb38972008-04-11 13:54:28 +02001050 # if we are in the toplevel scope and there was already an extends
1051 # statement we have to add a check that disables our yield(s) here
1052 # so that they don't appear in the output.
1053 outdent_later = False
1054 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001055 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001056 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001057 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001058
Armin Ronachere791c2a2008-04-07 18:39:54 +02001059 # try to evaluate as many chunks as possible into a static
1060 # string at compile time.
1061 body = []
1062 for child in node.nodes:
1063 try:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001064 const = child.as_const()
1065 except nodes.Impossible:
1066 body.append(child)
1067 continue
1068 try:
1069 if self.environment.autoescape:
1070 if hasattr(const, '__html__'):
1071 const = const.__html__()
1072 else:
1073 const = escape(const)
1074 const = unicode(const)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001075 except:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001076 # if something goes wrong here we evaluate the node
1077 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001078 body.append(child)
1079 continue
1080 if body and isinstance(body[-1], list):
1081 body[-1].append(const)
1082 else:
1083 body.append([const])
1084
Armin Ronachered1e0d42008-05-18 20:25:28 +02001085 # if we have less than 3 nodes or a buffer we yield or extend/append
1086 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001087 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001088 # for one item we append, for more we extend
1089 if len(body) == 1:
1090 self.writeline('%s.append(' % frame.buffer)
1091 else:
1092 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001093 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001094 for item in body:
1095 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001096 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001097 if frame.buffer is None:
1098 self.writeline('yield ' + val)
1099 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001100 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001101 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001102 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001103 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001104 else:
1105 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001106 close = 1
1107 if self.environment.autoescape:
1108 self.write('escape(')
1109 else:
1110 self.write('unicode(')
1111 if self.environment.finalize is not None:
1112 self.write('environment.finalize(')
1113 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001114 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001115 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001116 if frame.buffer is not None:
1117 self.write(', ')
1118 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001119 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001120 self.outdent()
1121 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001122
1123 # otherwise we create a format string as this is faster in that case
1124 else:
1125 format = []
1126 arguments = []
1127 for item in body:
1128 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001129 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001130 else:
1131 format.append('%s')
1132 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001133 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001134 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001135 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001136 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001137 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001138 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001139 close = 0
1140 if self.environment.autoescape:
1141 self.write('escape(')
1142 close += 1
1143 if self.environment.finalize is not None:
1144 self.write('environment.finalize(')
1145 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001146 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001147 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001148 self.outdent()
1149 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001150
Armin Ronacher7fb38972008-04-11 13:54:28 +02001151 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001152 self.outdent()
1153
Armin Ronacher8efc5222008-04-08 14:47:40 +02001154 def visit_Assign(self, node, frame):
1155 self.newline(node)
1156 # toplevel assignments however go into the local namespace and
1157 # the current template's context. We create a copy of the frame
1158 # here and add a set so that the Name visitor can add the assigned
1159 # names here.
1160 if frame.toplevel:
1161 assignment_frame = frame.copy()
1162 assignment_frame.assigned_names = set()
1163 else:
1164 assignment_frame = frame
1165 self.visit(node.target, assignment_frame)
1166 self.write(' = ')
1167 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001168
1169 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001170 if frame.toplevel:
Armin Ronacher69e12db2008-05-12 09:00:03 +02001171 public_names = [x for x in assignment_frame.assigned_names
Armin Ronacher903d1682008-05-23 00:51:58 +02001172 if not x.startswith('_')]
Armin Ronacher69e12db2008-05-12 09:00:03 +02001173 if len(assignment_frame.assigned_names) == 1:
1174 name = iter(assignment_frame.assigned_names).next()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001175 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001176 else:
1177 self.writeline('context.vars.update({')
1178 for idx, name in enumerate(assignment_frame.assigned_names):
1179 if idx:
1180 self.write(', ')
1181 self.write('%r: l_%s' % (name, name))
1182 self.write('})')
1183 if public_names:
1184 if len(public_names) == 1:
1185 self.writeline('context.exported_vars.add(%r)' %
1186 public_names[0])
1187 else:
1188 self.writeline('context.exported_vars.update((%s))' %
1189 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001190
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001191 # -- Expression Visitors
1192
Armin Ronachere791c2a2008-04-07 18:39:54 +02001193 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001194 if node.ctx == 'store' and frame.toplevel:
1195 frame.assigned_names.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001196 self.write('l_' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001197
1198 def visit_Const(self, node, frame):
1199 val = node.value
1200 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001201 self.write(str(val))
1202 else:
1203 self.write(repr(val))
1204
Armin Ronacher5411ce72008-05-25 11:36:22 +02001205 def visit_TemplateData(self, node, frame):
1206 self.write(repr(node.as_const()))
1207
Armin Ronacher8efc5222008-04-08 14:47:40 +02001208 def visit_Tuple(self, node, frame):
1209 self.write('(')
1210 idx = -1
1211 for idx, item in enumerate(node.items):
1212 if idx:
1213 self.write(', ')
1214 self.visit(item, frame)
1215 self.write(idx == 0 and ',)' or ')')
1216
Armin Ronacher8edbe492008-04-10 20:43:43 +02001217 def visit_List(self, node, frame):
1218 self.write('[')
1219 for idx, item in enumerate(node.items):
1220 if idx:
1221 self.write(', ')
1222 self.visit(item, frame)
1223 self.write(']')
1224
1225 def visit_Dict(self, node, frame):
1226 self.write('{')
1227 for idx, item in enumerate(node.items):
1228 if idx:
1229 self.write(', ')
1230 self.visit(item.key, frame)
1231 self.write(': ')
1232 self.visit(item.value, frame)
1233 self.write('}')
1234
Armin Ronachere791c2a2008-04-07 18:39:54 +02001235 def binop(operator):
1236 def visitor(self, node, frame):
1237 self.write('(')
1238 self.visit(node.left, frame)
1239 self.write(' %s ' % operator)
1240 self.visit(node.right, frame)
1241 self.write(')')
1242 return visitor
1243
1244 def uaop(operator):
1245 def visitor(self, node, frame):
1246 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001247 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001248 self.write(')')
1249 return visitor
1250
1251 visit_Add = binop('+')
1252 visit_Sub = binop('-')
1253 visit_Mul = binop('*')
1254 visit_Div = binop('/')
1255 visit_FloorDiv = binop('//')
1256 visit_Pow = binop('**')
1257 visit_Mod = binop('%')
1258 visit_And = binop('and')
1259 visit_Or = binop('or')
1260 visit_Pos = uaop('+')
1261 visit_Neg = uaop('-')
1262 visit_Not = uaop('not ')
1263 del binop, uaop
1264
Armin Ronacherd1342312008-04-28 12:20:12 +02001265 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001266 self.write('%s((' % (self.environment.autoescape and
1267 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001268 for arg in node.nodes:
1269 self.visit(arg, frame)
1270 self.write(', ')
1271 self.write('))')
1272
Armin Ronachere791c2a2008-04-07 18:39:54 +02001273 def visit_Compare(self, node, frame):
1274 self.visit(node.expr, frame)
1275 for op in node.ops:
1276 self.visit(op, frame)
1277
1278 def visit_Operand(self, node, frame):
1279 self.write(' %s ' % operators[node.op])
1280 self.visit(node.expr, frame)
1281
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001282 def visit_Getattr(self, node, frame):
1283 self.write('environment.getattr(')
1284 self.visit(node.node, frame)
1285 self.write(', %r)' % node.attr)
1286
1287 def visit_Getitem(self, node, frame):
Armin Ronacherb9388772008-06-25 20:43:18 +02001288 # slices or integer subscriptions bypass the getitem
Armin Ronacher08a6a3b2008-05-13 15:35:47 +02001289 # method if we can determine that at compile time.
1290 if isinstance(node.arg, nodes.Slice) or \
1291 (isinstance(node.arg, nodes.Const) and
1292 isinstance(node.arg.value, (int, long))):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001293 self.visit(node.node, frame)
1294 self.write('[')
1295 self.visit(node.arg, frame)
1296 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001297 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001298 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001299 self.visit(node.node, frame)
1300 self.write(', ')
1301 self.visit(node.arg, frame)
1302 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001303
1304 def visit_Slice(self, node, frame):
1305 if node.start is not None:
1306 self.visit(node.start, frame)
1307 self.write(':')
1308 if node.stop is not None:
1309 self.visit(node.stop, frame)
1310 if node.step is not None:
1311 self.write(':')
1312 self.visit(node.step, frame)
1313
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001314 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001315 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001316 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001317 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001318 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001319 if getattr(func, 'contextfilter', False):
1320 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001321 elif getattr(func, 'environmentfilter', False):
1322 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001323
1324 # if the filter node is None we are inside a filter block
1325 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001326 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001327 self.visit(node.node, frame)
Armin Ronacher3da90312008-05-23 16:37:28 +02001328 elif self.environment.autoescape:
1329 self.write('Markup(concat(%s))' % frame.buffer)
1330 else:
1331 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001332 self.signature(node, frame)
1333 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001334
1335 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001336 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001337 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001338 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001339 self.visit(node.node, frame)
1340 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001341 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001342
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001343 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001344 def write_expr2():
1345 if node.expr2 is not None:
1346 return self.visit(node.expr2, frame)
1347 self.write('environment.undefined(%r)' % ('the inline if-'
1348 'expression on %s evaluated to false and '
1349 'no else section was defined.' % self.position(node)))
1350
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001351 if not have_condexpr:
1352 self.write('((')
1353 self.visit(node.test, frame)
1354 self.write(') and (')
1355 self.visit(node.expr1, frame)
1356 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001357 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001358 self.write(',))[0]')
1359 else:
1360 self.write('(')
1361 self.visit(node.expr1, frame)
1362 self.write(' if ')
1363 self.visit(node.test, frame)
1364 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001365 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001366 self.write(')')
1367
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001368 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001369 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001370 self.write('environment.call(context, ')
1371 else:
1372 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001373 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001374 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001375 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001376 self.write(')')
1377
1378 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001379 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001380 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001381
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001382 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001383
1384 def visit_MarkSafe(self, node, frame):
1385 self.write('Markup(')
1386 self.visit(node.expr, frame)
1387 self.write(')')
1388
1389 def visit_EnvironmentAttribute(self, node, frame):
1390 self.write('environment.' + node.name)
1391
1392 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001393 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001394
1395 def visit_ImportedName(self, node, frame):
1396 self.write(self.import_aliases[node.importname])
1397
1398 def visit_InternalName(self, node, frame):
1399 self.write(node.name)
1400
Armin Ronacher6df604e2008-05-23 22:18:38 +02001401 def visit_ContextReference(self, node, frame):
1402 self.write('context')
1403
Armin Ronachered1e0d42008-05-18 20:25:28 +02001404 def visit_Continue(self, node, frame):
1405 self.writeline('continue', node)
1406
1407 def visit_Break(self, node, frame):
1408 self.writeline('break', node)