blob: ad7857d07e3076928f507dbfee06ce5b0b22eb86 [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.
Armin Ronacherd7764372008-07-15 00:11:14 +02009 :license: BSD.
Armin Ronachere791c2a2008-04-07 18:39:54 +020010"""
Armin Ronachere791c2a2008-04-07 18:39:54 +020011from cStringIO import StringIO
Armin Ronacherd1ff8582008-05-11 00:30:43 +020012from itertools import chain
Armin Ronachere791c2a2008-04-07 18:39:54 +020013from jinja2 import nodes
14from jinja2.visitor import NodeVisitor, NodeTransformer
15from jinja2.exceptions import TemplateAssertionError
Armin Ronacher9a0078d2008-08-13 18:24:17 +020016from jinja2.utils import Markup, concat, escape, is_python_keyword
Armin Ronachere791c2a2008-04-07 18:39:54 +020017
18
19operators = {
20 'eq': '==',
21 'ne': '!=',
22 'gt': '>',
23 'gteq': '>=',
24 'lt': '<',
25 'lteq': '<=',
26 'in': 'in',
27 'notin': 'not in'
28}
29
Armin Ronacher3d8b7842008-04-13 13:16:50 +020030try:
31 exec '(0 if 0 else 0)'
32except SyntaxError:
33 have_condexpr = False
34else:
35 have_condexpr = True
36
37
Armin Ronacher8e8d0712008-04-16 23:10:49 +020038def generate(node, environment, name, filename, stream=None):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020039 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020040 if not isinstance(node, nodes.Template):
41 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher8e8d0712008-04-16 23:10:49 +020042 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020043 generator.visit(node)
44 if stream is None:
45 return generator.stream.getvalue()
46
47
Armin Ronacher4dfc9752008-04-09 15:03:29 +020048def has_safe_repr(value):
49 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020050 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020051 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020052 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher32a910f2008-04-26 23:21:03 +020053 xrange, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020054 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020055 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020056 for item in value:
57 if not has_safe_repr(item):
58 return False
59 return True
60 elif isinstance(value, dict):
61 for key, value in value.iteritems():
62 if not has_safe_repr(key):
63 return False
64 if not has_safe_repr(value):
65 return False
66 return True
67 return False
68
69
Armin Ronacherc9705c22008-04-27 21:28:03 +020070def find_undeclared(nodes, names):
71 """Check if the names passed are accessed undeclared. The return value
72 is a set of all the undeclared names from the sequence of names found.
73 """
74 visitor = UndeclaredNameVisitor(names)
75 try:
76 for node in nodes:
77 visitor.visit(node)
78 except VisitorExit:
79 pass
80 return visitor.undeclared
81
82
Armin Ronachere791c2a2008-04-07 18:39:54 +020083class Identifiers(object):
84 """Tracks the status of identifiers in frames."""
85
86 def __init__(self):
87 # variables that are known to be declared (probably from outer
88 # frames or because they are special for the frame)
89 self.declared = set()
90
Armin Ronacher10f3ba22008-04-18 11:30:37 +020091 # undeclared variables from outer scopes
92 self.outer_undeclared = set()
93
Armin Ronachere791c2a2008-04-07 18:39:54 +020094 # names that are accessed without being explicitly declared by
95 # this one or any of the outer scopes. Names can appear both in
96 # declared and undeclared.
97 self.undeclared = set()
98
99 # names that are declared locally
100 self.declared_locally = set()
101
102 # names that are declared by parameters
103 self.declared_parameter = set()
104
105 def add_special(self, name):
106 """Register a special name like `loop`."""
107 self.undeclared.discard(name)
108 self.declared.add(name)
109
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200110 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200111 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200112 if name in self.declared_locally or name in self.declared_parameter:
113 return True
114 if local_only:
115 return False
116 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200117
Armin Ronacherff53c782008-08-13 18:55:50 +0200118 def find_shadowed(self, extra=()):
119 """Find all the shadowed names. extra is an iterable of variables
120 that may be defined with `add_special` which may occour scoped.
121 """
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200122 return (self.declared | self.outer_undeclared) & \
Armin Ronacherff53c782008-08-13 18:55:50 +0200123 (self.declared_locally | self.declared_parameter) | \
124 set(x for x in extra if self.is_declared(x))
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."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200168 rv = object.__new__(self.__class__)
169 rv.__dict__.update(self.__dict__)
170 rv.identifiers = object.__new__(self.identifiers.__class__)
171 rv.identifiers.__dict__.update(self.identifiers.__dict__)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200172 return rv
173
Armin Ronacherc9705c22008-04-27 21:28:03 +0200174 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200175 """Walk the node and check for identifiers. If the scope is hard (eg:
176 enforce on a python level) overrides from outer scopes are tracked
177 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200178 """
179 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200180 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200181 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200182
183 def inner(self):
184 """Return an inner frame."""
185 return Frame(self)
186
Armin Ronacher75cfb862008-04-11 13:47:22 +0200187 def soft(self):
188 """Return a soft frame. A soft frame may not be modified as
189 standalone thing as it shares the resources with the frame it
190 was created of, but it's not a rootlevel frame any longer.
191 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200192 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200193 rv.rootlevel = False
194 return rv
195
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200196 __copy__ = copy
197
Armin Ronachere791c2a2008-04-07 18:39:54 +0200198
Armin Ronacherc9705c22008-04-27 21:28:03 +0200199class VisitorExit(RuntimeError):
200 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
201
202
203class DependencyFinderVisitor(NodeVisitor):
204 """A visitor that collects filter and test calls."""
205
206 def __init__(self):
207 self.filters = set()
208 self.tests = set()
209
210 def visit_Filter(self, node):
211 self.generic_visit(node)
212 self.filters.add(node.name)
213
214 def visit_Test(self, node):
215 self.generic_visit(node)
216 self.tests.add(node.name)
217
218 def visit_Block(self, node):
219 """Stop visiting at blocks."""
220
221
222class UndeclaredNameVisitor(NodeVisitor):
223 """A visitor that checks if a name is accessed without being
224 declared. This is different from the frame visitor as it will
225 not stop at closure frames.
226 """
227
228 def __init__(self, names):
229 self.names = set(names)
230 self.undeclared = set()
231
232 def visit_Name(self, node):
233 if node.ctx == 'load' and node.name in self.names:
234 self.undeclared.add(node.name)
235 if self.undeclared == self.names:
236 raise VisitorExit()
237 else:
238 self.names.discard(node.name)
239
240 def visit_Block(self, node):
241 """Stop visiting a blocks."""
242
243
Armin Ronachere791c2a2008-04-07 18:39:54 +0200244class FrameIdentifierVisitor(NodeVisitor):
245 """A visitor for `Frame.inspect`."""
246
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200247 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200248 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200249 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200250
Armin Ronacherc9705c22008-04-27 21:28:03 +0200251 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200252 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200253 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200254 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200255 elif node.ctx == 'param':
256 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200257 elif node.ctx == 'load' and not \
258 self.identifiers.is_declared(node.name, self.hard_scope):
259 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200260
Armin Ronacherc9705c22008-04-27 21:28:03 +0200261 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200262 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200263
Armin Ronacherc9705c22008-04-27 21:28:03 +0200264 def visit_Import(self, node):
265 self.generic_visit(node)
266 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200267
Armin Ronacherc9705c22008-04-27 21:28:03 +0200268 def visit_FromImport(self, node):
269 self.generic_visit(node)
270 for name in node.names:
271 if isinstance(name, tuple):
272 self.identifiers.declared_locally.add(name[1])
273 else:
274 self.identifiers.declared_locally.add(name)
275
276 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200277 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200278 self.visit(node.node)
279 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200280
Armin Ronacherc9705c22008-04-27 21:28:03 +0200281 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200282 """Visiting stops at for blocks. However the block sequence
283 is visited as part of the outer scope.
284 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200285 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200286
Armin Ronacherc9705c22008-04-27 21:28:03 +0200287 def visit_CallBlock(self, node):
288 for child in node.iter_child_nodes(exclude=('body',)):
289 self.visit(child)
290
291 def visit_FilterBlock(self, node):
292 self.visit(node.filter)
293
294 def visit_Block(self, node):
295 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200296
297
Armin Ronacher75cfb862008-04-11 13:47:22 +0200298class CompilerExit(Exception):
299 """Raised if the compiler encountered a situation where it just
300 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200301 raises such an exception is not further processed.
302 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200303
304
Armin Ronachere791c2a2008-04-07 18:39:54 +0200305class CodeGenerator(NodeVisitor):
306
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200307 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200308 if stream is None:
309 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200310 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200311 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200312 self.filename = filename
313 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200314
Armin Ronacher023b5e92008-05-08 11:03:10 +0200315 # aliases for imports
316 self.import_aliases = {}
317
Armin Ronacherfed44b52008-04-13 19:42:53 +0200318 # a registry for all blocks. Because blocks are moved out
319 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200320 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200321
322 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200323 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200324
325 # some templates have a rootlevel extends. In this case we
326 # can safely assume that we're a child template and do some
327 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200328 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200329
Armin Ronacherba3757b2008-04-16 19:43:16 +0200330 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200331 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200332
Armin Ronacherb9e78752008-05-10 23:36:28 +0200333 # registry of all filters and tests (global, not block local)
334 self.tests = {}
335 self.filters = {}
336
Armin Ronacherba3757b2008-04-16 19:43:16 +0200337 # the debug information
338 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200339 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200340
Armin Ronacherfed44b52008-04-13 19:42:53 +0200341 # the number of new lines before the next write()
342 self._new_lines = 0
343
344 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200345 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200346
347 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200348 self._first_write = True
349
Armin Ronacherfed44b52008-04-13 19:42:53 +0200350 # used by the `temporary_identifier` method to get new
351 # unique, temporary identifier
352 self._last_identifier = 0
353
354 # the current indentation
355 self._indentation = 0
356
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200357 # -- Various compilation helpers
358
Armin Ronachere2244882008-05-19 09:25:57 +0200359 def fail(self, msg, lineno):
360 """Fail with a `TemplateAssertionError`."""
361 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
362
Armin Ronachere791c2a2008-04-07 18:39:54 +0200363 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200364 """Get a new unique identifier."""
365 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200366 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200367
Armin Ronachered1e0d42008-05-18 20:25:28 +0200368 def buffer(self, frame):
369 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200370 frame.buffer = self.temporary_identifier()
371 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200372
373 def return_buffer_contents(self, frame):
374 """Return the buffer contents of the frame."""
375 if self.environment.autoescape:
376 self.writeline('return Markup(concat(%s))' % frame.buffer)
377 else:
378 self.writeline('return concat(%s)' % frame.buffer)
379
Armin Ronachere791c2a2008-04-07 18:39:54 +0200380 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200381 """Indent by one."""
382 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200383
Armin Ronacher8efc5222008-04-08 14:47:40 +0200384 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200385 """Outdent by step."""
386 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200387
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200388 def start_write(self, frame, node=None):
389 """Yield or write into the frame buffer."""
390 if frame.buffer is None:
391 self.writeline('yield ', node)
392 else:
393 self.writeline('%s.append(' % frame.buffer, node)
394
395 def end_write(self, frame):
396 """End the writing process started by `start_write`."""
397 if frame.buffer is not None:
398 self.write(')')
399
400 def simple_write(self, s, frame, node=None):
401 """Simple shortcut for start_write + write + end_write."""
402 self.start_write(frame, node)
403 self.write(s)
404 self.end_write(frame)
405
Armin Ronacherc9705c22008-04-27 21:28:03 +0200406 def blockvisit(self, nodes, frame, force_generator=True):
407 """Visit a list of nodes as block in a frame. If the current frame
408 is no buffer a dummy ``if 0: yield None`` is written automatically
409 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200410 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200411 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200412 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200413 try:
414 for node in nodes:
415 self.visit(node, frame)
416 except CompilerExit:
417 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200418
419 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200420 """Write a string into the output stream."""
421 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200422 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200423 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200424 self.code_lineno += self._new_lines
425 if self._write_debug_info is not None:
426 self.debug_info.append((self._write_debug_info,
427 self.code_lineno))
428 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200429 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200430 self.stream.write(' ' * self._indentation)
431 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200432 self.stream.write(x)
433
434 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200435 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200436 self.newline(node, extra)
437 self.write(x)
438
439 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200440 """Add one or more newlines before the next write."""
441 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200442 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200443 self._write_debug_info = node.lineno
444 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200445
Armin Ronacherfd310492008-05-25 00:16:51 +0200446 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200447 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200448 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200449 arguments may not include python keywords otherwise a syntax
450 error could occour. The extra keyword arguments should be given
451 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200452 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200453 # if any of the given keyword arguments is a python keyword
454 # we have to make sure that no invalid call is created.
455 kwarg_workaround = False
456 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200457 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200458 kwarg_workaround = True
459 break
460
Armin Ronacher8efc5222008-04-08 14:47:40 +0200461 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200462 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200463 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200464
465 if not kwarg_workaround:
466 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200467 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200468 self.visit(kwarg, frame)
469 if extra_kwargs is not None:
470 for key, value in extra_kwargs.iteritems():
Armin Ronacherfd310492008-05-25 00:16:51 +0200471 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200472 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200473 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200474 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200475
476 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200477 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200478 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200479 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200480 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200481 for kwarg in node.kwargs:
482 self.write('%r: ' % kwarg.key)
483 self.visit(kwarg.value, frame)
484 self.write(', ')
485 if extra_kwargs is not None:
486 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200487 self.write('%r: %s, ' % (key, value))
488 if node.dyn_kwargs is not None:
489 self.write('}, **')
490 self.visit(node.dyn_kwargs, frame)
491 self.write(')')
492 else:
493 self.write('}')
494
495 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200496 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200497 self.visit(node.dyn_kwargs, frame)
498
Armin Ronacherc9705c22008-04-27 21:28:03 +0200499 def pull_locals(self, frame):
500 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200501 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200502 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200503
504 def pull_dependencies(self, nodes):
505 """Pull all the dependencies."""
506 visitor = DependencyFinderVisitor()
507 for node in nodes:
508 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200509 for dependency in 'filters', 'tests':
510 mapping = getattr(self, dependency)
511 for name in getattr(visitor, dependency):
512 if name not in mapping:
513 mapping[name] = self.temporary_identifier()
514 self.writeline('%s = environment.%s[%r]' %
515 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200516
Armin Ronacherff53c782008-08-13 18:55:50 +0200517 def collect_shadowed(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200518 """This function returns all the shadowed variables in a dict
519 in the form name: alias and will write the required assignments
520 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200521
522 `extra_vars` is passed to `Identifiers.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200523 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200524 aliases = {}
Armin Ronacherff53c782008-08-13 18:55:50 +0200525 for name in frame.identifiers.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200526 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200527 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200528 return aliases
529
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200530 def restore_shadowed(self, aliases):
531 """Restore all aliases."""
532 for name, alias in aliases.iteritems():
533 self.writeline('l_%s = %s' % (name, alias))
534
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200535 def function_scoping(self, node, frame, children=None,
536 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200537 """In Jinja a few statements require the help of anonymous
538 functions. Those are currently macros and call blocks and in
539 the future also recursive loops. As there is currently
540 technical limitation that doesn't allow reading and writing a
541 variable in a scope where the initial value is coming from an
542 outer scope, this function tries to fall back with a common
543 error message. Additionally the frame passed is modified so
544 that the argumetns are collected and callers are looked up.
545
546 This will return the modified frame.
547 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200548 # we have to iterate twice over it, make sure that works
549 if children is None:
550 children = node.iter_child_nodes()
551 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200552 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200553 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200554
555 # variables that are undeclared (accessed before declaration) and
556 # declared locally *and* part of an outside scope raise a template
557 # assertion error. Reason: we can't generate reasonable code from
558 # it without aliasing all the variables. XXX: alias them ^^
559 overriden_closure_vars = (
560 func_frame.identifiers.undeclared &
561 func_frame.identifiers.declared &
562 (func_frame.identifiers.declared_locally |
563 func_frame.identifiers.declared_parameter)
564 )
565 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200566 self.fail('It\'s not possible to set and access variables '
567 'derived from an outer scope! (affects: %s' %
568 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200569
570 # remove variables from a closure from the frame's undeclared
571 # identifiers.
572 func_frame.identifiers.undeclared -= (
573 func_frame.identifiers.undeclared &
574 func_frame.identifiers.declared
575 )
576
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200577 # no special variables for this scope, abort early
578 if not find_special:
579 return func_frame
580
Armin Ronacher963f97d2008-04-25 11:44:59 +0200581 func_frame.accesses_kwargs = False
582 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200583 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200584 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200585
Armin Ronacherc9705c22008-04-27 21:28:03 +0200586 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
587
588 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200589 func_frame.accesses_caller = True
590 func_frame.identifiers.add_special('caller')
591 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200592 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200593 func_frame.accesses_kwargs = True
594 func_frame.identifiers.add_special('kwargs')
595 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200596 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200597 func_frame.accesses_varargs = True
598 func_frame.identifiers.add_special('varargs')
599 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200600 return func_frame
601
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200602 def macro_body(self, node, frame, children=None):
603 """Dump the function def of a macro or call block."""
604 frame = self.function_scoping(node, frame, children)
605 args = frame.arguments
606 self.writeline('def macro(%s):' % ', '.join(args), node)
607 self.indent()
608 self.buffer(frame)
609 self.pull_locals(frame)
610 self.blockvisit(node.body, frame)
611 self.return_buffer_contents(frame)
612 self.outdent()
613 return frame
614
615 def macro_def(self, node, frame):
616 """Dump the macro definition for the def created by macro_body."""
617 arg_tuple = ', '.join(repr(x.name) for x in node.args)
618 name = getattr(node, 'name', None)
619 if len(node.args) == 1:
620 arg_tuple += ','
621 self.write('Macro(environment, macro, %r, (%s), (' %
622 (name, arg_tuple))
623 for arg in node.defaults:
624 self.visit(arg, frame)
625 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200626 self.write('), %r, %r, %r)' % (
627 bool(frame.accesses_kwargs),
628 bool(frame.accesses_varargs),
629 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200630 ))
631
Armin Ronacher547d0b62008-07-04 16:35:10 +0200632 def position(self, node):
633 """Return a human readable position for the node."""
634 rv = 'line %d' % node.lineno
635 if self.name is not None:
636 rv += ' in' + repr(self.name)
637 return rv
638
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200639 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200640
641 def visit_Template(self, node, frame=None):
642 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200643 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200644 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200645 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8edbe492008-04-10 20:43:43 +0200646
Armin Ronacher75cfb862008-04-11 13:47:22 +0200647 # do we have an extends tag at all? If not, we can save some
648 # overhead by just not processing any inheritance code.
649 have_extends = node.find(nodes.Extends) is not None
650
Armin Ronacher8edbe492008-04-10 20:43:43 +0200651 # find all blocks
652 for block in node.find_all(nodes.Block):
653 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200654 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200655 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200656
Armin Ronacher023b5e92008-05-08 11:03:10 +0200657 # find all imports and import them
658 for import_ in node.find_all(nodes.ImportedName):
659 if import_.importname not in self.import_aliases:
660 imp = import_.importname
661 self.import_aliases[imp] = alias = self.temporary_identifier()
662 if '.' in imp:
663 module, obj = imp.rsplit('.', 1)
664 self.writeline('from %s import %s as %s' %
665 (module, obj, alias))
666 else:
667 self.writeline('import %s as %s' % (imp, alias))
668
669 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200670 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200671
Armin Ronacher8efc5222008-04-08 14:47:40 +0200672 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200673 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200674
675 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200676 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200677 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200678 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200679 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200680 if have_extends:
681 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200682 if 'self' in find_undeclared(node.body, ('self',)):
683 frame.identifiers.add_special('self')
684 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200685 self.pull_locals(frame)
686 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200687 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200688 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200689
Armin Ronacher8efc5222008-04-08 14:47:40 +0200690 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200691 if have_extends:
692 if not self.has_known_extends:
693 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200694 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200695 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200696 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200697 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200698 self.indent()
699 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200700 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200701
702 # at this point we now have the blocks collected and can visit them too.
703 for name, block in self.blocks.iteritems():
704 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200705 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200706 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200707 self.writeline('def block_%s(context, environment=environment):'
708 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200709 self.indent()
710 undeclared = find_undeclared(block.body, ('self', 'super'))
711 if 'self' in undeclared:
712 block_frame.identifiers.add_special('self')
713 self.writeline('l_self = TemplateReference(context)')
714 if 'super' in undeclared:
715 block_frame.identifiers.add_special('super')
716 self.writeline('l_super = context.super(%r, '
717 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200718 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200719 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200720 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200721 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200722
Armin Ronacher75cfb862008-04-11 13:47:22 +0200723 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200724 for x in self.blocks),
725 extra=1)
726
727 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200728 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
729 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200730
Armin Ronachere791c2a2008-04-07 18:39:54 +0200731 def visit_Block(self, node, frame):
732 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200733 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200734 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200735 # if we know that we are a child template, there is no need to
736 # check if we are one
737 if self.has_known_extends:
738 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200739 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200740 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200741 self.indent()
742 level += 1
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200743 self.writeline('for event in context.blocks[%r][0](context):' %
Armin Ronacherc9705c22008-04-27 21:28:03 +0200744 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200745 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200746 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200747 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200748
749 def visit_Extends(self, node, frame):
750 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200751 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200752 self.fail('cannot use extend from a non top-level scope',
753 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200754
Armin Ronacher7fb38972008-04-11 13:54:28 +0200755 # if the number of extends statements in general is zero so
756 # far, we don't have to add a check if something extended
757 # the template before this one.
758 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200759
Armin Ronacher7fb38972008-04-11 13:54:28 +0200760 # if we have a known extends we just add a template runtime
761 # error into the generated code. We could catch that at compile
762 # time too, but i welcome it not to confuse users by throwing the
763 # same error at different times just "because we can".
764 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200765 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200766 self.indent()
767 self.writeline('raise TemplateRuntimeError(%r)' %
768 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200769
Armin Ronacher7fb38972008-04-11 13:54:28 +0200770 # if we have a known extends already we don't need that code here
771 # as we know that the template execution will end here.
772 if self.has_known_extends:
773 raise CompilerExit()
774 self.outdent()
775
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200776 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200777 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200778 self.write(', %r)' % self.name)
779 self.writeline('for name, parent_block in parent_template.'
780 'blocks.iteritems():')
781 self.indent()
782 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200783 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200784 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200785
786 # if this extends statement was in the root level we can take
787 # advantage of that information and simplify the generated code
788 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200789 if frame.rootlevel:
790 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200791
Armin Ronacher7fb38972008-04-11 13:54:28 +0200792 # and now we have one more
793 self.extends_so_far += 1
794
Armin Ronacherf059ec12008-04-11 22:21:00 +0200795 def visit_Include(self, node, frame):
796 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200797 if node.with_context:
798 self.writeline('template = environment.get_template(', node)
799 self.visit(node.template, frame)
800 self.write(', %r)' % self.name)
Armin Ronacher5411ce72008-05-25 11:36:22 +0200801 self.writeline('for event in template.root_render_func('
Armin Ronacherea847c52008-05-02 20:04:32 +0200802 'template.new_context(context.parent, True)):')
803 else:
804 self.writeline('for event in environment.get_template(', node)
805 self.visit(node.template, frame)
Armin Ronacher771c7502008-05-18 23:14:14 +0200806 self.write(', %r).module._body_stream:' %
Armin Ronacherea847c52008-05-02 20:04:32 +0200807 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200808 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200809 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200810 self.outdent()
811
Armin Ronacher0611e492008-04-25 23:44:14 +0200812 def visit_Import(self, node, frame):
813 """Visit regular imports."""
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200814 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200815 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200816 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200817 self.write('environment.get_template(')
818 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200819 self.write(', %r).' % self.name)
820 if node.with_context:
821 self.write('make_module(context.parent, True)')
822 else:
823 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200824 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200825 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200826
827 def visit_FromImport(self, node, frame):
828 """Visit named imports."""
829 self.newline(node)
830 self.write('included_template = environment.get_template(')
831 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200832 self.write(', %r).' % self.name)
833 if node.with_context:
834 self.write('make_module(context.parent, True)')
835 else:
836 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200837
838 var_names = []
839 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200840 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200841 if isinstance(name, tuple):
842 name, alias = name
843 else:
844 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200845 self.writeline('l_%s = getattr(included_template, '
846 '%r, missing)' % (alias, name))
847 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200848 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200849 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +0200850 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200851 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +0200852 (alias, 'the template %%r (imported on %s) does '
853 'not export the requested name %s' % (
854 self.position(node),
855 repr(name)
856 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +0200857 self.outdent()
858 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +0200859 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +0200860 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +0200861 discarded_names.append(alias)
862
863 if var_names:
864 if len(var_names) == 1:
865 name = var_names[0]
866 self.writeline('context.vars[%r] = l_%s' % (name, name))
867 else:
868 self.writeline('context.vars.update({%s})' % ', '.join(
869 '%r: l_%s' % (name, name) for name in var_names
870 ))
871 if discarded_names:
872 if len(discarded_names) == 1:
873 self.writeline('context.exported_vars.discard(%r)' %
874 discarded_names[0])
875 else:
876 self.writeline('context.exported_vars.difference_'
877 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200878
Armin Ronachere791c2a2008-04-07 18:39:54 +0200879 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200880 # when calculating the nodes for the inner frame we have to exclude
881 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200882 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200883 if node.recursive:
884 loop_frame = self.function_scoping(node, frame, children,
885 find_special=False)
886 else:
887 loop_frame = frame.inner()
888 loop_frame.inspect(children)
889
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200890 # try to figure out if we have an extended loop. An extended loop
891 # is necessary if the loop is in recursive mode if the special loop
892 # variable is accessed in the body.
893 extended_loop = node.recursive or 'loop' in \
894 find_undeclared(node.iter_child_nodes(
895 only=('body',)), ('loop',))
896
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200897 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +0200898 # variables at that point. Because loops can be nested but the loop
899 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200900 if not node.recursive:
Armin Ronacherff53c782008-08-13 18:55:50 +0200901 aliases = self.collect_shadowed(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200902
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 Ronacherff53c782008-08-13 18:55:50 +0200910 # make sure the loop variable is a special one and raise a template
911 # assertion error if a loop tries to write to loop
912 loop_frame.identifiers.add_special('loop')
913 for name in node.find_all(nodes.Name):
914 if name.ctx == 'store' and name.name == 'loop':
915 self.fail('Can\'t assign to special loop variable '
916 'in for-loop target', name.lineno)
917
Armin Ronacherc9705c22008-04-27 21:28:03 +0200918 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200919 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200920 iteration_indicator = self.temporary_identifier()
921 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200922
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200923 # Create a fake parent loop if the else or test section of a
924 # loop is accessing the special loop variable and no parent loop
925 # exists.
926 if 'loop' not in aliases and 'loop' in find_undeclared(
927 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
928 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +0200929 ("'loop' is undefined. the filter section of a loop as well "
930 "as the else block doesn't have access to the special 'loop'"
931 " variable of the current loop. Because there is no parent "
932 "loop it's undefined. Happened in loop on %s" %
933 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200934
935 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200936 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200937 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200938
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200939 # if we have an extened loop and a node test, we filter in the
940 # "outer frame".
941 if extended_loop and node.test is not None:
942 self.write('(')
943 self.visit(node.target, loop_frame)
944 self.write(' for ')
945 self.visit(node.target, loop_frame)
946 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200947 if node.recursive:
948 self.write('reciter')
949 else:
950 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200951 self.write(' if (')
952 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200953 self.visit(node.test, test_frame)
954 self.write('))')
955
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200956 elif node.recursive:
957 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200958 else:
959 self.visit(node.iter, loop_frame)
960
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200961 if node.recursive:
962 self.write(', recurse=loop_render_func):')
963 else:
964 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200965
966 # tests in not extended loops become a continue
967 if not extended_loop and node.test is not None:
968 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200969 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200970 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200971 self.write(':')
972 self.indent()
973 self.writeline('continue')
974 self.outdent(2)
975
Armin Ronacherc9705c22008-04-27 21:28:03 +0200976 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200977 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200978 if node.else_:
979 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200980 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200981
982 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200983 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200984 self.indent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200985 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200986 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200987
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200988 # reset the aliases if there are any.
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200989 self.restore_shadowed(aliases)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200990
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200991 # if the node was recursive we have to return the buffer contents
992 # and start the iteration code
993 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200994 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200995 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200996 self.start_write(frame, node)
997 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200998 self.visit(node.iter, frame)
999 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001000 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001001
Armin Ronachere791c2a2008-04-07 18:39:54 +02001002 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001003 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001004 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001005 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001006 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001007 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001008 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001009 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001010 if node.else_:
1011 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001012 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001013 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001014 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001015
Armin Ronacher8efc5222008-04-08 14:47:40 +02001016 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001017 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001018 self.newline()
1019 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001020 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001021 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001022 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001023 self.write('l_%s = ' % node.name)
1024 self.macro_def(node, macro_frame)
Armin Ronacher71082072008-04-12 14:19:36 +02001025
1026 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001027 children = node.iter_child_nodes(exclude=('call',))
1028 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001029 self.writeline('caller = ')
1030 self.macro_def(node, call_frame)
1031 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001032 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001033 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001034
1035 def visit_FilterBlock(self, node, frame):
1036 filter_frame = frame.inner()
1037 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001038 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001039 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001040 self.buffer(filter_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001041 self.blockvisit(node.body, filter_frame, force_generator=False)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001042 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001043 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001044 self.end_write(frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001045 self.restore_shadowed(aliases)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001046
Armin Ronachere791c2a2008-04-07 18:39:54 +02001047 def visit_ExprStmt(self, node, frame):
1048 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001049 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001050
1051 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001052 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +02001053 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001054 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001055
Armin Ronacher665bfb82008-07-14 13:41:46 +02001056 if self.environment.finalize:
1057 finalize = lambda x: unicode(self.environment.finalize(x))
1058 else:
1059 finalize = unicode
1060
Armin Ronacher75cfb862008-04-11 13:47:22 +02001061 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001062
Armin Ronacher7fb38972008-04-11 13:54:28 +02001063 # if we are in the toplevel scope and there was already an extends
1064 # statement we have to add a check that disables our yield(s) here
1065 # so that they don't appear in the output.
1066 outdent_later = False
1067 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001068 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001069 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001070 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001071
Armin Ronachere791c2a2008-04-07 18:39:54 +02001072 # try to evaluate as many chunks as possible into a static
1073 # string at compile time.
1074 body = []
1075 for child in node.nodes:
1076 try:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001077 const = child.as_const()
1078 except nodes.Impossible:
1079 body.append(child)
1080 continue
1081 try:
1082 if self.environment.autoescape:
1083 if hasattr(const, '__html__'):
1084 const = const.__html__()
1085 else:
1086 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001087 const = finalize(const)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001088 except:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001089 # if something goes wrong here we evaluate the node
1090 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001091 body.append(child)
1092 continue
1093 if body and isinstance(body[-1], list):
1094 body[-1].append(const)
1095 else:
1096 body.append([const])
1097
Armin Ronachered1e0d42008-05-18 20:25:28 +02001098 # if we have less than 3 nodes or a buffer we yield or extend/append
1099 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001100 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001101 # for one item we append, for more we extend
1102 if len(body) == 1:
1103 self.writeline('%s.append(' % frame.buffer)
1104 else:
1105 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001106 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001107 for item in body:
1108 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001109 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001110 if frame.buffer is None:
1111 self.writeline('yield ' + val)
1112 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001113 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001114 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001115 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001116 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001117 else:
1118 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001119 close = 1
1120 if self.environment.autoescape:
1121 self.write('escape(')
1122 else:
1123 self.write('unicode(')
1124 if self.environment.finalize is not None:
1125 self.write('environment.finalize(')
1126 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001127 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001128 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001129 if frame.buffer is not None:
1130 self.write(', ')
1131 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001132 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001133 self.outdent()
1134 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001135
1136 # otherwise we create a format string as this is faster in that case
1137 else:
1138 format = []
1139 arguments = []
1140 for item in body:
1141 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001142 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001143 else:
1144 format.append('%s')
1145 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001146 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001147 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001148 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001149 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001150 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001151 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001152 close = 0
1153 if self.environment.autoescape:
1154 self.write('escape(')
1155 close += 1
1156 if self.environment.finalize is not None:
1157 self.write('environment.finalize(')
1158 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001159 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001160 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001161 self.outdent()
1162 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001163
Armin Ronacher7fb38972008-04-11 13:54:28 +02001164 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001165 self.outdent()
1166
Armin Ronacher8efc5222008-04-08 14:47:40 +02001167 def visit_Assign(self, node, frame):
1168 self.newline(node)
1169 # toplevel assignments however go into the local namespace and
1170 # the current template's context. We create a copy of the frame
1171 # here and add a set so that the Name visitor can add the assigned
1172 # names here.
1173 if frame.toplevel:
1174 assignment_frame = frame.copy()
1175 assignment_frame.assigned_names = set()
1176 else:
1177 assignment_frame = frame
1178 self.visit(node.target, assignment_frame)
1179 self.write(' = ')
1180 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001181
1182 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001183 if frame.toplevel:
Armin Ronacher69e12db2008-05-12 09:00:03 +02001184 public_names = [x for x in assignment_frame.assigned_names
Armin Ronacher903d1682008-05-23 00:51:58 +02001185 if not x.startswith('_')]
Armin Ronacher69e12db2008-05-12 09:00:03 +02001186 if len(assignment_frame.assigned_names) == 1:
1187 name = iter(assignment_frame.assigned_names).next()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001188 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001189 else:
1190 self.writeline('context.vars.update({')
1191 for idx, name in enumerate(assignment_frame.assigned_names):
1192 if idx:
1193 self.write(', ')
1194 self.write('%r: l_%s' % (name, name))
1195 self.write('})')
1196 if public_names:
1197 if len(public_names) == 1:
1198 self.writeline('context.exported_vars.add(%r)' %
1199 public_names[0])
1200 else:
1201 self.writeline('context.exported_vars.update((%s))' %
1202 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001203
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001204 # -- Expression Visitors
1205
Armin Ronachere791c2a2008-04-07 18:39:54 +02001206 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001207 if node.ctx == 'store' and frame.toplevel:
1208 frame.assigned_names.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001209 self.write('l_' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001210
1211 def visit_Const(self, node, frame):
1212 val = node.value
1213 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001214 self.write(str(val))
1215 else:
1216 self.write(repr(val))
1217
Armin Ronacher5411ce72008-05-25 11:36:22 +02001218 def visit_TemplateData(self, node, frame):
1219 self.write(repr(node.as_const()))
1220
Armin Ronacher8efc5222008-04-08 14:47:40 +02001221 def visit_Tuple(self, node, frame):
1222 self.write('(')
1223 idx = -1
1224 for idx, item in enumerate(node.items):
1225 if idx:
1226 self.write(', ')
1227 self.visit(item, frame)
1228 self.write(idx == 0 and ',)' or ')')
1229
Armin Ronacher8edbe492008-04-10 20:43:43 +02001230 def visit_List(self, node, frame):
1231 self.write('[')
1232 for idx, item in enumerate(node.items):
1233 if idx:
1234 self.write(', ')
1235 self.visit(item, frame)
1236 self.write(']')
1237
1238 def visit_Dict(self, node, frame):
1239 self.write('{')
1240 for idx, item in enumerate(node.items):
1241 if idx:
1242 self.write(', ')
1243 self.visit(item.key, frame)
1244 self.write(': ')
1245 self.visit(item.value, frame)
1246 self.write('}')
1247
Armin Ronachere791c2a2008-04-07 18:39:54 +02001248 def binop(operator):
1249 def visitor(self, node, frame):
1250 self.write('(')
1251 self.visit(node.left, frame)
1252 self.write(' %s ' % operator)
1253 self.visit(node.right, frame)
1254 self.write(')')
1255 return visitor
1256
1257 def uaop(operator):
1258 def visitor(self, node, frame):
1259 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001260 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001261 self.write(')')
1262 return visitor
1263
1264 visit_Add = binop('+')
1265 visit_Sub = binop('-')
1266 visit_Mul = binop('*')
1267 visit_Div = binop('/')
1268 visit_FloorDiv = binop('//')
1269 visit_Pow = binop('**')
1270 visit_Mod = binop('%')
1271 visit_And = binop('and')
1272 visit_Or = binop('or')
1273 visit_Pos = uaop('+')
1274 visit_Neg = uaop('-')
1275 visit_Not = uaop('not ')
1276 del binop, uaop
1277
Armin Ronacherd1342312008-04-28 12:20:12 +02001278 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001279 self.write('%s((' % (self.environment.autoescape and
1280 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001281 for arg in node.nodes:
1282 self.visit(arg, frame)
1283 self.write(', ')
1284 self.write('))')
1285
Armin Ronachere791c2a2008-04-07 18:39:54 +02001286 def visit_Compare(self, node, frame):
1287 self.visit(node.expr, frame)
1288 for op in node.ops:
1289 self.visit(op, frame)
1290
1291 def visit_Operand(self, node, frame):
1292 self.write(' %s ' % operators[node.op])
1293 self.visit(node.expr, frame)
1294
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001295 def visit_Getattr(self, node, frame):
1296 self.write('environment.getattr(')
1297 self.visit(node.node, frame)
1298 self.write(', %r)' % node.attr)
1299
1300 def visit_Getitem(self, node, frame):
Armin Ronacherb9388772008-06-25 20:43:18 +02001301 # slices or integer subscriptions bypass the getitem
Armin Ronacher08a6a3b2008-05-13 15:35:47 +02001302 # method if we can determine that at compile time.
1303 if isinstance(node.arg, nodes.Slice) or \
1304 (isinstance(node.arg, nodes.Const) and
1305 isinstance(node.arg.value, (int, long))):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001306 self.visit(node.node, frame)
1307 self.write('[')
1308 self.visit(node.arg, frame)
1309 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001310 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001311 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001312 self.visit(node.node, frame)
1313 self.write(', ')
1314 self.visit(node.arg, frame)
1315 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001316
1317 def visit_Slice(self, node, frame):
1318 if node.start is not None:
1319 self.visit(node.start, frame)
1320 self.write(':')
1321 if node.stop is not None:
1322 self.visit(node.stop, frame)
1323 if node.step is not None:
1324 self.write(':')
1325 self.visit(node.step, frame)
1326
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001327 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001328 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001329 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001330 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001331 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001332 if getattr(func, 'contextfilter', False):
1333 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001334 elif getattr(func, 'environmentfilter', False):
1335 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001336
1337 # if the filter node is None we are inside a filter block
1338 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001339 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001340 self.visit(node.node, frame)
Armin Ronacher3da90312008-05-23 16:37:28 +02001341 elif self.environment.autoescape:
1342 self.write('Markup(concat(%s))' % frame.buffer)
1343 else:
1344 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001345 self.signature(node, frame)
1346 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001347
1348 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001349 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001350 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001351 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001352 self.visit(node.node, frame)
1353 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001354 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001355
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001356 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001357 def write_expr2():
1358 if node.expr2 is not None:
1359 return self.visit(node.expr2, frame)
1360 self.write('environment.undefined(%r)' % ('the inline if-'
1361 'expression on %s evaluated to false and '
1362 'no else section was defined.' % self.position(node)))
1363
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001364 if not have_condexpr:
1365 self.write('((')
1366 self.visit(node.test, frame)
1367 self.write(') and (')
1368 self.visit(node.expr1, frame)
1369 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001370 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001371 self.write(',))[0]')
1372 else:
1373 self.write('(')
1374 self.visit(node.expr1, frame)
1375 self.write(' if ')
1376 self.visit(node.test, frame)
1377 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001378 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001379 self.write(')')
1380
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001381 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001382 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001383 self.write('environment.call(context, ')
1384 else:
1385 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001386 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001387 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001388 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001389 self.write(')')
1390
1391 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001392 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001393 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001394
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001395 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001396
1397 def visit_MarkSafe(self, node, frame):
1398 self.write('Markup(')
1399 self.visit(node.expr, frame)
1400 self.write(')')
1401
1402 def visit_EnvironmentAttribute(self, node, frame):
1403 self.write('environment.' + node.name)
1404
1405 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001406 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001407
1408 def visit_ImportedName(self, node, frame):
1409 self.write(self.import_aliases[node.importname])
1410
1411 def visit_InternalName(self, node, frame):
1412 self.write(node.name)
1413
Armin Ronacher6df604e2008-05-23 22:18:38 +02001414 def visit_ContextReference(self, node, frame):
1415 self.write('context')
1416
Armin Ronachered1e0d42008-05-18 20:25:28 +02001417 def visit_Continue(self, node, frame):
1418 self.writeline('continue', node)
1419
1420 def visit_Break(self, node, frame):
1421 self.writeline('break', node)