blob: fab6ea0c09f7dd76c0b1a74e89fbcfec7e537f3f [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
118 def find_shadowed(self):
119 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200120 return (self.declared | self.outer_undeclared) & \
121 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200122
123
124class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200125 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200126
127 def __init__(self, parent=None):
128 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200129
Armin Ronacher75cfb862008-04-11 13:47:22 +0200130 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200131 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200132
Armin Ronacher75cfb862008-04-11 13:47:22 +0200133 # the root frame is basically just the outermost frame, so no if
134 # conditions. This information is used to optimize inheritance
135 # situations.
136 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200137
138 # inside some tags we are using a buffer rather than yield statements.
139 # this for example affects {% filter %} or {% macro %}. If a frame
140 # is buffered this variable points to the name of the list used as
141 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200142 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200143
Armin Ronacherfed44b52008-04-13 19:42:53 +0200144 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200145 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200146
147 # the parent of this frame
148 self.parent = parent
149
Armin Ronachere791c2a2008-04-07 18:39:54 +0200150 if parent is not None:
151 self.identifiers.declared.update(
152 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200153 parent.identifiers.declared_locally |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200154 parent.identifiers.declared_parameter |
155 parent.identifiers.undeclared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200156 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200157 self.identifiers.outer_undeclared.update(
158 parent.identifiers.undeclared -
159 self.identifiers.declared
160 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200161 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200162
Armin Ronacher8efc5222008-04-08 14:47:40 +0200163 def copy(self):
164 """Create a copy of the current one."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200165 rv = object.__new__(self.__class__)
166 rv.__dict__.update(self.__dict__)
167 rv.identifiers = object.__new__(self.identifiers.__class__)
168 rv.identifiers.__dict__.update(self.identifiers.__dict__)
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 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200189 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200190 rv.rootlevel = False
191 return rv
192
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200193 __copy__ = copy
194
Armin Ronachere791c2a2008-04-07 18:39:54 +0200195
Armin Ronacherc9705c22008-04-27 21:28:03 +0200196class VisitorExit(RuntimeError):
197 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
198
199
200class DependencyFinderVisitor(NodeVisitor):
201 """A visitor that collects filter and test calls."""
202
203 def __init__(self):
204 self.filters = set()
205 self.tests = set()
206
207 def visit_Filter(self, node):
208 self.generic_visit(node)
209 self.filters.add(node.name)
210
211 def visit_Test(self, node):
212 self.generic_visit(node)
213 self.tests.add(node.name)
214
215 def visit_Block(self, node):
216 """Stop visiting at blocks."""
217
218
219class UndeclaredNameVisitor(NodeVisitor):
220 """A visitor that checks if a name is accessed without being
221 declared. This is different from the frame visitor as it will
222 not stop at closure frames.
223 """
224
225 def __init__(self, names):
226 self.names = set(names)
227 self.undeclared = set()
228
229 def visit_Name(self, node):
230 if node.ctx == 'load' and node.name in self.names:
231 self.undeclared.add(node.name)
232 if self.undeclared == self.names:
233 raise VisitorExit()
234 else:
235 self.names.discard(node.name)
236
237 def visit_Block(self, node):
238 """Stop visiting a blocks."""
239
240
Armin Ronachere791c2a2008-04-07 18:39:54 +0200241class FrameIdentifierVisitor(NodeVisitor):
242 """A visitor for `Frame.inspect`."""
243
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200244 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200245 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200246 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200247
Armin Ronacherc9705c22008-04-27 21:28:03 +0200248 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200249 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200250 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200251 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200252 elif node.ctx == 'param':
253 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200254 elif node.ctx == 'load' and not \
255 self.identifiers.is_declared(node.name, self.hard_scope):
256 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200257
Armin Ronacherc9705c22008-04-27 21:28:03 +0200258 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200259 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200260
Armin Ronacherc9705c22008-04-27 21:28:03 +0200261 def visit_Import(self, node):
262 self.generic_visit(node)
263 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200264
Armin Ronacherc9705c22008-04-27 21:28:03 +0200265 def visit_FromImport(self, node):
266 self.generic_visit(node)
267 for name in node.names:
268 if isinstance(name, tuple):
269 self.identifiers.declared_locally.add(name[1])
270 else:
271 self.identifiers.declared_locally.add(name)
272
273 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200274 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200275 self.visit(node.node)
276 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200277
Armin Ronacherc9705c22008-04-27 21:28:03 +0200278 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200279 """Visiting stops at for blocks. However the block sequence
280 is visited as part of the outer scope.
281 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200282 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200283
Armin Ronacherc9705c22008-04-27 21:28:03 +0200284 def visit_CallBlock(self, node):
285 for child in node.iter_child_nodes(exclude=('body',)):
286 self.visit(child)
287
288 def visit_FilterBlock(self, node):
289 self.visit(node.filter)
290
291 def visit_Block(self, node):
292 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200293
294
Armin Ronacher75cfb862008-04-11 13:47:22 +0200295class CompilerExit(Exception):
296 """Raised if the compiler encountered a situation where it just
297 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200298 raises such an exception is not further processed.
299 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200300
301
Armin Ronachere791c2a2008-04-07 18:39:54 +0200302class CodeGenerator(NodeVisitor):
303
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200304 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200305 if stream is None:
306 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200307 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200308 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200309 self.filename = filename
310 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200311
Armin Ronacher023b5e92008-05-08 11:03:10 +0200312 # aliases for imports
313 self.import_aliases = {}
314
Armin Ronacherfed44b52008-04-13 19:42:53 +0200315 # a registry for all blocks. Because blocks are moved out
316 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200317 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200318
319 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200320 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200321
322 # some templates have a rootlevel extends. In this case we
323 # can safely assume that we're a child template and do some
324 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200325 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200326
Armin Ronacherba3757b2008-04-16 19:43:16 +0200327 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200328 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200329
Armin Ronacherb9e78752008-05-10 23:36:28 +0200330 # registry of all filters and tests (global, not block local)
331 self.tests = {}
332 self.filters = {}
333
Armin Ronacherba3757b2008-04-16 19:43:16 +0200334 # the debug information
335 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200336 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200337
Armin Ronacherfed44b52008-04-13 19:42:53 +0200338 # the number of new lines before the next write()
339 self._new_lines = 0
340
341 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200342 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200343
344 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200345 self._first_write = True
346
Armin Ronacherfed44b52008-04-13 19:42:53 +0200347 # used by the `temporary_identifier` method to get new
348 # unique, temporary identifier
349 self._last_identifier = 0
350
351 # the current indentation
352 self._indentation = 0
353
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200354 # -- Various compilation helpers
355
Armin Ronachere2244882008-05-19 09:25:57 +0200356 def fail(self, msg, lineno):
357 """Fail with a `TemplateAssertionError`."""
358 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
359
Armin Ronachere791c2a2008-04-07 18:39:54 +0200360 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200361 """Get a new unique identifier."""
362 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200363 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200364
Armin Ronachered1e0d42008-05-18 20:25:28 +0200365 def buffer(self, frame):
366 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200367 frame.buffer = self.temporary_identifier()
368 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200369
370 def return_buffer_contents(self, frame):
371 """Return the buffer contents of the frame."""
372 if self.environment.autoescape:
373 self.writeline('return Markup(concat(%s))' % frame.buffer)
374 else:
375 self.writeline('return concat(%s)' % frame.buffer)
376
Armin Ronachere791c2a2008-04-07 18:39:54 +0200377 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200378 """Indent by one."""
379 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200380
Armin Ronacher8efc5222008-04-08 14:47:40 +0200381 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200382 """Outdent by step."""
383 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200384
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200385 def start_write(self, frame, node=None):
386 """Yield or write into the frame buffer."""
387 if frame.buffer is None:
388 self.writeline('yield ', node)
389 else:
390 self.writeline('%s.append(' % frame.buffer, node)
391
392 def end_write(self, frame):
393 """End the writing process started by `start_write`."""
394 if frame.buffer is not None:
395 self.write(')')
396
397 def simple_write(self, s, frame, node=None):
398 """Simple shortcut for start_write + write + end_write."""
399 self.start_write(frame, node)
400 self.write(s)
401 self.end_write(frame)
402
Armin Ronacherc9705c22008-04-27 21:28:03 +0200403 def blockvisit(self, nodes, frame, force_generator=True):
404 """Visit a list of nodes as block in a frame. If the current frame
405 is no buffer a dummy ``if 0: yield None`` is written automatically
406 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200407 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200408 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200409 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200410 try:
411 for node in nodes:
412 self.visit(node, frame)
413 except CompilerExit:
414 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200415
416 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200417 """Write a string into the output stream."""
418 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200419 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200420 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200421 self.code_lineno += self._new_lines
422 if self._write_debug_info is not None:
423 self.debug_info.append((self._write_debug_info,
424 self.code_lineno))
425 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200426 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200427 self.stream.write(' ' * self._indentation)
428 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200429 self.stream.write(x)
430
431 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200432 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200433 self.newline(node, extra)
434 self.write(x)
435
436 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200437 """Add one or more newlines before the next write."""
438 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200439 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200440 self._write_debug_info = node.lineno
441 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200442
Armin Ronacherfd310492008-05-25 00:16:51 +0200443 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200444 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200445 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200446 arguments may not include python keywords otherwise a syntax
447 error could occour. The extra keyword arguments should be given
448 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200449 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200450 # if any of the given keyword arguments is a python keyword
451 # we have to make sure that no invalid call is created.
452 kwarg_workaround = False
453 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200454 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200455 kwarg_workaround = True
456 break
457
Armin Ronacher8efc5222008-04-08 14:47:40 +0200458 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200459 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200460 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200461
462 if not kwarg_workaround:
463 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200464 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200465 self.visit(kwarg, frame)
466 if extra_kwargs is not None:
467 for key, value in extra_kwargs.iteritems():
Armin Ronacherfd310492008-05-25 00:16:51 +0200468 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200469 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200470 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200471 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200472
473 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200474 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200475 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200476 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200477 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200478 for kwarg in node.kwargs:
479 self.write('%r: ' % kwarg.key)
480 self.visit(kwarg.value, frame)
481 self.write(', ')
482 if extra_kwargs is not None:
483 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200484 self.write('%r: %s, ' % (key, value))
485 if node.dyn_kwargs is not None:
486 self.write('}, **')
487 self.visit(node.dyn_kwargs, frame)
488 self.write(')')
489 else:
490 self.write('}')
491
492 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200493 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200494 self.visit(node.dyn_kwargs, frame)
495
Armin Ronacherc9705c22008-04-27 21:28:03 +0200496 def pull_locals(self, frame):
497 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200498 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200499 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200500
501 def pull_dependencies(self, nodes):
502 """Pull all the dependencies."""
503 visitor = DependencyFinderVisitor()
504 for node in nodes:
505 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200506 for dependency in 'filters', 'tests':
507 mapping = getattr(self, dependency)
508 for name in getattr(visitor, dependency):
509 if name not in mapping:
510 mapping[name] = self.temporary_identifier()
511 self.writeline('%s = environment.%s[%r]' %
512 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200513
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200514 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200515 """This function returns all the shadowed variables in a dict
516 in the form name: alias and will write the required assignments
517 into the current scope. No indentation takes place.
518 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200519 aliases = {}
520 for name in frame.identifiers.find_shadowed():
521 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200522 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200523 return aliases
524
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200525 def restore_shadowed(self, aliases):
526 """Restore all aliases."""
527 for name, alias in aliases.iteritems():
528 self.writeline('l_%s = %s' % (name, alias))
529
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200530 def function_scoping(self, node, frame, children=None,
531 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200532 """In Jinja a few statements require the help of anonymous
533 functions. Those are currently macros and call blocks and in
534 the future also recursive loops. As there is currently
535 technical limitation that doesn't allow reading and writing a
536 variable in a scope where the initial value is coming from an
537 outer scope, this function tries to fall back with a common
538 error message. Additionally the frame passed is modified so
539 that the argumetns are collected and callers are looked up.
540
541 This will return the modified frame.
542 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200543 # we have to iterate twice over it, make sure that works
544 if children is None:
545 children = node.iter_child_nodes()
546 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200547 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200548 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200549
550 # variables that are undeclared (accessed before declaration) and
551 # declared locally *and* part of an outside scope raise a template
552 # assertion error. Reason: we can't generate reasonable code from
553 # it without aliasing all the variables. XXX: alias them ^^
554 overriden_closure_vars = (
555 func_frame.identifiers.undeclared &
556 func_frame.identifiers.declared &
557 (func_frame.identifiers.declared_locally |
558 func_frame.identifiers.declared_parameter)
559 )
560 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200561 self.fail('It\'s not possible to set and access variables '
562 'derived from an outer scope! (affects: %s' %
563 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200564
565 # remove variables from a closure from the frame's undeclared
566 # identifiers.
567 func_frame.identifiers.undeclared -= (
568 func_frame.identifiers.undeclared &
569 func_frame.identifiers.declared
570 )
571
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200572 # no special variables for this scope, abort early
573 if not find_special:
574 return func_frame
575
Armin Ronacher963f97d2008-04-25 11:44:59 +0200576 func_frame.accesses_kwargs = False
577 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200578 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200579 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200580
Armin Ronacherc9705c22008-04-27 21:28:03 +0200581 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
582
583 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200584 func_frame.accesses_caller = True
585 func_frame.identifiers.add_special('caller')
586 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200587 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200588 func_frame.accesses_kwargs = True
589 func_frame.identifiers.add_special('kwargs')
590 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200591 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200592 func_frame.accesses_varargs = True
593 func_frame.identifiers.add_special('varargs')
594 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200595 return func_frame
596
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200597 def macro_body(self, node, frame, children=None):
598 """Dump the function def of a macro or call block."""
599 frame = self.function_scoping(node, frame, children)
600 args = frame.arguments
601 self.writeline('def macro(%s):' % ', '.join(args), node)
602 self.indent()
603 self.buffer(frame)
604 self.pull_locals(frame)
605 self.blockvisit(node.body, frame)
606 self.return_buffer_contents(frame)
607 self.outdent()
608 return frame
609
610 def macro_def(self, node, frame):
611 """Dump the macro definition for the def created by macro_body."""
612 arg_tuple = ', '.join(repr(x.name) for x in node.args)
613 name = getattr(node, 'name', None)
614 if len(node.args) == 1:
615 arg_tuple += ','
616 self.write('Macro(environment, macro, %r, (%s), (' %
617 (name, arg_tuple))
618 for arg in node.defaults:
619 self.visit(arg, frame)
620 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200621 self.write('), %r, %r, %r)' % (
622 bool(frame.accesses_kwargs),
623 bool(frame.accesses_varargs),
624 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200625 ))
626
Armin Ronacher547d0b62008-07-04 16:35:10 +0200627 def position(self, node):
628 """Return a human readable position for the node."""
629 rv = 'line %d' % node.lineno
630 if self.name is not None:
631 rv += ' in' + repr(self.name)
632 return rv
633
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200634 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200635
636 def visit_Template(self, node, frame=None):
637 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200638 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200639 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200640 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8edbe492008-04-10 20:43:43 +0200641
Armin Ronacher75cfb862008-04-11 13:47:22 +0200642 # do we have an extends tag at all? If not, we can save some
643 # overhead by just not processing any inheritance code.
644 have_extends = node.find(nodes.Extends) is not None
645
Armin Ronacher8edbe492008-04-10 20:43:43 +0200646 # find all blocks
647 for block in node.find_all(nodes.Block):
648 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200649 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200650 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200651
Armin Ronacher023b5e92008-05-08 11:03:10 +0200652 # find all imports and import them
653 for import_ in node.find_all(nodes.ImportedName):
654 if import_.importname not in self.import_aliases:
655 imp = import_.importname
656 self.import_aliases[imp] = alias = self.temporary_identifier()
657 if '.' in imp:
658 module, obj = imp.rsplit('.', 1)
659 self.writeline('from %s import %s as %s' %
660 (module, obj, alias))
661 else:
662 self.writeline('import %s as %s' % (imp, alias))
663
664 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200665 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200666
Armin Ronacher8efc5222008-04-08 14:47:40 +0200667 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200668 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200669
670 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200671 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200672 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200673 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200674 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200675 if have_extends:
676 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200677 if 'self' in find_undeclared(node.body, ('self',)):
678 frame.identifiers.add_special('self')
679 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200680 self.pull_locals(frame)
681 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200682 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200683 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200684
Armin Ronacher8efc5222008-04-08 14:47:40 +0200685 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200686 if have_extends:
687 if not self.has_known_extends:
688 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200689 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200690 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200691 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200692 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200693 self.indent()
694 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200695 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200696
697 # at this point we now have the blocks collected and can visit them too.
698 for name, block in self.blocks.iteritems():
699 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200700 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200701 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200702 self.writeline('def block_%s(context, environment=environment):'
703 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200704 self.indent()
705 undeclared = find_undeclared(block.body, ('self', 'super'))
706 if 'self' in undeclared:
707 block_frame.identifiers.add_special('self')
708 self.writeline('l_self = TemplateReference(context)')
709 if 'super' in undeclared:
710 block_frame.identifiers.add_special('super')
711 self.writeline('l_super = context.super(%r, '
712 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200713 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200714 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200715 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200716 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200717
Armin Ronacher75cfb862008-04-11 13:47:22 +0200718 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200719 for x in self.blocks),
720 extra=1)
721
722 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200723 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
724 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200725
Armin Ronachere791c2a2008-04-07 18:39:54 +0200726 def visit_Block(self, node, frame):
727 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200728 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200729 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200730 # if we know that we are a child template, there is no need to
731 # check if we are one
732 if self.has_known_extends:
733 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200734 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200735 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200736 self.indent()
737 level += 1
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200738 self.writeline('for event in context.blocks[%r][0](context):' %
Armin Ronacherc9705c22008-04-27 21:28:03 +0200739 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200740 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200741 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200742 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200743
744 def visit_Extends(self, node, frame):
745 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200746 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200747 self.fail('cannot use extend from a non top-level scope',
748 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200749
Armin Ronacher7fb38972008-04-11 13:54:28 +0200750 # if the number of extends statements in general is zero so
751 # far, we don't have to add a check if something extended
752 # the template before this one.
753 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200754
Armin Ronacher7fb38972008-04-11 13:54:28 +0200755 # if we have a known extends we just add a template runtime
756 # error into the generated code. We could catch that at compile
757 # time too, but i welcome it not to confuse users by throwing the
758 # same error at different times just "because we can".
759 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200760 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200761 self.indent()
762 self.writeline('raise TemplateRuntimeError(%r)' %
763 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200764
Armin Ronacher7fb38972008-04-11 13:54:28 +0200765 # if we have a known extends already we don't need that code here
766 # as we know that the template execution will end here.
767 if self.has_known_extends:
768 raise CompilerExit()
769 self.outdent()
770
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200771 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200772 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200773 self.write(', %r)' % self.name)
774 self.writeline('for name, parent_block in parent_template.'
775 'blocks.iteritems():')
776 self.indent()
777 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200778 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200779 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200780
781 # if this extends statement was in the root level we can take
782 # advantage of that information and simplify the generated code
783 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200784 if frame.rootlevel:
785 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200786
Armin Ronacher7fb38972008-04-11 13:54:28 +0200787 # and now we have one more
788 self.extends_so_far += 1
789
Armin Ronacherf059ec12008-04-11 22:21:00 +0200790 def visit_Include(self, node, frame):
791 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200792 if node.with_context:
793 self.writeline('template = environment.get_template(', node)
794 self.visit(node.template, frame)
795 self.write(', %r)' % self.name)
Armin Ronacher5411ce72008-05-25 11:36:22 +0200796 self.writeline('for event in template.root_render_func('
Armin Ronacherea847c52008-05-02 20:04:32 +0200797 'template.new_context(context.parent, True)):')
798 else:
799 self.writeline('for event in environment.get_template(', node)
800 self.visit(node.template, frame)
Armin Ronacher771c7502008-05-18 23:14:14 +0200801 self.write(', %r).module._body_stream:' %
Armin Ronacherea847c52008-05-02 20:04:32 +0200802 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200803 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200804 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200805 self.outdent()
806
Armin Ronacher0611e492008-04-25 23:44:14 +0200807 def visit_Import(self, node, frame):
808 """Visit regular imports."""
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200809 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200810 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200811 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200812 self.write('environment.get_template(')
813 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200814 self.write(', %r).' % self.name)
815 if node.with_context:
816 self.write('make_module(context.parent, True)')
817 else:
818 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200819 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200820 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200821
822 def visit_FromImport(self, node, frame):
823 """Visit named imports."""
824 self.newline(node)
825 self.write('included_template = environment.get_template(')
826 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200827 self.write(', %r).' % self.name)
828 if node.with_context:
829 self.write('make_module(context.parent, True)')
830 else:
831 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200832
833 var_names = []
834 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200835 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200836 if isinstance(name, tuple):
837 name, alias = name
838 else:
839 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200840 self.writeline('l_%s = getattr(included_template, '
841 '%r, missing)' % (alias, name))
842 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200843 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200844 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +0200845 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200846 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +0200847 (alias, 'the template %%r (imported on %s) does '
848 'not export the requested name %s' % (
849 self.position(node),
850 repr(name)
851 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +0200852 self.outdent()
853 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +0200854 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +0200855 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +0200856 discarded_names.append(alias)
857
858 if var_names:
859 if len(var_names) == 1:
860 name = var_names[0]
861 self.writeline('context.vars[%r] = l_%s' % (name, name))
862 else:
863 self.writeline('context.vars.update({%s})' % ', '.join(
864 '%r: l_%s' % (name, name) for name in var_names
865 ))
866 if discarded_names:
867 if len(discarded_names) == 1:
868 self.writeline('context.exported_vars.discard(%r)' %
869 discarded_names[0])
870 else:
871 self.writeline('context.exported_vars.difference_'
872 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200873
Armin Ronachere791c2a2008-04-07 18:39:54 +0200874 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200875 # when calculating the nodes for the inner frame we have to exclude
876 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200877 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200878 if node.recursive:
879 loop_frame = self.function_scoping(node, frame, children,
880 find_special=False)
881 else:
882 loop_frame = frame.inner()
883 loop_frame.inspect(children)
884
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200885 # try to figure out if we have an extended loop. An extended loop
886 # is necessary if the loop is in recursive mode if the special loop
887 # variable is accessed in the body.
888 extended_loop = node.recursive or 'loop' in \
889 find_undeclared(node.iter_child_nodes(
890 only=('body',)), ('loop',))
891
892 # make sure the loop variable is a special one and raise a template
893 # assertion error if a loop tries to write to loop
894 loop_frame.identifiers.add_special('loop')
895 for name in node.find_all(nodes.Name):
896 if name.ctx == 'store' and name.name == 'loop':
897 self.fail('Can\'t assign to special loop variable '
898 'in for-loop target', name.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200899
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200900 # if we don't have an recursive loop we have to find the shadowed
901 # variables at that point
902 if not node.recursive:
903 aliases = self.collect_shadowed(loop_frame)
904
905 # otherwise we set up a buffer and add a function def
906 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200907 self.writeline('def loop(reciter, loop_render_func):', node)
908 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +0200909 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200910 aliases = {}
911
Armin Ronacherc9705c22008-04-27 21:28:03 +0200912 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200913 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200914 iteration_indicator = self.temporary_identifier()
915 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200916
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200917 # Create a fake parent loop if the else or test section of a
918 # loop is accessing the special loop variable and no parent loop
919 # exists.
920 if 'loop' not in aliases and 'loop' in find_undeclared(
921 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
922 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +0200923 ("'loop' is undefined. the filter section of a loop as well "
924 "as the else block doesn't have access to the special 'loop'"
925 " variable of the current loop. Because there is no parent "
926 "loop it's undefined. Happened in loop on %s" %
927 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200928
929 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200930 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200931 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200932
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200933 # if we have an extened loop and a node test, we filter in the
934 # "outer frame".
935 if extended_loop and node.test is not None:
936 self.write('(')
937 self.visit(node.target, loop_frame)
938 self.write(' for ')
939 self.visit(node.target, loop_frame)
940 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200941 if node.recursive:
942 self.write('reciter')
943 else:
944 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200945 self.write(' if (')
946 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200947 self.visit(node.test, test_frame)
948 self.write('))')
949
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200950 elif node.recursive:
951 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200952 else:
953 self.visit(node.iter, loop_frame)
954
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200955 if node.recursive:
956 self.write(', recurse=loop_render_func):')
957 else:
958 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200959
960 # tests in not extended loops become a continue
961 if not extended_loop and node.test is not None:
962 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200963 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200964 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200965 self.write(':')
966 self.indent()
967 self.writeline('continue')
968 self.outdent(2)
969
Armin Ronacherc9705c22008-04-27 21:28:03 +0200970 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200971 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200972 if node.else_:
973 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200974 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200975
976 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200977 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200978 self.indent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200979 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200980 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200981
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200982 # reset the aliases if there are any.
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200983 self.restore_shadowed(aliases)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200984
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200985 # if the node was recursive we have to return the buffer contents
986 # and start the iteration code
987 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200988 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200989 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200990 self.start_write(frame, node)
991 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200992 self.visit(node.iter, frame)
993 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200994 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200995
Armin Ronachere791c2a2008-04-07 18:39:54 +0200996 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200997 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200998 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200999 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001000 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001001 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001002 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001003 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001004 if node.else_:
1005 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001006 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001007 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001008 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001009
Armin Ronacher8efc5222008-04-08 14:47:40 +02001010 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001011 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001012 self.newline()
1013 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001014 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001015 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001016 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001017 self.write('l_%s = ' % node.name)
1018 self.macro_def(node, macro_frame)
Armin Ronacher71082072008-04-12 14:19:36 +02001019
1020 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001021 children = node.iter_child_nodes(exclude=('call',))
1022 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001023 self.writeline('caller = ')
1024 self.macro_def(node, call_frame)
1025 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001026 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001027 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001028
1029 def visit_FilterBlock(self, node, frame):
1030 filter_frame = frame.inner()
1031 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001032 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001033 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001034 self.buffer(filter_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001035 self.blockvisit(node.body, filter_frame, force_generator=False)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001036 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001037 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001038 self.end_write(frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001039 self.restore_shadowed(aliases)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001040
Armin Ronachere791c2a2008-04-07 18:39:54 +02001041 def visit_ExprStmt(self, node, frame):
1042 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001043 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001044
1045 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001046 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +02001047 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001048 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001049
Armin Ronacher665bfb82008-07-14 13:41:46 +02001050 if self.environment.finalize:
1051 finalize = lambda x: unicode(self.environment.finalize(x))
1052 else:
1053 finalize = unicode
1054
Armin Ronacher75cfb862008-04-11 13:47:22 +02001055 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001056
Armin Ronacher7fb38972008-04-11 13:54:28 +02001057 # if we are in the toplevel scope and there was already an extends
1058 # statement we have to add a check that disables our yield(s) here
1059 # so that they don't appear in the output.
1060 outdent_later = False
1061 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001062 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001063 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001064 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001065
Armin Ronachere791c2a2008-04-07 18:39:54 +02001066 # try to evaluate as many chunks as possible into a static
1067 # string at compile time.
1068 body = []
1069 for child in node.nodes:
1070 try:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001071 const = child.as_const()
1072 except nodes.Impossible:
1073 body.append(child)
1074 continue
1075 try:
1076 if self.environment.autoescape:
1077 if hasattr(const, '__html__'):
1078 const = const.__html__()
1079 else:
1080 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001081 const = finalize(const)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001082 except:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001083 # if something goes wrong here we evaluate the node
1084 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001085 body.append(child)
1086 continue
1087 if body and isinstance(body[-1], list):
1088 body[-1].append(const)
1089 else:
1090 body.append([const])
1091
Armin Ronachered1e0d42008-05-18 20:25:28 +02001092 # if we have less than 3 nodes or a buffer we yield or extend/append
1093 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001094 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001095 # for one item we append, for more we extend
1096 if len(body) == 1:
1097 self.writeline('%s.append(' % frame.buffer)
1098 else:
1099 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001100 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001101 for item in body:
1102 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001103 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001104 if frame.buffer is None:
1105 self.writeline('yield ' + val)
1106 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001107 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001108 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001109 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001110 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001111 else:
1112 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001113 close = 1
1114 if self.environment.autoescape:
1115 self.write('escape(')
1116 else:
1117 self.write('unicode(')
1118 if self.environment.finalize is not None:
1119 self.write('environment.finalize(')
1120 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001121 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001122 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001123 if frame.buffer is not None:
1124 self.write(', ')
1125 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001126 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001127 self.outdent()
1128 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001129
1130 # otherwise we create a format string as this is faster in that case
1131 else:
1132 format = []
1133 arguments = []
1134 for item in body:
1135 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001136 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001137 else:
1138 format.append('%s')
1139 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001140 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001141 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001142 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001143 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001144 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001145 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001146 close = 0
1147 if self.environment.autoescape:
1148 self.write('escape(')
1149 close += 1
1150 if self.environment.finalize is not None:
1151 self.write('environment.finalize(')
1152 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001153 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001154 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001155 self.outdent()
1156 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001157
Armin Ronacher7fb38972008-04-11 13:54:28 +02001158 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001159 self.outdent()
1160
Armin Ronacher8efc5222008-04-08 14:47:40 +02001161 def visit_Assign(self, node, frame):
1162 self.newline(node)
1163 # toplevel assignments however go into the local namespace and
1164 # the current template's context. We create a copy of the frame
1165 # here and add a set so that the Name visitor can add the assigned
1166 # names here.
1167 if frame.toplevel:
1168 assignment_frame = frame.copy()
1169 assignment_frame.assigned_names = set()
1170 else:
1171 assignment_frame = frame
1172 self.visit(node.target, assignment_frame)
1173 self.write(' = ')
1174 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001175
1176 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001177 if frame.toplevel:
Armin Ronacher69e12db2008-05-12 09:00:03 +02001178 public_names = [x for x in assignment_frame.assigned_names
Armin Ronacher903d1682008-05-23 00:51:58 +02001179 if not x.startswith('_')]
Armin Ronacher69e12db2008-05-12 09:00:03 +02001180 if len(assignment_frame.assigned_names) == 1:
1181 name = iter(assignment_frame.assigned_names).next()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001182 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001183 else:
1184 self.writeline('context.vars.update({')
1185 for idx, name in enumerate(assignment_frame.assigned_names):
1186 if idx:
1187 self.write(', ')
1188 self.write('%r: l_%s' % (name, name))
1189 self.write('})')
1190 if public_names:
1191 if len(public_names) == 1:
1192 self.writeline('context.exported_vars.add(%r)' %
1193 public_names[0])
1194 else:
1195 self.writeline('context.exported_vars.update((%s))' %
1196 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001197
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001198 # -- Expression Visitors
1199
Armin Ronachere791c2a2008-04-07 18:39:54 +02001200 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001201 if node.ctx == 'store' and frame.toplevel:
1202 frame.assigned_names.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001203 self.write('l_' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001204
1205 def visit_Const(self, node, frame):
1206 val = node.value
1207 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001208 self.write(str(val))
1209 else:
1210 self.write(repr(val))
1211
Armin Ronacher5411ce72008-05-25 11:36:22 +02001212 def visit_TemplateData(self, node, frame):
1213 self.write(repr(node.as_const()))
1214
Armin Ronacher8efc5222008-04-08 14:47:40 +02001215 def visit_Tuple(self, node, frame):
1216 self.write('(')
1217 idx = -1
1218 for idx, item in enumerate(node.items):
1219 if idx:
1220 self.write(', ')
1221 self.visit(item, frame)
1222 self.write(idx == 0 and ',)' or ')')
1223
Armin Ronacher8edbe492008-04-10 20:43:43 +02001224 def visit_List(self, node, frame):
1225 self.write('[')
1226 for idx, item in enumerate(node.items):
1227 if idx:
1228 self.write(', ')
1229 self.visit(item, frame)
1230 self.write(']')
1231
1232 def visit_Dict(self, node, frame):
1233 self.write('{')
1234 for idx, item in enumerate(node.items):
1235 if idx:
1236 self.write(', ')
1237 self.visit(item.key, frame)
1238 self.write(': ')
1239 self.visit(item.value, frame)
1240 self.write('}')
1241
Armin Ronachere791c2a2008-04-07 18:39:54 +02001242 def binop(operator):
1243 def visitor(self, node, frame):
1244 self.write('(')
1245 self.visit(node.left, frame)
1246 self.write(' %s ' % operator)
1247 self.visit(node.right, frame)
1248 self.write(')')
1249 return visitor
1250
1251 def uaop(operator):
1252 def visitor(self, node, frame):
1253 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001254 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001255 self.write(')')
1256 return visitor
1257
1258 visit_Add = binop('+')
1259 visit_Sub = binop('-')
1260 visit_Mul = binop('*')
1261 visit_Div = binop('/')
1262 visit_FloorDiv = binop('//')
1263 visit_Pow = binop('**')
1264 visit_Mod = binop('%')
1265 visit_And = binop('and')
1266 visit_Or = binop('or')
1267 visit_Pos = uaop('+')
1268 visit_Neg = uaop('-')
1269 visit_Not = uaop('not ')
1270 del binop, uaop
1271
Armin Ronacherd1342312008-04-28 12:20:12 +02001272 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001273 self.write('%s((' % (self.environment.autoescape and
1274 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001275 for arg in node.nodes:
1276 self.visit(arg, frame)
1277 self.write(', ')
1278 self.write('))')
1279
Armin Ronachere791c2a2008-04-07 18:39:54 +02001280 def visit_Compare(self, node, frame):
1281 self.visit(node.expr, frame)
1282 for op in node.ops:
1283 self.visit(op, frame)
1284
1285 def visit_Operand(self, node, frame):
1286 self.write(' %s ' % operators[node.op])
1287 self.visit(node.expr, frame)
1288
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001289 def visit_Getattr(self, node, frame):
1290 self.write('environment.getattr(')
1291 self.visit(node.node, frame)
1292 self.write(', %r)' % node.attr)
1293
1294 def visit_Getitem(self, node, frame):
Armin Ronacherb9388772008-06-25 20:43:18 +02001295 # slices or integer subscriptions bypass the getitem
Armin Ronacher08a6a3b2008-05-13 15:35:47 +02001296 # method if we can determine that at compile time.
1297 if isinstance(node.arg, nodes.Slice) or \
1298 (isinstance(node.arg, nodes.Const) and
1299 isinstance(node.arg.value, (int, long))):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001300 self.visit(node.node, frame)
1301 self.write('[')
1302 self.visit(node.arg, frame)
1303 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001304 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001305 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001306 self.visit(node.node, frame)
1307 self.write(', ')
1308 self.visit(node.arg, frame)
1309 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001310
1311 def visit_Slice(self, node, frame):
1312 if node.start is not None:
1313 self.visit(node.start, frame)
1314 self.write(':')
1315 if node.stop is not None:
1316 self.visit(node.stop, frame)
1317 if node.step is not None:
1318 self.write(':')
1319 self.visit(node.step, frame)
1320
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001321 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001322 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001323 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001324 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001325 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001326 if getattr(func, 'contextfilter', False):
1327 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001328 elif getattr(func, 'environmentfilter', False):
1329 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001330
1331 # if the filter node is None we are inside a filter block
1332 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001333 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001334 self.visit(node.node, frame)
Armin Ronacher3da90312008-05-23 16:37:28 +02001335 elif self.environment.autoescape:
1336 self.write('Markup(concat(%s))' % frame.buffer)
1337 else:
1338 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001339 self.signature(node, frame)
1340 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001341
1342 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001343 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001344 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001345 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001346 self.visit(node.node, frame)
1347 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001348 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001349
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001350 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001351 def write_expr2():
1352 if node.expr2 is not None:
1353 return self.visit(node.expr2, frame)
1354 self.write('environment.undefined(%r)' % ('the inline if-'
1355 'expression on %s evaluated to false and '
1356 'no else section was defined.' % self.position(node)))
1357
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001358 if not have_condexpr:
1359 self.write('((')
1360 self.visit(node.test, frame)
1361 self.write(') and (')
1362 self.visit(node.expr1, frame)
1363 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001364 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001365 self.write(',))[0]')
1366 else:
1367 self.write('(')
1368 self.visit(node.expr1, frame)
1369 self.write(' if ')
1370 self.visit(node.test, frame)
1371 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001372 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001373 self.write(')')
1374
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001375 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001376 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001377 self.write('environment.call(context, ')
1378 else:
1379 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001380 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001381 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001382 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001383 self.write(')')
1384
1385 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001386 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001387 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001388
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001389 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001390
1391 def visit_MarkSafe(self, node, frame):
1392 self.write('Markup(')
1393 self.visit(node.expr, frame)
1394 self.write(')')
1395
1396 def visit_EnvironmentAttribute(self, node, frame):
1397 self.write('environment.' + node.name)
1398
1399 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001400 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001401
1402 def visit_ImportedName(self, node, frame):
1403 self.write(self.import_aliases[node.importname])
1404
1405 def visit_InternalName(self, node, frame):
1406 self.write(node.name)
1407
Armin Ronacher6df604e2008-05-23 22:18:38 +02001408 def visit_ContextReference(self, node, frame):
1409 self.write('context')
1410
Armin Ronachered1e0d42008-05-18 20:25:28 +02001411 def visit_Continue(self, node, frame):
1412 self.writeline('continue', node)
1413
1414 def visit_Break(self, node, frame):
1415 self.writeline('break', node)