blob: 9ee323d625e9146ff9f412ed8c118054ba13deba [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 Ronacher2feed1d2008-04-26 16:26:52 +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
328 # the debug information
329 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200330 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200331
Armin Ronacherfed44b52008-04-13 19:42:53 +0200332 # the number of new lines before the next write()
333 self._new_lines = 0
334
335 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200336 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200337
338 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200339 self._first_write = True
340
Armin Ronacherfed44b52008-04-13 19:42:53 +0200341 # used by the `temporary_identifier` method to get new
342 # unique, temporary identifier
343 self._last_identifier = 0
344
345 # the current indentation
346 self._indentation = 0
347
Armin Ronachere791c2a2008-04-07 18:39:54 +0200348 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200349 """Get a new unique identifier."""
350 self._last_identifier += 1
351 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200352
353 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200354 """Indent by one."""
355 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200356
Armin Ronacher8efc5222008-04-08 14:47:40 +0200357 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200358 """Outdent by step."""
359 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200360
Armin Ronacherc9705c22008-04-27 21:28:03 +0200361 def blockvisit(self, nodes, frame, force_generator=True):
362 """Visit a list of nodes as block in a frame. If the current frame
363 is no buffer a dummy ``if 0: yield None`` is written automatically
364 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200365 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200366 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200367 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200368 try:
369 for node in nodes:
370 self.visit(node, frame)
371 except CompilerExit:
372 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200373
374 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200375 """Write a string into the output stream."""
376 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200377 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200378 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200379 self.code_lineno += self._new_lines
380 if self._write_debug_info is not None:
381 self.debug_info.append((self._write_debug_info,
382 self.code_lineno))
383 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200384 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200385 self.stream.write(' ' * self._indentation)
386 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200387 self.stream.write(x)
388
389 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200390 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200391 self.newline(node, extra)
392 self.write(x)
393
394 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200395 """Add one or more newlines before the next write."""
396 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200397 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200398 self._write_debug_info = node.lineno
399 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200400
Armin Ronacher71082072008-04-12 14:19:36 +0200401 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200402 """Writes a function call to the stream for the current node.
403 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200404 disabled by setting have_comma to False. The extra keyword
405 arguments may not include python keywords otherwise a syntax
406 error could occour. The extra keyword arguments should be given
407 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200408 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200409 have_comma = have_comma and [True] or []
410 def touch_comma():
411 if have_comma:
412 self.write(', ')
413 else:
414 have_comma.append(True)
415
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200416 # if any of the given keyword arguments is a python keyword
417 # we have to make sure that no invalid call is created.
418 kwarg_workaround = False
419 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
420 if iskeyword(kwarg):
421 kwarg_workaround = True
422 break
423
Armin Ronacher8efc5222008-04-08 14:47:40 +0200424 for arg in node.args:
425 touch_comma()
426 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200427
428 if not kwarg_workaround:
429 for kwarg in node.kwargs:
430 touch_comma()
431 self.visit(kwarg, frame)
432 if extra_kwargs is not None:
433 for key, value in extra_kwargs.iteritems():
434 touch_comma()
435 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200436 if node.dyn_args:
437 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200438 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200439 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200440
441 if kwarg_workaround:
442 touch_comma()
443 if node.dyn_kwargs is not None:
444 self.write('**dict({')
445 else:
446 self.write('**{')
447 for kwarg in node.kwargs:
448 self.write('%r: ' % kwarg.key)
449 self.visit(kwarg.value, frame)
450 self.write(', ')
451 if extra_kwargs is not None:
452 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200453 self.write('%r: %s, ' % (key, value))
454 if node.dyn_kwargs is not None:
455 self.write('}, **')
456 self.visit(node.dyn_kwargs, frame)
457 self.write(')')
458 else:
459 self.write('}')
460
461 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200462 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200463 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200464 self.visit(node.dyn_kwargs, frame)
465
Armin Ronacherc9705c22008-04-27 21:28:03 +0200466 def pull_locals(self, frame):
467 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200468 for name in frame.identifiers.undeclared:
Armin Ronacherf35e2812008-05-06 16:04:10 +0200469 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200470
471 def pull_dependencies(self, nodes):
472 """Pull all the dependencies."""
473 visitor = DependencyFinderVisitor()
474 for node in nodes:
475 visitor.visit(node)
476 for name in visitor.filters:
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200477 self.writeline('f_%s = environment.filters[%r]' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200478 for name in visitor.tests:
Armin Ronacherf059ec12008-04-11 22:21:00 +0200479 self.writeline('t_%s = environment.tests[%r]' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200480
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200481 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200482 """This function returns all the shadowed variables in a dict
483 in the form name: alias and will write the required assignments
484 into the current scope. No indentation takes place.
485 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200486 # make sure we "backup" overridden, local identifiers
487 # TODO: we should probably optimize this and check if the
488 # identifier is in use afterwards.
489 aliases = {}
490 for name in frame.identifiers.find_shadowed():
491 aliases[name] = ident = self.temporary_identifier()
492 self.writeline('%s = l_%s' % (ident, name))
493 return aliases
494
Armin Ronacherc9705c22008-04-27 21:28:03 +0200495 def function_scoping(self, node, frame, children=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200496 """In Jinja a few statements require the help of anonymous
497 functions. Those are currently macros and call blocks and in
498 the future also recursive loops. As there is currently
499 technical limitation that doesn't allow reading and writing a
500 variable in a scope where the initial value is coming from an
501 outer scope, this function tries to fall back with a common
502 error message. Additionally the frame passed is modified so
503 that the argumetns are collected and callers are looked up.
504
505 This will return the modified frame.
506 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200507 # we have to iterate twice over it, make sure that works
508 if children is None:
509 children = node.iter_child_nodes()
510 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200511 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200512 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200513
514 # variables that are undeclared (accessed before declaration) and
515 # declared locally *and* part of an outside scope raise a template
516 # assertion error. Reason: we can't generate reasonable code from
517 # it without aliasing all the variables. XXX: alias them ^^
518 overriden_closure_vars = (
519 func_frame.identifiers.undeclared &
520 func_frame.identifiers.declared &
521 (func_frame.identifiers.declared_locally |
522 func_frame.identifiers.declared_parameter)
523 )
524 if overriden_closure_vars:
525 vars = ', '.join(sorted(overriden_closure_vars))
526 raise TemplateAssertionError('It\'s not possible to set and '
527 'access variables derived from '
528 'an outer scope! (affects: %s' %
Armin Ronacher68f77672008-04-17 11:50:39 +0200529 vars, node.lineno, self.name)
Armin Ronacher71082072008-04-12 14:19:36 +0200530
531 # remove variables from a closure from the frame's undeclared
532 # identifiers.
533 func_frame.identifiers.undeclared -= (
534 func_frame.identifiers.undeclared &
535 func_frame.identifiers.declared
536 )
537
Armin Ronacher963f97d2008-04-25 11:44:59 +0200538 func_frame.accesses_kwargs = False
539 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200540 func_frame.accesses_caller = False
541 func_frame.arguments = args = ['l_' + x.name for x in node.args]
542
Armin Ronacherc9705c22008-04-27 21:28:03 +0200543 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
544
545 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200546 func_frame.accesses_caller = True
547 func_frame.identifiers.add_special('caller')
548 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200549 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200550 func_frame.accesses_kwargs = True
551 func_frame.identifiers.add_special('kwargs')
552 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200553 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200554 func_frame.accesses_varargs = True
555 func_frame.identifiers.add_special('varargs')
556 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200557 return func_frame
558
Armin Ronachere791c2a2008-04-07 18:39:54 +0200559 # -- Visitors
560
561 def visit_Template(self, node, frame=None):
562 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200563 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200564 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200565 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8edbe492008-04-10 20:43:43 +0200566
Armin Ronacher75cfb862008-04-11 13:47:22 +0200567 # do we have an extends tag at all? If not, we can save some
568 # overhead by just not processing any inheritance code.
569 have_extends = node.find(nodes.Extends) is not None
570
Armin Ronacher8edbe492008-04-10 20:43:43 +0200571 # find all blocks
572 for block in node.find_all(nodes.Block):
573 if block.name in self.blocks:
574 raise TemplateAssertionError('block %r defined twice' %
575 block.name, block.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200576 self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200577 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200578
Armin Ronacher023b5e92008-05-08 11:03:10 +0200579 # find all imports and import them
580 for import_ in node.find_all(nodes.ImportedName):
581 if import_.importname not in self.import_aliases:
582 imp = import_.importname
583 self.import_aliases[imp] = alias = self.temporary_identifier()
584 if '.' in imp:
585 module, obj = imp.rsplit('.', 1)
586 self.writeline('from %s import %s as %s' %
587 (module, obj, alias))
588 else:
589 self.writeline('import %s as %s' % (imp, alias))
590
591 # add the load name
592 self.writeline('name = %r' % self.name)
593
Armin Ronacher8efc5222008-04-08 14:47:40 +0200594 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200595 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200596
597 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200598 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200599 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200600 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200601 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200602 if have_extends:
603 self.writeline('parent_template = None')
604 self.pull_locals(frame)
605 self.pull_dependencies(node.body)
606 if 'self' in find_undeclared(node.body, ('self',)):
607 frame.identifiers.add_special('self')
608 self.writeline('l_self = TemplateReference(context)')
609 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200610 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200611
Armin Ronacher8efc5222008-04-08 14:47:40 +0200612 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200613 if have_extends:
614 if not self.has_known_extends:
615 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200616 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200617 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200618 self.writeline('for event in parent_template.'
619 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200620 self.indent()
621 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200622 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200623
624 # at this point we now have the blocks collected and can visit them too.
625 for name, block in self.blocks.iteritems():
626 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200627 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200628 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200629 self.writeline('def block_%s(context, environment=environment):'
630 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200631 self.indent()
632 undeclared = find_undeclared(block.body, ('self', 'super'))
633 if 'self' in undeclared:
634 block_frame.identifiers.add_special('self')
635 self.writeline('l_self = TemplateReference(context)')
636 if 'super' in undeclared:
637 block_frame.identifiers.add_special('super')
638 self.writeline('l_super = context.super(%r, '
639 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200640 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200641 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200642 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200643 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200644
Armin Ronacher75cfb862008-04-11 13:47:22 +0200645 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200646 for x in self.blocks),
647 extra=1)
648
649 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200650 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
651 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200652
Armin Ronachere791c2a2008-04-07 18:39:54 +0200653 def visit_Block(self, node, frame):
654 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200655 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200656 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200657 # if we know that we are a child template, there is no need to
658 # check if we are one
659 if self.has_known_extends:
660 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200661 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200662 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200663 self.indent()
664 level += 1
Armin Ronacherc9705c22008-04-27 21:28:03 +0200665 self.writeline('for event in context.blocks[%r][-1](context):' %
666 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200667 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200668 if frame.buffer is None:
669 self.writeline('yield event')
670 else:
671 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200672 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200673
674 def visit_Extends(self, node, frame):
675 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200676 if not frame.toplevel:
677 raise TemplateAssertionError('cannot use extend from a non '
678 'top-level scope', node.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200679 self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200680
Armin Ronacher7fb38972008-04-11 13:54:28 +0200681 # if the number of extends statements in general is zero so
682 # far, we don't have to add a check if something extended
683 # the template before this one.
684 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200685
Armin Ronacher7fb38972008-04-11 13:54:28 +0200686 # if we have a known extends we just add a template runtime
687 # error into the generated code. We could catch that at compile
688 # time too, but i welcome it not to confuse users by throwing the
689 # same error at different times just "because we can".
690 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200691 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200692 self.indent()
693 self.writeline('raise TemplateRuntimeError(%r)' %
694 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200695
Armin Ronacher7fb38972008-04-11 13:54:28 +0200696 # if we have a known extends already we don't need that code here
697 # as we know that the template execution will end here.
698 if self.has_known_extends:
699 raise CompilerExit()
700 self.outdent()
701
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200702 self.writeline('parent_template = environment.get_template(', node, 1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200703 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200704 self.write(', %r)' % self.name)
705 self.writeline('for name, parent_block in parent_template.'
706 'blocks.iteritems():')
707 self.indent()
708 self.writeline('context.blocks.setdefault(name, []).'
709 'insert(0, parent_block)')
710 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200711
712 # if this extends statement was in the root level we can take
713 # advantage of that information and simplify the generated code
714 # in the top level from this point onwards
715 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200716
Armin Ronacher7fb38972008-04-11 13:54:28 +0200717 # and now we have one more
718 self.extends_so_far += 1
719
Armin Ronacherf059ec12008-04-11 22:21:00 +0200720 def visit_Include(self, node, frame):
721 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200722 if node.with_context:
723 self.writeline('template = environment.get_template(', node)
724 self.visit(node.template, frame)
725 self.write(', %r)' % self.name)
726 self.writeline('for event in template.root_render_func('
727 'template.new_context(context.parent, True)):')
728 else:
729 self.writeline('for event in environment.get_template(', node)
730 self.visit(node.template, frame)
731 self.write(', %r).module._TemplateModule__body_stream:' %
732 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200733 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200734 if frame.buffer is None:
735 self.writeline('yield event')
736 else:
737 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200738 self.outdent()
739
Armin Ronacher0611e492008-04-25 23:44:14 +0200740 def visit_Import(self, node, frame):
741 """Visit regular imports."""
742 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200743 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200744 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200745 self.write('environment.get_template(')
746 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200747 self.write(', %r).' % self.name)
748 if node.with_context:
749 self.write('make_module(context.parent, True)')
750 else:
751 self.write('module')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200752 if frame.toplevel and not node.target.startswith('__'):
Armin Ronacher53042292008-04-26 18:30:19 +0200753 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200754
755 def visit_FromImport(self, node, frame):
756 """Visit named imports."""
757 self.newline(node)
758 self.write('included_template = environment.get_template(')
759 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200760 self.write(', %r).' % self.name)
761 if node.with_context:
762 self.write('make_module(context.parent, True)')
763 else:
764 self.write('module')
Armin Ronacher0611e492008-04-25 23:44:14 +0200765 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200766 if isinstance(name, tuple):
767 name, alias = name
768 else:
769 alias = name
Armin Ronacher0611e492008-04-25 23:44:14 +0200770 self.writeline('l_%s = getattr(included_template, '
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200771 '%r, missing)' % (alias, name))
772 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200773 self.indent()
774 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200775 'included_template.name, '
776 'name=included_template.name)' %
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200777 (alias, 'the template %r does not export '
Armin Ronacher0611e492008-04-25 23:44:14 +0200778 'the requested name ' + repr(name)))
779 self.outdent()
780 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200781 self.writeline('context.vars[%r] = l_%s' % (alias, alias))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200782 if not alias.startswith('__'):
783 self.writeline('context.exported_vars.discard(%r)' % alias)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200784
Armin Ronachere791c2a2008-04-07 18:39:54 +0200785 def visit_For(self, node, frame):
786 loop_frame = frame.inner()
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200787 loop_frame.inspect(node.iter_child_nodes(exclude=('iter',)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200788 extended_loop = bool(node.else_) or \
789 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200790 if extended_loop:
791 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200792
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200793 aliases = self.collect_shadowed(loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200794 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200795 if node.else_:
796 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200797
798 self.newline(node)
799 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200800 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200801 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200802
803 # the expression pointing to the parent loop. We make the
804 # undefined a bit more debug friendly at the same time.
805 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200806 or "environment.undefined(%r, name='loop')" % "'loop' " \
807 'is undefined. "the filter section of a loop as well ' \
808 'as the else block doesn\'t have access to the ' \
809 "special 'loop' variable of the current loop. " \
810 "Because there is no parent loop it's undefined."
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200811
812 # if we have an extened loop and a node test, we filter in the
813 # "outer frame".
814 if extended_loop and node.test is not None:
815 self.write('(')
816 self.visit(node.target, loop_frame)
817 self.write(' for ')
818 self.visit(node.target, loop_frame)
819 self.write(' in ')
820 self.visit(node.iter, loop_frame)
821 self.write(' if (')
822 test_frame = loop_frame.copy()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200823 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200824 self.visit(node.test, test_frame)
825 self.write('))')
826
827 else:
828 self.visit(node.iter, loop_frame)
829
Armin Ronachere791c2a2008-04-07 18:39:54 +0200830 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200831
832 # tests in not extended loops become a continue
833 if not extended_loop and node.test is not None:
834 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200835 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200836 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200837 self.write(':')
838 self.indent()
839 self.writeline('continue')
840 self.outdent(2)
841
Armin Ronacherc9705c22008-04-27 21:28:03 +0200842 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200843 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200844 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200845
846 if node.else_:
847 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200848 self.indent()
849 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher625215e2008-04-13 16:31:08 +0200850 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200851 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200852
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200853 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200854 for name, alias in aliases.iteritems():
Armin Ronacher8efc5222008-04-08 14:47:40 +0200855 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200856
857 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200858 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200859 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200860 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200861 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200862 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200863 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200864 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200865 if node.else_:
866 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200867 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200868 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200869 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200870
Armin Ronacher8efc5222008-04-08 14:47:40 +0200871 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200872 macro_frame = self.function_scoping(node, frame)
873 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200874 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200875 macro_frame.buffer = buf = self.temporary_identifier()
876 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200877 self.pull_locals(macro_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200878 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200879 self.blockvisit(node.body, macro_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200880 if self.environment.autoescape:
881 self.writeline('return Markup(concat(%s))' % buf)
882 else:
883 self.writeline("return concat(%s)" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200884 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200885 self.newline()
886 if frame.toplevel:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200887 if not node.name.startswith('__'):
888 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +0200889 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200890 arg_tuple = ', '.join(repr(x.name) for x in node.args)
891 if len(node.args) == 1:
892 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200893 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
894 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200895 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200896 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200897 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200898 self.write('), %s, %s, %s)' % (
899 macro_frame.accesses_kwargs and '1' or '0',
900 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200901 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200902 ))
903
904 def visit_CallBlock(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200905 call_frame = self.function_scoping(node, frame, node.iter_child_nodes
906 (exclude=('call',)))
Armin Ronacher71082072008-04-12 14:19:36 +0200907 args = call_frame.arguments
908 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200909 call_frame.buffer = buf = self.temporary_identifier()
910 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200911 self.pull_locals(call_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200912 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200913 self.blockvisit(node.body, call_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200914 if self.environment.autoescape:
915 self.writeline("return Markup(concat(%s))" % buf)
916 else:
917 self.writeline('return concat(%s)' % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200918 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200919 arg_tuple = ', '.join(repr(x.name) for x in node.args)
920 if len(node.args) == 1:
921 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200922 self.writeline('caller = Macro(environment, call, None, (%s), (' %
923 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200924 for arg in node.defaults:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200925 self.visit(arg, call_frame)
Armin Ronacher71082072008-04-12 14:19:36 +0200926 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200927 self.write('), %s, %s, 0)' % (
928 call_frame.accesses_kwargs and '1' or '0',
929 call_frame.accesses_varargs and '1' or '0'
930 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200931 if frame.buffer is None:
932 self.writeline('yield ', node)
933 else:
934 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200935 self.visit_Call(node.call, call_frame,
936 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200937 if frame.buffer is not None:
938 self.write(')')
939
940 def visit_FilterBlock(self, node, frame):
941 filter_frame = frame.inner()
942 filter_frame.inspect(node.iter_child_nodes())
943
944 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200945 self.pull_locals(filter_frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200946 filter_frame.buffer = buf = self.temporary_identifier()
947
948 self.writeline('%s = []' % buf, node)
949 for child in node.body:
950 self.visit(child, filter_frame)
951
952 if frame.buffer is None:
953 self.writeline('yield ', node)
954 else:
955 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200956 self.visit_Filter(node.filter, filter_frame, 'concat(%s)' % buf)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200957 if frame.buffer is not None:
958 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200959
Armin Ronachere791c2a2008-04-07 18:39:54 +0200960 def visit_ExprStmt(self, node, frame):
961 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +0200962 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200963
964 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200965 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +0200966 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200967 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200968
Armin Ronacher75cfb862008-04-11 13:47:22 +0200969 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200970
Armin Ronacher7fb38972008-04-11 13:54:28 +0200971 # if we are in the toplevel scope and there was already an extends
972 # statement we have to add a check that disables our yield(s) here
973 # so that they don't appear in the output.
974 outdent_later = False
975 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200976 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200977 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200978 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +0200979
Armin Ronachere791c2a2008-04-07 18:39:54 +0200980 # try to evaluate as many chunks as possible into a static
981 # string at compile time.
982 body = []
983 for child in node.nodes:
984 try:
985 const = unicode(child.as_const())
986 except:
987 body.append(child)
988 continue
989 if body and isinstance(body[-1], list):
990 body[-1].append(const)
991 else:
992 body.append([const])
993
Armin Ronacher32a910f2008-04-26 23:21:03 +0200994 # if we have less than 3 nodes or less than 6 and a buffer we
995 # yield or extend
996 if len(body) < 3 or (frame.buffer is not None and len(body) < 6):
997 if frame.buffer is not None:
998 self.writeline('%s.extend((' % frame.buffer)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200999 for item in body:
1000 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001001 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001002 if frame.buffer is None:
1003 self.writeline('yield ' + val)
1004 else:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001005 self.write(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001006 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001007 if frame.buffer is None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001008 self.writeline('yield ')
Armin Ronacherd1342312008-04-28 12:20:12 +02001009 close = 1
1010 if self.environment.autoescape:
1011 self.write('escape(')
1012 else:
1013 self.write('unicode(')
1014 if self.environment.finalize is not None:
1015 self.write('environment.finalize(')
1016 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001017 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001018 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001019 if frame.buffer is not None:
1020 self.write(', ')
1021 if frame.buffer is not None:
1022 self.write('))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001023
1024 # otherwise we create a format string as this is faster in that case
1025 else:
1026 format = []
1027 arguments = []
1028 for item in body:
1029 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001030 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001031 else:
1032 format.append('%s')
1033 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001034 if frame.buffer is None:
1035 self.writeline('yield ')
1036 else:
1037 self.writeline('%s.append(' % frame.buffer)
Armin Ronacherde6bf712008-04-26 01:44:14 +02001038 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001039 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001040 self.indent()
1041 for argument in arguments:
1042 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001043 close = 0
1044 if self.environment.autoescape:
1045 self.write('escape(')
1046 close += 1
1047 if self.environment.finalize is not None:
1048 self.write('environment.finalize(')
1049 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001050 self.visit(argument, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001051 self.write(')' * close + ',')
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001052 self.outdent()
1053 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001054 if frame.buffer is not None:
1055 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001056
Armin Ronacher7fb38972008-04-11 13:54:28 +02001057 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001058 self.outdent()
1059
Armin Ronacher8efc5222008-04-08 14:47:40 +02001060 def visit_Assign(self, node, frame):
1061 self.newline(node)
1062 # toplevel assignments however go into the local namespace and
1063 # the current template's context. We create a copy of the frame
1064 # here and add a set so that the Name visitor can add the assigned
1065 # names here.
1066 if frame.toplevel:
1067 assignment_frame = frame.copy()
1068 assignment_frame.assigned_names = set()
1069 else:
1070 assignment_frame = frame
1071 self.visit(node.target, assignment_frame)
1072 self.write(' = ')
1073 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001074
1075 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001076 if frame.toplevel:
1077 for name in assignment_frame.assigned_names:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001078 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +02001079 if not name.startswith('__'):
1080 self.writeline('context.exported_vars.add(%r)' % name)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001081
Armin Ronachere791c2a2008-04-07 18:39:54 +02001082 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001083 if node.ctx == 'store' and frame.toplevel:
1084 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001085 self.write('l_' + node.name)
1086
Armin Ronacherd84ec462008-04-29 13:43:16 +02001087 def visit_MarkSafe(self, node, frame):
1088 self.write('Markup(')
1089 self.visit(node.expr, frame)
1090 self.write(')')
1091
Armin Ronacher023b5e92008-05-08 11:03:10 +02001092 def visit_EnvironmentAttribute(self, node, frame):
1093 self.write('environment.' + node.name)
1094
1095 def visit_ExtensionAttribute(self, node, frame):
1096 self.write('environment.extensions[%r].%s' % (node.identifier, node.attr))
1097
1098 def visit_ImportedName(self, node, frame):
1099 self.write(self.import_aliases[node.importname])
1100
1101 def visit_InternalName(self, node, frame):
1102 self.write(node.name)
1103
Armin Ronachere791c2a2008-04-07 18:39:54 +02001104 def visit_Const(self, node, frame):
1105 val = node.value
1106 if isinstance(val, float):
1107 # XXX: add checks for infinity and nan
1108 self.write(str(val))
1109 else:
1110 self.write(repr(val))
1111
Armin Ronacher8efc5222008-04-08 14:47:40 +02001112 def visit_Tuple(self, node, frame):
1113 self.write('(')
1114 idx = -1
1115 for idx, item in enumerate(node.items):
1116 if idx:
1117 self.write(', ')
1118 self.visit(item, frame)
1119 self.write(idx == 0 and ',)' or ')')
1120
Armin Ronacher8edbe492008-04-10 20:43:43 +02001121 def visit_List(self, node, frame):
1122 self.write('[')
1123 for idx, item in enumerate(node.items):
1124 if idx:
1125 self.write(', ')
1126 self.visit(item, frame)
1127 self.write(']')
1128
1129 def visit_Dict(self, node, frame):
1130 self.write('{')
1131 for idx, item in enumerate(node.items):
1132 if idx:
1133 self.write(', ')
1134 self.visit(item.key, frame)
1135 self.write(': ')
1136 self.visit(item.value, frame)
1137 self.write('}')
1138
Armin Ronachere791c2a2008-04-07 18:39:54 +02001139 def binop(operator):
1140 def visitor(self, node, frame):
1141 self.write('(')
1142 self.visit(node.left, frame)
1143 self.write(' %s ' % operator)
1144 self.visit(node.right, frame)
1145 self.write(')')
1146 return visitor
1147
1148 def uaop(operator):
1149 def visitor(self, node, frame):
1150 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001151 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001152 self.write(')')
1153 return visitor
1154
1155 visit_Add = binop('+')
1156 visit_Sub = binop('-')
1157 visit_Mul = binop('*')
1158 visit_Div = binop('/')
1159 visit_FloorDiv = binop('//')
1160 visit_Pow = binop('**')
1161 visit_Mod = binop('%')
1162 visit_And = binop('and')
1163 visit_Or = binop('or')
1164 visit_Pos = uaop('+')
1165 visit_Neg = uaop('-')
1166 visit_Not = uaop('not ')
1167 del binop, uaop
1168
Armin Ronacherd1342312008-04-28 12:20:12 +02001169 def visit_Concat(self, node, frame):
Armin Ronacher709f6e52008-04-28 18:18:16 +02001170 self.write('%s((' % self.environment.autoescape and
1171 'markup_join' or 'unicode_join')
Armin Ronacherd1342312008-04-28 12:20:12 +02001172 for arg in node.nodes:
1173 self.visit(arg, frame)
1174 self.write(', ')
1175 self.write('))')
1176
Armin Ronachere791c2a2008-04-07 18:39:54 +02001177 def visit_Compare(self, node, frame):
1178 self.visit(node.expr, frame)
1179 for op in node.ops:
1180 self.visit(op, frame)
1181
1182 def visit_Operand(self, node, frame):
1183 self.write(' %s ' % operators[node.op])
1184 self.visit(node.expr, frame)
1185
1186 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001187 if isinstance(node.arg, nodes.Slice):
1188 self.visit(node.node, frame)
1189 self.write('[')
1190 self.visit(node.arg, frame)
1191 self.write(']')
1192 return
1193 try:
1194 const = node.arg.as_const()
1195 have_const = True
1196 except nodes.Impossible:
1197 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001198 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001199 self.visit(node.node, frame)
1200 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001201 if have_const:
1202 self.write(repr(const))
1203 else:
1204 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001205 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001206
1207 def visit_Slice(self, node, frame):
1208 if node.start is not None:
1209 self.visit(node.start, frame)
1210 self.write(':')
1211 if node.stop is not None:
1212 self.visit(node.stop, frame)
1213 if node.step is not None:
1214 self.write(':')
1215 self.visit(node.step, frame)
1216
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001217 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001218 self.write('f_%s(' % node.name)
Christoph Hack80909862008-04-14 01:35:10 +02001219 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001220 if func is None:
1221 raise TemplateAssertionError('no filter named %r' % node.name,
1222 node.lineno, self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001223 if getattr(func, 'contextfilter', False):
1224 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001225 elif getattr(func, 'environmentfilter', False):
1226 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001227 if isinstance(node.node, nodes.Filter):
1228 self.visit_Filter(node.node, frame, initial)
1229 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001230 self.write(initial)
1231 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001232 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001233 self.signature(node, frame)
1234 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001235
1236 def visit_Test(self, node, frame):
Armin Ronacherf059ec12008-04-11 22:21:00 +02001237 self.write('t_%s(' % node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001238 if node.name not in self.environment.tests:
1239 raise TemplateAssertionError('no test named %r' % node.name,
1240 node.lineno, self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001241 self.visit(node.node, frame)
1242 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001243 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001244
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001245 def visit_CondExpr(self, node, frame):
1246 if not have_condexpr:
1247 self.write('((')
1248 self.visit(node.test, frame)
1249 self.write(') and (')
1250 self.visit(node.expr1, frame)
1251 self.write(',) or (')
1252 self.visit(node.expr2, frame)
1253 self.write(',))[0]')
1254 else:
1255 self.write('(')
1256 self.visit(node.expr1, frame)
1257 self.write(' if ')
1258 self.visit(node.test, frame)
1259 self.write(' else ')
1260 self.visit(node.expr2, frame)
1261 self.write(')')
1262
Armin Ronacher71082072008-04-12 14:19:36 +02001263 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001264 if self.environment.sandboxed:
1265 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001266 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001267 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001268 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001269 self.write(')')
1270
1271 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001272 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001273 self.visit(node.value, frame)