blob: 7b8366cd8f6da813b50bc76e3665ce57991ce343 [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
Armin Ronacher27069d72008-05-11 19:48:12 +0200722 if frame.rootlevel:
723 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200724
Armin Ronacher7fb38972008-04-11 13:54:28 +0200725 # and now we have one more
726 self.extends_so_far += 1
727
Armin Ronacherf059ec12008-04-11 22:21:00 +0200728 def visit_Include(self, node, frame):
729 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200730 if node.with_context:
731 self.writeline('template = environment.get_template(', node)
732 self.visit(node.template, frame)
733 self.write(', %r)' % self.name)
734 self.writeline('for event in template.root_render_func('
735 'template.new_context(context.parent, True)):')
736 else:
737 self.writeline('for event in environment.get_template(', node)
738 self.visit(node.template, frame)
739 self.write(', %r).module._TemplateModule__body_stream:' %
740 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200741 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200742 if frame.buffer is None:
743 self.writeline('yield event')
744 else:
745 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200746 self.outdent()
747
Armin Ronacher0611e492008-04-25 23:44:14 +0200748 def visit_Import(self, node, frame):
749 """Visit regular imports."""
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200750 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200751 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200752 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200753 self.write('environment.get_template(')
754 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200755 self.write(', %r).' % self.name)
756 if node.with_context:
757 self.write('make_module(context.parent, True)')
758 else:
759 self.write('module')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200760 if frame.toplevel and not node.target.startswith('__'):
Armin Ronacher53042292008-04-26 18:30:19 +0200761 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200762
763 def visit_FromImport(self, node, frame):
764 """Visit named imports."""
765 self.newline(node)
766 self.write('included_template = environment.get_template(')
767 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200768 self.write(', %r).' % self.name)
769 if node.with_context:
770 self.write('make_module(context.parent, True)')
771 else:
772 self.write('module')
Armin Ronacher0611e492008-04-25 23:44:14 +0200773 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200774 if isinstance(name, tuple):
775 name, alias = name
776 else:
777 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200778 self.writeline('l_%s = getattr(included_template, '
779 '%r, missing)' % (alias, name))
780 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200781 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200782 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200783 'included_template.name, '
784 'name=included_template.name)' %
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200785 (alias, 'the template %r does not export '
786 'the requested name ' + repr(name)))
Armin Ronacher0611e492008-04-25 23:44:14 +0200787 self.outdent()
788 if frame.toplevel:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200789 self.writeline('context.vars[%r] = l_%s' % (alias, alias))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200790 if not alias.startswith('__'):
791 self.writeline('context.exported_vars.discard(%r)' % alias)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200792
Armin Ronachere791c2a2008-04-07 18:39:54 +0200793 def visit_For(self, node, frame):
794 loop_frame = frame.inner()
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200795 loop_frame.inspect(node.iter_child_nodes(exclude=('iter',)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200796 extended_loop = bool(node.else_) or \
797 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200798 if extended_loop:
799 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200800
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200801 aliases = self.collect_shadowed(loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200802 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200803 if node.else_:
804 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200805
806 self.newline(node)
807 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200808 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200809 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200810
811 # the expression pointing to the parent loop. We make the
812 # undefined a bit more debug friendly at the same time.
813 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200814 or "environment.undefined(%r, name='loop')" % "'loop' " \
815 'is undefined. "the filter section of a loop as well ' \
816 'as the else block doesn\'t have access to the ' \
817 "special 'loop' variable of the current loop. " \
818 "Because there is no parent loop it's undefined."
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200819
820 # if we have an extened loop and a node test, we filter in the
821 # "outer frame".
822 if extended_loop and node.test is not None:
823 self.write('(')
824 self.visit(node.target, loop_frame)
825 self.write(' for ')
826 self.visit(node.target, loop_frame)
827 self.write(' in ')
828 self.visit(node.iter, loop_frame)
829 self.write(' if (')
830 test_frame = loop_frame.copy()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200831 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200832 self.visit(node.test, test_frame)
833 self.write('))')
834
835 else:
836 self.visit(node.iter, loop_frame)
837
Armin Ronachere791c2a2008-04-07 18:39:54 +0200838 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200839
840 # tests in not extended loops become a continue
841 if not extended_loop and node.test is not None:
842 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200843 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200844 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200845 self.write(':')
846 self.indent()
847 self.writeline('continue')
848 self.outdent(2)
849
Armin Ronacherc9705c22008-04-27 21:28:03 +0200850 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200851 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200852 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200853
854 if node.else_:
855 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200856 self.indent()
857 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher625215e2008-04-13 16:31:08 +0200858 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200859 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200860
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200861 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200862 for name, alias in aliases.iteritems():
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200863 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200864
865 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200866 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200867 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200868 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200869 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200870 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200871 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200872 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200873 if node.else_:
874 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200875 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200876 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200877 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200878
Armin Ronacher8efc5222008-04-08 14:47:40 +0200879 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200880 macro_frame = self.function_scoping(node, frame)
881 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200882 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200883 macro_frame.buffer = buf = self.temporary_identifier()
884 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200885 self.pull_locals(macro_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200886 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200887 self.blockvisit(node.body, macro_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200888 if self.environment.autoescape:
889 self.writeline('return Markup(concat(%s))' % buf)
890 else:
891 self.writeline("return concat(%s)" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200892 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200893 self.newline()
894 if frame.toplevel:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200895 if not node.name.startswith('__'):
896 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +0200897 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200898 arg_tuple = ', '.join(repr(x.name) for x in node.args)
899 if len(node.args) == 1:
900 arg_tuple += ','
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200901 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
902 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200903 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200904 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200905 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200906 self.write('), %s, %s, %s)' % (
907 macro_frame.accesses_kwargs and '1' or '0',
908 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200909 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200910 ))
911
912 def visit_CallBlock(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200913 call_frame = self.function_scoping(node, frame, node.iter_child_nodes
914 (exclude=('call',)))
Armin Ronacher71082072008-04-12 14:19:36 +0200915 args = call_frame.arguments
916 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200917 call_frame.buffer = buf = self.temporary_identifier()
918 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200919 self.pull_locals(call_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200920 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200921 self.blockvisit(node.body, call_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200922 if self.environment.autoescape:
923 self.writeline("return Markup(concat(%s))" % buf)
924 else:
925 self.writeline('return concat(%s)' % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200926 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200927 arg_tuple = ', '.join(repr(x.name) for x in node.args)
928 if len(node.args) == 1:
929 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200930 self.writeline('caller = Macro(environment, call, None, (%s), (' %
931 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200932 for arg in node.defaults:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200933 self.visit(arg, call_frame)
Armin Ronacher71082072008-04-12 14:19:36 +0200934 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200935 self.write('), %s, %s, 0)' % (
936 call_frame.accesses_kwargs and '1' or '0',
937 call_frame.accesses_varargs and '1' or '0'
938 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200939 if frame.buffer is None:
940 self.writeline('yield ', node)
941 else:
942 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200943 self.visit_Call(node.call, call_frame,
944 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200945 if frame.buffer is not None:
946 self.write(')')
947
948 def visit_FilterBlock(self, node, frame):
949 filter_frame = frame.inner()
950 filter_frame.inspect(node.iter_child_nodes())
951
952 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200953 self.pull_locals(filter_frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200954 filter_frame.buffer = buf = self.temporary_identifier()
955
956 self.writeline('%s = []' % buf, node)
957 for child in node.body:
958 self.visit(child, filter_frame)
959
960 if frame.buffer is None:
961 self.writeline('yield ', node)
962 else:
963 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200964 self.visit_Filter(node.filter, filter_frame, 'concat(%s)' % buf)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200965 if frame.buffer is not None:
966 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200967
Armin Ronachere791c2a2008-04-07 18:39:54 +0200968 def visit_ExprStmt(self, node, frame):
969 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +0200970 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200971
972 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200973 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +0200974 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200975 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200976
Armin Ronacher75cfb862008-04-11 13:47:22 +0200977 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200978
Armin Ronacher7fb38972008-04-11 13:54:28 +0200979 # if we are in the toplevel scope and there was already an extends
980 # statement we have to add a check that disables our yield(s) here
981 # so that they don't appear in the output.
982 outdent_later = False
983 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200984 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200985 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200986 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +0200987
Armin Ronachere791c2a2008-04-07 18:39:54 +0200988 # try to evaluate as many chunks as possible into a static
989 # string at compile time.
990 body = []
991 for child in node.nodes:
992 try:
993 const = unicode(child.as_const())
994 except:
995 body.append(child)
996 continue
997 if body and isinstance(body[-1], list):
998 body[-1].append(const)
999 else:
1000 body.append([const])
1001
Armin Ronacher32a910f2008-04-26 23:21:03 +02001002 # if we have less than 3 nodes or less than 6 and a buffer we
1003 # yield or extend
1004 if len(body) < 3 or (frame.buffer is not None and len(body) < 6):
1005 if frame.buffer is not None:
1006 self.writeline('%s.extend((' % frame.buffer)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001007 for item in body:
1008 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001009 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001010 if frame.buffer is None:
1011 self.writeline('yield ' + val)
1012 else:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001013 self.write(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001014 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001015 if frame.buffer is None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001016 self.writeline('yield ')
Armin Ronacherd1342312008-04-28 12:20:12 +02001017 close = 1
1018 if self.environment.autoescape:
1019 self.write('escape(')
1020 else:
1021 self.write('unicode(')
1022 if self.environment.finalize is not None:
1023 self.write('environment.finalize(')
1024 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001025 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001026 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001027 if frame.buffer is not None:
1028 self.write(', ')
1029 if frame.buffer is not None:
1030 self.write('))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001031
1032 # otherwise we create a format string as this is faster in that case
1033 else:
1034 format = []
1035 arguments = []
1036 for item in body:
1037 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001038 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001039 else:
1040 format.append('%s')
1041 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001042 if frame.buffer is None:
1043 self.writeline('yield ')
1044 else:
1045 self.writeline('%s.append(' % frame.buffer)
Armin Ronacherde6bf712008-04-26 01:44:14 +02001046 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001047 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001048 self.indent()
1049 for argument in arguments:
1050 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001051 close = 0
1052 if self.environment.autoescape:
1053 self.write('escape(')
1054 close += 1
1055 if self.environment.finalize is not None:
1056 self.write('environment.finalize(')
1057 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001058 self.visit(argument, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001059 self.write(')' * close + ',')
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001060 self.outdent()
1061 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001062 if frame.buffer is not None:
1063 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001064
Armin Ronacher7fb38972008-04-11 13:54:28 +02001065 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001066 self.outdent()
1067
Armin Ronacher8efc5222008-04-08 14:47:40 +02001068 def visit_Assign(self, node, frame):
1069 self.newline(node)
1070 # toplevel assignments however go into the local namespace and
1071 # the current template's context. We create a copy of the frame
1072 # here and add a set so that the Name visitor can add the assigned
1073 # names here.
1074 if frame.toplevel:
1075 assignment_frame = frame.copy()
1076 assignment_frame.assigned_names = set()
1077 else:
1078 assignment_frame = frame
1079 self.visit(node.target, assignment_frame)
1080 self.write(' = ')
1081 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001082
1083 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001084 if frame.toplevel:
1085 for name in assignment_frame.assigned_names:
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001086 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +02001087 if not name.startswith('__'):
1088 self.writeline('context.exported_vars.add(%r)' % name)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001089
Armin Ronachere791c2a2008-04-07 18:39:54 +02001090 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001091 if node.ctx == 'store' and frame.toplevel:
1092 frame.assigned_names.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001093 self.write('l_' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001094
Armin Ronacherd84ec462008-04-29 13:43:16 +02001095 def visit_MarkSafe(self, node, frame):
1096 self.write('Markup(')
1097 self.visit(node.expr, frame)
1098 self.write(')')
1099
Armin Ronacher023b5e92008-05-08 11:03:10 +02001100 def visit_EnvironmentAttribute(self, node, frame):
1101 self.write('environment.' + node.name)
1102
1103 def visit_ExtensionAttribute(self, node, frame):
1104 self.write('environment.extensions[%r].%s' % (node.identifier, node.attr))
1105
1106 def visit_ImportedName(self, node, frame):
1107 self.write(self.import_aliases[node.importname])
1108
1109 def visit_InternalName(self, node, frame):
1110 self.write(node.name)
1111
Armin Ronachere791c2a2008-04-07 18:39:54 +02001112 def visit_Const(self, node, frame):
1113 val = node.value
1114 if isinstance(val, float):
1115 # XXX: add checks for infinity and nan
1116 self.write(str(val))
1117 else:
1118 self.write(repr(val))
1119
Armin Ronacher8efc5222008-04-08 14:47:40 +02001120 def visit_Tuple(self, node, frame):
1121 self.write('(')
1122 idx = -1
1123 for idx, item in enumerate(node.items):
1124 if idx:
1125 self.write(', ')
1126 self.visit(item, frame)
1127 self.write(idx == 0 and ',)' or ')')
1128
Armin Ronacher8edbe492008-04-10 20:43:43 +02001129 def visit_List(self, node, frame):
1130 self.write('[')
1131 for idx, item in enumerate(node.items):
1132 if idx:
1133 self.write(', ')
1134 self.visit(item, frame)
1135 self.write(']')
1136
1137 def visit_Dict(self, node, frame):
1138 self.write('{')
1139 for idx, item in enumerate(node.items):
1140 if idx:
1141 self.write(', ')
1142 self.visit(item.key, frame)
1143 self.write(': ')
1144 self.visit(item.value, frame)
1145 self.write('}')
1146
Armin Ronachere791c2a2008-04-07 18:39:54 +02001147 def binop(operator):
1148 def visitor(self, node, frame):
1149 self.write('(')
1150 self.visit(node.left, frame)
1151 self.write(' %s ' % operator)
1152 self.visit(node.right, frame)
1153 self.write(')')
1154 return visitor
1155
1156 def uaop(operator):
1157 def visitor(self, node, frame):
1158 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001159 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001160 self.write(')')
1161 return visitor
1162
1163 visit_Add = binop('+')
1164 visit_Sub = binop('-')
1165 visit_Mul = binop('*')
1166 visit_Div = binop('/')
1167 visit_FloorDiv = binop('//')
1168 visit_Pow = binop('**')
1169 visit_Mod = binop('%')
1170 visit_And = binop('and')
1171 visit_Or = binop('or')
1172 visit_Pos = uaop('+')
1173 visit_Neg = uaop('-')
1174 visit_Not = uaop('not ')
1175 del binop, uaop
1176
Armin Ronacherd1342312008-04-28 12:20:12 +02001177 def visit_Concat(self, node, frame):
Armin Ronacher709f6e52008-04-28 18:18:16 +02001178 self.write('%s((' % self.environment.autoescape and
1179 'markup_join' or 'unicode_join')
Armin Ronacherd1342312008-04-28 12:20:12 +02001180 for arg in node.nodes:
1181 self.visit(arg, frame)
1182 self.write(', ')
1183 self.write('))')
1184
Armin Ronachere791c2a2008-04-07 18:39:54 +02001185 def visit_Compare(self, node, frame):
1186 self.visit(node.expr, frame)
1187 for op in node.ops:
1188 self.visit(op, frame)
1189
1190 def visit_Operand(self, node, frame):
1191 self.write(' %s ' % operators[node.op])
1192 self.visit(node.expr, frame)
1193
1194 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001195 if isinstance(node.arg, nodes.Slice):
1196 self.visit(node.node, frame)
1197 self.write('[')
1198 self.visit(node.arg, frame)
1199 self.write(']')
1200 return
1201 try:
1202 const = node.arg.as_const()
1203 have_const = True
1204 except nodes.Impossible:
1205 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001206 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001207 self.visit(node.node, frame)
1208 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001209 if have_const:
1210 self.write(repr(const))
1211 else:
1212 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001213 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001214
1215 def visit_Slice(self, node, frame):
1216 if node.start is not None:
1217 self.visit(node.start, frame)
1218 self.write(':')
1219 if node.stop is not None:
1220 self.visit(node.stop, frame)
1221 if node.step is not None:
1222 self.write(':')
1223 self.visit(node.step, frame)
1224
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001225 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001226 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001227 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001228 if func is None:
1229 raise TemplateAssertionError('no filter named %r' % node.name,
1230 node.lineno, self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001231 if getattr(func, 'contextfilter', False):
1232 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001233 elif getattr(func, 'environmentfilter', False):
1234 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001235 if isinstance(node.node, nodes.Filter):
1236 self.visit_Filter(node.node, frame, initial)
1237 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001238 self.write(initial)
1239 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001240 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001241 self.signature(node, frame)
1242 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001243
1244 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001245 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001246 if node.name not in self.environment.tests:
1247 raise TemplateAssertionError('no test named %r' % node.name,
1248 node.lineno, self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001249 self.visit(node.node, frame)
1250 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001251 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001252
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001253 def visit_CondExpr(self, node, frame):
1254 if not have_condexpr:
1255 self.write('((')
1256 self.visit(node.test, frame)
1257 self.write(') and (')
1258 self.visit(node.expr1, frame)
1259 self.write(',) or (')
1260 self.visit(node.expr2, frame)
1261 self.write(',))[0]')
1262 else:
1263 self.write('(')
1264 self.visit(node.expr1, frame)
1265 self.write(' if ')
1266 self.visit(node.test, frame)
1267 self.write(' else ')
1268 self.visit(node.expr2, frame)
1269 self.write(')')
1270
Armin Ronacher71082072008-04-12 14:19:36 +02001271 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001272 if self.environment.sandboxed:
1273 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001274 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001275 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001276 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001277 self.write(')')
1278
1279 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001280 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001281 self.visit(node.value, frame)