blob: 6518427d2fddcdf1142d0cba7e92a21720f3a4d6 [file] [log] [blame]
Armin Ronachere791c2a2008-04-07 18:39:54 +02001# -*- coding: utf-8 -*-
2"""
3 jinja2.compiler
4 ~~~~~~~~~~~~~~~
5
6 Compiles nodes into python code.
7
8 :copyright: Copyright 2008 by Armin Ronacher.
9 :license: GNU GPL.
10"""
Armin Ronacher32a910f2008-04-26 23:21:03 +020011from time import time
Armin Ronacher8efc5222008-04-08 14:47:40 +020012from copy import copy
Armin Ronachere791c2a2008-04-07 18:39:54 +020013from random import randrange
Armin Ronacher2feed1d2008-04-26 16:26:52 +020014from keyword import iskeyword
Armin Ronachere791c2a2008-04-07 18:39:54 +020015from cStringIO import StringIO
Armin Ronacherd1ff8582008-05-11 00:30:43 +020016from itertools import chain
Armin Ronachere791c2a2008-04-07 18:39:54 +020017from jinja2 import nodes
18from jinja2.visitor import NodeVisitor, NodeTransformer
19from jinja2.exceptions import TemplateAssertionError
Armin Ronacher7ceced52008-05-03 10:15:31 +020020from jinja2.utils import Markup, concat
Armin Ronachere791c2a2008-04-07 18:39:54 +020021
22
23operators = {
24 'eq': '==',
25 'ne': '!=',
26 'gt': '>',
27 'gteq': '>=',
28 'lt': '<',
29 'lteq': '<=',
30 'in': 'in',
31 'notin': 'not in'
32}
33
Armin Ronacher3d8b7842008-04-13 13:16:50 +020034try:
35 exec '(0 if 0 else 0)'
36except SyntaxError:
37 have_condexpr = False
38else:
39 have_condexpr = True
40
41
Armin Ronacher8e8d0712008-04-16 23:10:49 +020042def generate(node, environment, name, filename, stream=None):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020043 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020044 if not isinstance(node, nodes.Template):
45 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher8e8d0712008-04-16 23:10:49 +020046 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020047 generator.visit(node)
48 if stream is None:
49 return generator.stream.getvalue()
50
51
Armin Ronacher4dfc9752008-04-09 15:03:29 +020052def has_safe_repr(value):
53 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020054 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020055 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020056 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher32a910f2008-04-26 23:21:03 +020057 xrange, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020058 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020059 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020060 for item in value:
61 if not has_safe_repr(item):
62 return False
63 return True
64 elif isinstance(value, dict):
65 for key, value in value.iteritems():
66 if not has_safe_repr(key):
67 return False
68 if not has_safe_repr(value):
69 return False
70 return True
71 return False
72
73
Armin Ronacherc9705c22008-04-27 21:28:03 +020074def find_undeclared(nodes, names):
75 """Check if the names passed are accessed undeclared. The return value
76 is a set of all the undeclared names from the sequence of names found.
77 """
78 visitor = UndeclaredNameVisitor(names)
79 try:
80 for node in nodes:
81 visitor.visit(node)
82 except VisitorExit:
83 pass
84 return visitor.undeclared
85
86
Armin Ronachere791c2a2008-04-07 18:39:54 +020087class Identifiers(object):
88 """Tracks the status of identifiers in frames."""
89
90 def __init__(self):
91 # variables that are known to be declared (probably from outer
92 # frames or because they are special for the frame)
93 self.declared = set()
94
Armin Ronacher10f3ba22008-04-18 11:30:37 +020095 # undeclared variables from outer scopes
96 self.outer_undeclared = set()
97
Armin Ronachere791c2a2008-04-07 18:39:54 +020098 # names that are accessed without being explicitly declared by
99 # this one or any of the outer scopes. Names can appear both in
100 # declared and undeclared.
101 self.undeclared = set()
102
103 # names that are declared locally
104 self.declared_locally = set()
105
106 # names that are declared by parameters
107 self.declared_parameter = set()
108
109 def add_special(self, name):
110 """Register a special name like `loop`."""
111 self.undeclared.discard(name)
112 self.declared.add(name)
113
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200114 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200115 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200116 if name in self.declared_locally or name in self.declared_parameter:
117 return True
118 if local_only:
119 return False
120 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200121
122 def find_shadowed(self):
123 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200124 return (self.declared | self.outer_undeclared) & \
125 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200126
127
128class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200129 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200130
131 def __init__(self, parent=None):
132 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200133
Armin Ronacher75cfb862008-04-11 13:47:22 +0200134 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200135 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200136
Armin Ronacher75cfb862008-04-11 13:47:22 +0200137 # the root frame is basically just the outermost frame, so no if
138 # conditions. This information is used to optimize inheritance
139 # situations.
140 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200141
142 # inside some tags we are using a buffer rather than yield statements.
143 # this for example affects {% filter %} or {% macro %}. If a frame
144 # is buffered this variable points to the name of the list used as
145 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200146 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200147
Armin Ronacherfed44b52008-04-13 19:42:53 +0200148 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200149 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200150
151 # the parent of this frame
152 self.parent = parent
153
Armin Ronachere791c2a2008-04-07 18:39:54 +0200154 if parent is not None:
155 self.identifiers.declared.update(
156 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200157 parent.identifiers.declared_locally |
158 parent.identifiers.declared_parameter
159 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200160 self.identifiers.outer_undeclared.update(
161 parent.identifiers.undeclared -
162 self.identifiers.declared
163 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200164 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200165
Armin Ronacher8efc5222008-04-08 14:47:40 +0200166 def copy(self):
167 """Create a copy of the current one."""
168 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200169 rv.identifiers = copy(self.identifiers)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200170 return rv
171
Armin Ronacherc9705c22008-04-27 21:28:03 +0200172 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200173 """Walk the node and check for identifiers. If the scope is hard (eg:
174 enforce on a python level) overrides from outer scopes are tracked
175 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200176 """
177 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200178 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200179 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200180
181 def inner(self):
182 """Return an inner frame."""
183 return Frame(self)
184
Armin Ronacher75cfb862008-04-11 13:47:22 +0200185 def soft(self):
186 """Return a soft frame. A soft frame may not be modified as
187 standalone thing as it shares the resources with the frame it
188 was created of, but it's not a rootlevel frame any longer.
189 """
190 rv = copy(self)
191 rv.rootlevel = False
192 return rv
193
Armin Ronachere791c2a2008-04-07 18:39:54 +0200194
Armin Ronacherc9705c22008-04-27 21:28:03 +0200195class VisitorExit(RuntimeError):
196 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
197
198
199class DependencyFinderVisitor(NodeVisitor):
200 """A visitor that collects filter and test calls."""
201
202 def __init__(self):
203 self.filters = set()
204 self.tests = set()
205
206 def visit_Filter(self, node):
207 self.generic_visit(node)
208 self.filters.add(node.name)
209
210 def visit_Test(self, node):
211 self.generic_visit(node)
212 self.tests.add(node.name)
213
214 def visit_Block(self, node):
215 """Stop visiting at blocks."""
216
217
218class UndeclaredNameVisitor(NodeVisitor):
219 """A visitor that checks if a name is accessed without being
220 declared. This is different from the frame visitor as it will
221 not stop at closure frames.
222 """
223
224 def __init__(self, names):
225 self.names = set(names)
226 self.undeclared = set()
227
228 def visit_Name(self, node):
229 if node.ctx == 'load' and node.name in self.names:
230 self.undeclared.add(node.name)
231 if self.undeclared == self.names:
232 raise VisitorExit()
233 else:
234 self.names.discard(node.name)
235
236 def visit_Block(self, node):
237 """Stop visiting a blocks."""
238
239
Armin Ronachere791c2a2008-04-07 18:39:54 +0200240class FrameIdentifierVisitor(NodeVisitor):
241 """A visitor for `Frame.inspect`."""
242
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200243 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200244 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200245 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200246
Armin Ronacherc9705c22008-04-27 21:28:03 +0200247 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200248 """All assignments to names go through this function."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200249 if node.ctx in ('store', 'param'):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200250 self.identifiers.declared_locally.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200251 elif node.ctx == 'load' and not \
252 self.identifiers.is_declared(node.name, self.hard_scope):
253 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200254
Armin Ronacherc9705c22008-04-27 21:28:03 +0200255 def visit_Macro(self, node):
256 self.generic_visit(node)
257 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200258
Armin Ronacherc9705c22008-04-27 21:28:03 +0200259 def visit_Import(self, node):
260 self.generic_visit(node)
261 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200262
Armin Ronacherc9705c22008-04-27 21:28:03 +0200263 def visit_FromImport(self, node):
264 self.generic_visit(node)
265 for name in node.names:
266 if isinstance(name, tuple):
267 self.identifiers.declared_locally.add(name[1])
268 else:
269 self.identifiers.declared_locally.add(name)
270
271 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200272 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200273 self.visit(node.node)
274 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200275
Armin Ronacherc9705c22008-04-27 21:28:03 +0200276 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200277 """Visiting stops at for blocks. However the block sequence
278 is visited as part of the outer scope.
279 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200280 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200281
Armin Ronacherc9705c22008-04-27 21:28:03 +0200282 def visit_CallBlock(self, node):
283 for child in node.iter_child_nodes(exclude=('body',)):
284 self.visit(child)
285
286 def visit_FilterBlock(self, node):
287 self.visit(node.filter)
288
289 def visit_Block(self, node):
290 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200291
292
Armin Ronacher75cfb862008-04-11 13:47:22 +0200293class CompilerExit(Exception):
294 """Raised if the compiler encountered a situation where it just
295 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200296 raises such an exception is not further processed.
297 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200298
299
Armin Ronachere791c2a2008-04-07 18:39:54 +0200300class CodeGenerator(NodeVisitor):
301
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200302 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200303 if stream is None:
304 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200305 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200306 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200307 self.filename = filename
308 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200309
Armin Ronacher023b5e92008-05-08 11:03:10 +0200310 # aliases for imports
311 self.import_aliases = {}
312
Armin Ronacherfed44b52008-04-13 19:42:53 +0200313 # a registry for all blocks. Because blocks are moved out
314 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200315 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200316
317 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200318 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200319
320 # some templates have a rootlevel extends. In this case we
321 # can safely assume that we're a child template and do some
322 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200323 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200324
Armin Ronacherba3757b2008-04-16 19:43:16 +0200325 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200326 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200327
Armin Ronacherb9e78752008-05-10 23:36:28 +0200328 # registry of all filters and tests (global, not block local)
329 self.tests = {}
330 self.filters = {}
331
Armin Ronacherba3757b2008-04-16 19:43:16 +0200332 # the debug information
333 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200334 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200335
Armin Ronacherfed44b52008-04-13 19:42:53 +0200336 # the number of new lines before the next write()
337 self._new_lines = 0
338
339 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200340 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200341
342 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200343 self._first_write = True
344
Armin Ronacherfed44b52008-04-13 19:42:53 +0200345 # used by the `temporary_identifier` method to get new
346 # unique, temporary identifier
347 self._last_identifier = 0
348
349 # the current indentation
350 self._indentation = 0
351
Armin Ronachere791c2a2008-04-07 18:39:54 +0200352 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200353 """Get a new unique identifier."""
354 self._last_identifier += 1
355 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200356
357 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200358 """Indent by one."""
359 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200360
Armin Ronacher8efc5222008-04-08 14:47:40 +0200361 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200362 """Outdent by step."""
363 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200364
Armin Ronacherc9705c22008-04-27 21:28:03 +0200365 def blockvisit(self, nodes, frame, force_generator=True):
366 """Visit a list of nodes as block in a frame. If the current frame
367 is no buffer a dummy ``if 0: yield None`` is written automatically
368 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200369 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200370 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200371 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200372 try:
373 for node in nodes:
374 self.visit(node, frame)
375 except CompilerExit:
376 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200377
378 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200379 """Write a string into the output stream."""
380 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200381 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200382 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200383 self.code_lineno += self._new_lines
384 if self._write_debug_info is not None:
385 self.debug_info.append((self._write_debug_info,
386 self.code_lineno))
387 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200388 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200389 self.stream.write(' ' * self._indentation)
390 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200391 self.stream.write(x)
392
393 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200394 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200395 self.newline(node, extra)
396 self.write(x)
397
398 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200399 """Add one or more newlines before the next write."""
400 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200401 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200402 self._write_debug_info = node.lineno
403 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200404
Armin Ronacher71082072008-04-12 14:19:36 +0200405 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200406 """Writes a function call to the stream for the current node.
407 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200408 disabled by setting have_comma to False. The extra keyword
409 arguments may not include python keywords otherwise a syntax
410 error could occour. The extra keyword arguments should be given
411 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200412 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200413 have_comma = have_comma and [True] or []
414 def touch_comma():
415 if have_comma:
416 self.write(', ')
417 else:
418 have_comma.append(True)
419
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200420 # if any of the given keyword arguments is a python keyword
421 # we have to make sure that no invalid call is created.
422 kwarg_workaround = False
423 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
424 if iskeyword(kwarg):
425 kwarg_workaround = True
426 break
427
Armin Ronacher8efc5222008-04-08 14:47:40 +0200428 for arg in node.args:
429 touch_comma()
430 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200431
432 if not kwarg_workaround:
433 for kwarg in node.kwargs:
434 touch_comma()
435 self.visit(kwarg, frame)
436 if extra_kwargs is not None:
437 for key, value in extra_kwargs.iteritems():
438 touch_comma()
439 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200440 if node.dyn_args:
441 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200442 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200443 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200444
445 if kwarg_workaround:
446 touch_comma()
447 if node.dyn_kwargs is not None:
448 self.write('**dict({')
449 else:
450 self.write('**{')
451 for kwarg in node.kwargs:
452 self.write('%r: ' % kwarg.key)
453 self.visit(kwarg.value, frame)
454 self.write(', ')
455 if extra_kwargs is not None:
456 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200457 self.write('%r: %s, ' % (key, value))
458 if node.dyn_kwargs is not None:
459 self.write('}, **')
460 self.visit(node.dyn_kwargs, frame)
461 self.write(')')
462 else:
463 self.write('}')
464
465 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200466 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200467 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200468 self.visit(node.dyn_kwargs, frame)
469
Armin Ronacherc9705c22008-04-27 21:28:03 +0200470 def pull_locals(self, frame):
471 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200472 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200473 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200474
475 def pull_dependencies(self, nodes):
476 """Pull all the dependencies."""
477 visitor = DependencyFinderVisitor()
478 for node in nodes:
479 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200480 for dependency in 'filters', 'tests':
481 mapping = getattr(self, dependency)
482 for name in getattr(visitor, dependency):
483 if name not in mapping:
484 mapping[name] = self.temporary_identifier()
485 self.writeline('%s = environment.%s[%r]' %
486 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200487
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200488 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200489 """This function returns all the shadowed variables in a dict
490 in the form name: alias and will write the required assignments
491 into the current scope. No indentation takes place.
492 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200493 # make sure we "backup" overridden, local identifiers
494 # TODO: we should probably optimize this and check if the
495 # identifier is in use afterwards.
496 aliases = {}
497 for name in frame.identifiers.find_shadowed():
498 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200499 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200500 return aliases
501
Armin Ronacherc9705c22008-04-27 21:28:03 +0200502 def function_scoping(self, node, frame, children=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200503 """In Jinja a few statements require the help of anonymous
504 functions. Those are currently macros and call blocks and in
505 the future also recursive loops. As there is currently
506 technical limitation that doesn't allow reading and writing a
507 variable in a scope where the initial value is coming from an
508 outer scope, this function tries to fall back with a common
509 error message. Additionally the frame passed is modified so
510 that the argumetns are collected and callers are looked up.
511
512 This will return the modified frame.
513 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200514 # we have to iterate twice over it, make sure that works
515 if children is None:
516 children = node.iter_child_nodes()
517 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200518 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200519 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200520
521 # variables that are undeclared (accessed before declaration) and
522 # declared locally *and* part of an outside scope raise a template
523 # assertion error. Reason: we can't generate reasonable code from
524 # it without aliasing all the variables. XXX: alias them ^^
525 overriden_closure_vars = (
526 func_frame.identifiers.undeclared &
527 func_frame.identifiers.declared &
528 (func_frame.identifiers.declared_locally |
529 func_frame.identifiers.declared_parameter)
530 )
531 if overriden_closure_vars:
532 vars = ', '.join(sorted(overriden_closure_vars))
533 raise TemplateAssertionError('It\'s not possible to set and '
534 'access variables derived from '
535 'an outer scope! (affects: %s' %
Armin Ronacher68f77672008-04-17 11:50:39 +0200536 vars, node.lineno, self.name)
Armin Ronacher71082072008-04-12 14:19:36 +0200537
538 # remove variables from a closure from the frame's undeclared
539 # identifiers.
540 func_frame.identifiers.undeclared -= (
541 func_frame.identifiers.undeclared &
542 func_frame.identifiers.declared
543 )
544
Armin Ronacher963f97d2008-04-25 11:44:59 +0200545 func_frame.accesses_kwargs = False
546 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200547 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200548 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200549
Armin Ronacherc9705c22008-04-27 21:28:03 +0200550 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
551
552 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200553 func_frame.accesses_caller = True
554 func_frame.identifiers.add_special('caller')
555 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200556 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200557 func_frame.accesses_kwargs = True
558 func_frame.identifiers.add_special('kwargs')
559 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200560 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200561 func_frame.accesses_varargs = True
562 func_frame.identifiers.add_special('varargs')
563 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200564 return func_frame
565
Armin Ronachere791c2a2008-04-07 18:39:54 +0200566 # -- Visitors
567
568 def visit_Template(self, node, frame=None):
569 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200570 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200571 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200572 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8edbe492008-04-10 20:43:43 +0200573
Armin Ronacher75cfb862008-04-11 13:47:22 +0200574 # do we have an extends tag at all? If not, we can save some
575 # overhead by just not processing any inheritance code.
576 have_extends = node.find(nodes.Extends) is not None
577
Armin Ronacher8edbe492008-04-10 20:43:43 +0200578 # find all blocks
579 for block in node.find_all(nodes.Block):
580 if block.name in self.blocks:
581 raise TemplateAssertionError('block %r defined twice' %
582 block.name, block.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200583 self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200584 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200585
Armin Ronacher023b5e92008-05-08 11:03:10 +0200586 # find all imports and import them
587 for import_ in node.find_all(nodes.ImportedName):
588 if import_.importname not in self.import_aliases:
589 imp = import_.importname
590 self.import_aliases[imp] = alias = self.temporary_identifier()
591 if '.' in imp:
592 module, obj = imp.rsplit('.', 1)
593 self.writeline('from %s import %s as %s' %
594 (module, obj, alias))
595 else:
596 self.writeline('import %s as %s' % (imp, alias))
597
598 # add the load name
599 self.writeline('name = %r' % self.name)
600
Armin Ronacher8efc5222008-04-08 14:47:40 +0200601 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200602 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200603
604 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200605 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200606 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200607 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200608 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200609 if have_extends:
610 self.writeline('parent_template = None')
611 self.pull_locals(frame)
612 self.pull_dependencies(node.body)
613 if 'self' in find_undeclared(node.body, ('self',)):
614 frame.identifiers.add_special('self')
615 self.writeline('l_self = TemplateReference(context)')
616 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200617 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200618
Armin Ronacher8efc5222008-04-08 14:47:40 +0200619 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200620 if have_extends:
621 if not self.has_known_extends:
622 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200623 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200624 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200625 self.writeline('for event in parent_template.'
626 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200627 self.indent()
628 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200629 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200630
631 # at this point we now have the blocks collected and can visit them too.
632 for name, block in self.blocks.iteritems():
633 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200634 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200635 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200636 self.writeline('def block_%s(context, environment=environment):'
637 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200638 self.indent()
639 undeclared = find_undeclared(block.body, ('self', 'super'))
640 if 'self' in undeclared:
641 block_frame.identifiers.add_special('self')
642 self.writeline('l_self = TemplateReference(context)')
643 if 'super' in undeclared:
644 block_frame.identifiers.add_special('super')
645 self.writeline('l_super = context.super(%r, '
646 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200647 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200648 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200649 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200650 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200651
Armin Ronacher75cfb862008-04-11 13:47:22 +0200652 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200653 for x in self.blocks),
654 extra=1)
655
656 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200657 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
658 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200659
Armin Ronachere791c2a2008-04-07 18:39:54 +0200660 def visit_Block(self, node, frame):
661 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200662 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200663 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200664 # if we know that we are a child template, there is no need to
665 # check if we are one
666 if self.has_known_extends:
667 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200668 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200669 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200670 self.indent()
671 level += 1
Armin Ronacherc9705c22008-04-27 21:28:03 +0200672 self.writeline('for event in context.blocks[%r][-1](context):' %
673 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200674 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200675 if frame.buffer is None:
676 self.writeline('yield event')
677 else:
678 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200679 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200680
681 def visit_Extends(self, node, frame):
682 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200683 if not frame.toplevel:
684 raise TemplateAssertionError('cannot use extend from a non '
685 'top-level scope', node.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200686 self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200687
Armin Ronacher7fb38972008-04-11 13:54:28 +0200688 # if the number of extends statements in general is zero so
689 # far, we don't have to add a check if something extended
690 # the template before this one.
691 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200692
Armin Ronacher7fb38972008-04-11 13:54:28 +0200693 # if we have a known extends we just add a template runtime
694 # error into the generated code. We could catch that at compile
695 # time too, but i welcome it not to confuse users by throwing the
696 # same error at different times just "because we can".
697 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200698 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200699 self.indent()
700 self.writeline('raise TemplateRuntimeError(%r)' %
701 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200702
Armin Ronacher7fb38972008-04-11 13:54:28 +0200703 # if we have a known extends already we don't need that code here
704 # as we know that the template execution will end here.
705 if self.has_known_extends:
706 raise CompilerExit()
707 self.outdent()
708
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200709 self.writeline('parent_template = environment.get_template(', node, 1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200710 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200711 self.write(', %r)' % self.name)
712 self.writeline('for name, parent_block in parent_template.'
713 'blocks.iteritems():')
714 self.indent()
715 self.writeline('context.blocks.setdefault(name, []).'
716 'insert(0, parent_block)')
717 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200718
719 # if this extends statement was in the root level we can take
720 # advantage of that information and simplify the generated code
721 # in the top level from this point onwards
722 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200723
Armin Ronacher7fb38972008-04-11 13:54:28 +0200724 # and now we have one more
725 self.extends_so_far += 1
726
Armin Ronacherf059ec12008-04-11 22:21:00 +0200727 def visit_Include(self, node, frame):
728 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200729 if node.with_context:
730 self.writeline('template = environment.get_template(', node)
731 self.visit(node.template, frame)
732 self.write(', %r)' % self.name)
733 self.writeline('for event in template.root_render_func('
734 'template.new_context(context.parent, True)):')
735 else:
736 self.writeline('for event in environment.get_template(', node)
737 self.visit(node.template, frame)
738 self.write(', %r).module._TemplateModule__body_stream:' %
739 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200740 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200741 if frame.buffer is None:
742 self.writeline('yield event')
743 else:
744 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200745 self.outdent()
746
Armin Ronacher0611e492008-04-25 23:44:14 +0200747 def visit_Import(self, node, frame):
748 """Visit regular imports."""
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200749 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200750 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200751 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200752 self.write('environment.get_template(')
753 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200754 self.write(', %r).' % self.name)
755 if node.with_context:
756 self.write('make_module(context.parent, True)')
757 else:
758 self.write('module')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200759 if frame.toplevel and not node.target.startswith('__'):
Armin Ronacher53042292008-04-26 18:30:19 +0200760 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200761
762 def visit_FromImport(self, node, frame):
763 """Visit named imports."""
764 self.newline(node)
765 self.write('included_template = environment.get_template(')
766 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200767 self.write(', %r).' % self.name)
768 if node.with_context:
769 self.write('make_module(context.parent, True)')
770 else:
771 self.write('module')
Armin Ronacher0611e492008-04-25 23:44:14 +0200772 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200773 if isinstance(name, tuple):
774 name, alias = name
775 else:
776 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200777 self.writeline('l_%s = getattr(included_template, '
778 '%r, missing)' % (alias, name))
779 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200780 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200781 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200782 'included_template.name, '
783 'name=included_template.name)' %
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200784 (alias, 'the template %r does not export '
785 'the requested name ' + repr(name)))
Armin Ronacher0611e492008-04-25 23:44:14 +0200786 self.outdent()
787 if frame.toplevel:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200788 self.writeline('context.vars[%r] = l_%s' % (alias, alias))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200789 if not alias.startswith('__'):
790 self.writeline('context.exported_vars.discard(%r)' % alias)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200791
Armin Ronachere791c2a2008-04-07 18:39:54 +0200792 def visit_For(self, node, frame):
793 loop_frame = frame.inner()
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200794 loop_frame.inspect(node.iter_child_nodes(exclude=('iter',)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200795 extended_loop = bool(node.else_) or \
796 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200797 if extended_loop:
798 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200799
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200800 aliases = self.collect_shadowed(loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200801 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200802 if node.else_:
803 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200804
805 self.newline(node)
806 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200807 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200808 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200809
810 # the expression pointing to the parent loop. We make the
811 # undefined a bit more debug friendly at the same time.
812 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200813 or "environment.undefined(%r, name='loop')" % "'loop' " \
814 'is undefined. "the filter section of a loop as well ' \
815 'as the else block doesn\'t have access to the ' \
816 "special 'loop' variable of the current loop. " \
817 "Because there is no parent loop it's undefined."
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200818
819 # if we have an extened loop and a node test, we filter in the
820 # "outer frame".
821 if extended_loop and node.test is not None:
822 self.write('(')
823 self.visit(node.target, loop_frame)
824 self.write(' for ')
825 self.visit(node.target, loop_frame)
826 self.write(' in ')
827 self.visit(node.iter, loop_frame)
828 self.write(' if (')
829 test_frame = loop_frame.copy()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200830 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200831 self.visit(node.test, test_frame)
832 self.write('))')
833
834 else:
835 self.visit(node.iter, loop_frame)
836
Armin Ronachere791c2a2008-04-07 18:39:54 +0200837 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200838
839 # tests in not extended loops become a continue
840 if not extended_loop and node.test is not None:
841 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200842 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200843 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200844 self.write(':')
845 self.indent()
846 self.writeline('continue')
847 self.outdent(2)
848
Armin Ronacherc9705c22008-04-27 21:28:03 +0200849 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200850 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200851 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200852
853 if node.else_:
854 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200855 self.indent()
856 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher625215e2008-04-13 16:31:08 +0200857 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200858 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200859
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200860 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200861 for name, alias in aliases.iteritems():
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200862 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200863
864 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200865 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200866 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200867 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200868 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200869 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200870 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200871 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200872 if node.else_:
873 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200874 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200875 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200876 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200877
Armin Ronacher8efc5222008-04-08 14:47:40 +0200878 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200879 macro_frame = self.function_scoping(node, frame)
880 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200881 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200882 macro_frame.buffer = buf = self.temporary_identifier()
883 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200884 self.pull_locals(macro_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200885 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200886 self.blockvisit(node.body, macro_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200887 if self.environment.autoescape:
888 self.writeline('return Markup(concat(%s))' % buf)
889 else:
890 self.writeline("return concat(%s)" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200891 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200892 self.newline()
893 if frame.toplevel:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200894 if not node.name.startswith('__'):
895 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +0200896 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200897 arg_tuple = ', '.join(repr(x.name) for x in node.args)
898 if len(node.args) == 1:
899 arg_tuple += ','
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200900 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
901 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200902 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200903 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200904 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200905 self.write('), %s, %s, %s)' % (
906 macro_frame.accesses_kwargs and '1' or '0',
907 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200908 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200909 ))
910
911 def visit_CallBlock(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200912 call_frame = self.function_scoping(node, frame, node.iter_child_nodes
913 (exclude=('call',)))
Armin Ronacher71082072008-04-12 14:19:36 +0200914 args = call_frame.arguments
915 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200916 call_frame.buffer = buf = self.temporary_identifier()
917 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200918 self.pull_locals(call_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200919 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200920 self.blockvisit(node.body, call_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200921 if self.environment.autoescape:
922 self.writeline("return Markup(concat(%s))" % buf)
923 else:
924 self.writeline('return concat(%s)' % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200925 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200926 arg_tuple = ', '.join(repr(x.name) for x in node.args)
927 if len(node.args) == 1:
928 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200929 self.writeline('caller = Macro(environment, call, None, (%s), (' %
930 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200931 for arg in node.defaults:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200932 self.visit(arg, call_frame)
Armin Ronacher71082072008-04-12 14:19:36 +0200933 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200934 self.write('), %s, %s, 0)' % (
935 call_frame.accesses_kwargs and '1' or '0',
936 call_frame.accesses_varargs and '1' or '0'
937 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200938 if frame.buffer is None:
939 self.writeline('yield ', node)
940 else:
941 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200942 self.visit_Call(node.call, call_frame,
943 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200944 if frame.buffer is not None:
945 self.write(')')
946
947 def visit_FilterBlock(self, node, frame):
948 filter_frame = frame.inner()
949 filter_frame.inspect(node.iter_child_nodes())
950
951 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200952 self.pull_locals(filter_frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200953 filter_frame.buffer = buf = self.temporary_identifier()
954
955 self.writeline('%s = []' % buf, node)
956 for child in node.body:
957 self.visit(child, filter_frame)
958
959 if frame.buffer is None:
960 self.writeline('yield ', node)
961 else:
962 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200963 self.visit_Filter(node.filter, filter_frame, 'concat(%s)' % buf)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200964 if frame.buffer is not None:
965 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200966
Armin Ronachere791c2a2008-04-07 18:39:54 +0200967 def visit_ExprStmt(self, node, frame):
968 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +0200969 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200970
971 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200972 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +0200973 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200974 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200975
Armin Ronacher75cfb862008-04-11 13:47:22 +0200976 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200977
Armin Ronacher7fb38972008-04-11 13:54:28 +0200978 # if we are in the toplevel scope and there was already an extends
979 # statement we have to add a check that disables our yield(s) here
980 # so that they don't appear in the output.
981 outdent_later = False
982 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200983 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200984 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200985 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +0200986
Armin Ronachere791c2a2008-04-07 18:39:54 +0200987 # try to evaluate as many chunks as possible into a static
988 # string at compile time.
989 body = []
990 for child in node.nodes:
991 try:
992 const = unicode(child.as_const())
993 except:
994 body.append(child)
995 continue
996 if body and isinstance(body[-1], list):
997 body[-1].append(const)
998 else:
999 body.append([const])
1000
Armin Ronacher32a910f2008-04-26 23:21:03 +02001001 # if we have less than 3 nodes or less than 6 and a buffer we
1002 # yield or extend
1003 if len(body) < 3 or (frame.buffer is not None and len(body) < 6):
1004 if frame.buffer is not None:
1005 self.writeline('%s.extend((' % frame.buffer)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001006 for item in body:
1007 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001008 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001009 if frame.buffer is None:
1010 self.writeline('yield ' + val)
1011 else:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001012 self.write(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001013 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001014 if frame.buffer is None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001015 self.writeline('yield ')
Armin Ronacherd1342312008-04-28 12:20:12 +02001016 close = 1
1017 if self.environment.autoescape:
1018 self.write('escape(')
1019 else:
1020 self.write('unicode(')
1021 if self.environment.finalize is not None:
1022 self.write('environment.finalize(')
1023 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001024 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001025 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001026 if frame.buffer is not None:
1027 self.write(', ')
1028 if frame.buffer is not None:
1029 self.write('))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001030
1031 # otherwise we create a format string as this is faster in that case
1032 else:
1033 format = []
1034 arguments = []
1035 for item in body:
1036 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001037 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001038 else:
1039 format.append('%s')
1040 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001041 if frame.buffer is None:
1042 self.writeline('yield ')
1043 else:
1044 self.writeline('%s.append(' % frame.buffer)
Armin Ronacherde6bf712008-04-26 01:44:14 +02001045 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001046 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001047 self.indent()
1048 for argument in arguments:
1049 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001050 close = 0
1051 if self.environment.autoescape:
1052 self.write('escape(')
1053 close += 1
1054 if self.environment.finalize is not None:
1055 self.write('environment.finalize(')
1056 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001057 self.visit(argument, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001058 self.write(')' * close + ',')
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001059 self.outdent()
1060 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001061 if frame.buffer is not None:
1062 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001063
Armin Ronacher7fb38972008-04-11 13:54:28 +02001064 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001065 self.outdent()
1066
Armin Ronacher8efc5222008-04-08 14:47:40 +02001067 def visit_Assign(self, node, frame):
1068 self.newline(node)
1069 # toplevel assignments however go into the local namespace and
1070 # the current template's context. We create a copy of the frame
1071 # here and add a set so that the Name visitor can add the assigned
1072 # names here.
1073 if frame.toplevel:
1074 assignment_frame = frame.copy()
1075 assignment_frame.assigned_names = set()
1076 else:
1077 assignment_frame = frame
1078 self.visit(node.target, assignment_frame)
1079 self.write(' = ')
1080 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001081
1082 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001083 if frame.toplevel:
1084 for name in assignment_frame.assigned_names:
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001085 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +02001086 if not name.startswith('__'):
1087 self.writeline('context.exported_vars.add(%r)' % name)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001088
Armin Ronachere791c2a2008-04-07 18:39:54 +02001089 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001090 if node.ctx == 'store' and frame.toplevel:
1091 frame.assigned_names.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001092 self.write('l_' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001093
Armin Ronacherd84ec462008-04-29 13:43:16 +02001094 def visit_MarkSafe(self, node, frame):
1095 self.write('Markup(')
1096 self.visit(node.expr, frame)
1097 self.write(')')
1098
Armin Ronacher023b5e92008-05-08 11:03:10 +02001099 def visit_EnvironmentAttribute(self, node, frame):
1100 self.write('environment.' + node.name)
1101
1102 def visit_ExtensionAttribute(self, node, frame):
1103 self.write('environment.extensions[%r].%s' % (node.identifier, node.attr))
1104
1105 def visit_ImportedName(self, node, frame):
1106 self.write(self.import_aliases[node.importname])
1107
1108 def visit_InternalName(self, node, frame):
1109 self.write(node.name)
1110
Armin Ronachere791c2a2008-04-07 18:39:54 +02001111 def visit_Const(self, node, frame):
1112 val = node.value
1113 if isinstance(val, float):
1114 # XXX: add checks for infinity and nan
1115 self.write(str(val))
1116 else:
1117 self.write(repr(val))
1118
Armin Ronacher8efc5222008-04-08 14:47:40 +02001119 def visit_Tuple(self, node, frame):
1120 self.write('(')
1121 idx = -1
1122 for idx, item in enumerate(node.items):
1123 if idx:
1124 self.write(', ')
1125 self.visit(item, frame)
1126 self.write(idx == 0 and ',)' or ')')
1127
Armin Ronacher8edbe492008-04-10 20:43:43 +02001128 def visit_List(self, node, frame):
1129 self.write('[')
1130 for idx, item in enumerate(node.items):
1131 if idx:
1132 self.write(', ')
1133 self.visit(item, frame)
1134 self.write(']')
1135
1136 def visit_Dict(self, node, frame):
1137 self.write('{')
1138 for idx, item in enumerate(node.items):
1139 if idx:
1140 self.write(', ')
1141 self.visit(item.key, frame)
1142 self.write(': ')
1143 self.visit(item.value, frame)
1144 self.write('}')
1145
Armin Ronachere791c2a2008-04-07 18:39:54 +02001146 def binop(operator):
1147 def visitor(self, node, frame):
1148 self.write('(')
1149 self.visit(node.left, frame)
1150 self.write(' %s ' % operator)
1151 self.visit(node.right, frame)
1152 self.write(')')
1153 return visitor
1154
1155 def uaop(operator):
1156 def visitor(self, node, frame):
1157 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001158 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001159 self.write(')')
1160 return visitor
1161
1162 visit_Add = binop('+')
1163 visit_Sub = binop('-')
1164 visit_Mul = binop('*')
1165 visit_Div = binop('/')
1166 visit_FloorDiv = binop('//')
1167 visit_Pow = binop('**')
1168 visit_Mod = binop('%')
1169 visit_And = binop('and')
1170 visit_Or = binop('or')
1171 visit_Pos = uaop('+')
1172 visit_Neg = uaop('-')
1173 visit_Not = uaop('not ')
1174 del binop, uaop
1175
Armin Ronacherd1342312008-04-28 12:20:12 +02001176 def visit_Concat(self, node, frame):
Armin Ronacher709f6e52008-04-28 18:18:16 +02001177 self.write('%s((' % self.environment.autoescape and
1178 'markup_join' or 'unicode_join')
Armin Ronacherd1342312008-04-28 12:20:12 +02001179 for arg in node.nodes:
1180 self.visit(arg, frame)
1181 self.write(', ')
1182 self.write('))')
1183
Armin Ronachere791c2a2008-04-07 18:39:54 +02001184 def visit_Compare(self, node, frame):
1185 self.visit(node.expr, frame)
1186 for op in node.ops:
1187 self.visit(op, frame)
1188
1189 def visit_Operand(self, node, frame):
1190 self.write(' %s ' % operators[node.op])
1191 self.visit(node.expr, frame)
1192
1193 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001194 if isinstance(node.arg, nodes.Slice):
1195 self.visit(node.node, frame)
1196 self.write('[')
1197 self.visit(node.arg, frame)
1198 self.write(']')
1199 return
1200 try:
1201 const = node.arg.as_const()
1202 have_const = True
1203 except nodes.Impossible:
1204 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001205 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001206 self.visit(node.node, frame)
1207 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001208 if have_const:
1209 self.write(repr(const))
1210 else:
1211 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001212 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001213
1214 def visit_Slice(self, node, frame):
1215 if node.start is not None:
1216 self.visit(node.start, frame)
1217 self.write(':')
1218 if node.stop is not None:
1219 self.visit(node.stop, frame)
1220 if node.step is not None:
1221 self.write(':')
1222 self.visit(node.step, frame)
1223
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001224 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001225 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001226 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001227 if func is None:
1228 raise TemplateAssertionError('no filter named %r' % node.name,
1229 node.lineno, self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001230 if getattr(func, 'contextfilter', False):
1231 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001232 elif getattr(func, 'environmentfilter', False):
1233 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001234 if isinstance(node.node, nodes.Filter):
1235 self.visit_Filter(node.node, frame, initial)
1236 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001237 self.write(initial)
1238 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001239 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001240 self.signature(node, frame)
1241 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001242
1243 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001244 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001245 if node.name not in self.environment.tests:
1246 raise TemplateAssertionError('no test named %r' % node.name,
1247 node.lineno, self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001248 self.visit(node.node, frame)
1249 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001250 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001251
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001252 def visit_CondExpr(self, node, frame):
1253 if not have_condexpr:
1254 self.write('((')
1255 self.visit(node.test, frame)
1256 self.write(') and (')
1257 self.visit(node.expr1, frame)
1258 self.write(',) or (')
1259 self.visit(node.expr2, frame)
1260 self.write(',))[0]')
1261 else:
1262 self.write('(')
1263 self.visit(node.expr1, frame)
1264 self.write(' if ')
1265 self.visit(node.test, frame)
1266 self.write(' else ')
1267 self.visit(node.expr2, frame)
1268 self.write(')')
1269
Armin Ronacher71082072008-04-12 14:19:36 +02001270 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001271 if self.environment.sandboxed:
1272 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001273 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001274 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001275 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001276 self.write(')')
1277
1278 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001279 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001280 self.visit(node.value, frame)