blob: 8b4abf6e655947032424343fe04f578807373a81 [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 Ronacher8e8d0712008-04-16 23:10:49 +020044 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020045 generator.visit(node)
46 if stream is None:
47 return generator.stream.getvalue()
48
49
Armin Ronacher4dfc9752008-04-09 15:03:29 +020050def has_safe_repr(value):
51 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020052 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020053 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020054 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher32a910f2008-04-26 23:21:03 +020055 xrange, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020056 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020057 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020058 for item in value:
59 if not has_safe_repr(item):
60 return False
61 return True
62 elif isinstance(value, dict):
63 for key, value in value.iteritems():
64 if not has_safe_repr(key):
65 return False
66 if not has_safe_repr(value):
67 return False
68 return True
69 return False
70
71
Armin Ronacherc9705c22008-04-27 21:28:03 +020072def find_undeclared(nodes, names):
73 """Check if the names passed are accessed undeclared. The return value
74 is a set of all the undeclared names from the sequence of names found.
75 """
76 visitor = UndeclaredNameVisitor(names)
77 try:
78 for node in nodes:
79 visitor.visit(node)
80 except VisitorExit:
81 pass
82 return visitor.undeclared
83
84
Armin Ronachere791c2a2008-04-07 18:39:54 +020085class Identifiers(object):
86 """Tracks the status of identifiers in frames."""
87
88 def __init__(self):
89 # variables that are known to be declared (probably from outer
90 # frames or because they are special for the frame)
91 self.declared = set()
92
Armin Ronacher10f3ba22008-04-18 11:30:37 +020093 # undeclared variables from outer scopes
94 self.outer_undeclared = set()
95
Armin Ronachere791c2a2008-04-07 18:39:54 +020096 # names that are accessed without being explicitly declared by
97 # this one or any of the outer scopes. Names can appear both in
98 # declared and undeclared.
99 self.undeclared = set()
100
101 # names that are declared locally
102 self.declared_locally = set()
103
104 # names that are declared by parameters
105 self.declared_parameter = set()
106
107 def add_special(self, name):
108 """Register a special name like `loop`."""
109 self.undeclared.discard(name)
110 self.declared.add(name)
111
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200112 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200113 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200114 if name in self.declared_locally or name in self.declared_parameter:
115 return True
116 if local_only:
117 return False
118 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200119
120 def find_shadowed(self):
121 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200122 return (self.declared | self.outer_undeclared) & \
123 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200124
125
126class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200127 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200128
129 def __init__(self, parent=None):
130 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200131
Armin Ronacher75cfb862008-04-11 13:47:22 +0200132 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200133 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200134
Armin Ronacher75cfb862008-04-11 13:47:22 +0200135 # the root frame is basically just the outermost frame, so no if
136 # conditions. This information is used to optimize inheritance
137 # situations.
138 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200139
140 # inside some tags we are using a buffer rather than yield statements.
141 # this for example affects {% filter %} or {% macro %}. If a frame
142 # is buffered this variable points to the name of the list used as
143 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200144 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200145
Armin Ronacherfed44b52008-04-13 19:42:53 +0200146 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200147 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200148
149 # the parent of this frame
150 self.parent = parent
151
Armin Ronachere791c2a2008-04-07 18:39:54 +0200152 if parent is not None:
153 self.identifiers.declared.update(
154 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200155 parent.identifiers.declared_locally |
156 parent.identifiers.declared_parameter
157 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200158 self.identifiers.outer_undeclared.update(
159 parent.identifiers.undeclared -
160 self.identifiers.declared
161 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200162 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200163
Armin Ronacher8efc5222008-04-08 14:47:40 +0200164 def copy(self):
165 """Create a copy of the current one."""
166 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200167 rv.identifiers = copy(self.identifiers)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200168 return rv
169
Armin Ronacherc9705c22008-04-27 21:28:03 +0200170 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200171 """Walk the node and check for identifiers. If the scope is hard (eg:
172 enforce on a python level) overrides from outer scopes are tracked
173 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200174 """
175 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200176 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200177 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200178
179 def inner(self):
180 """Return an inner frame."""
181 return Frame(self)
182
Armin Ronacher75cfb862008-04-11 13:47:22 +0200183 def soft(self):
184 """Return a soft frame. A soft frame may not be modified as
185 standalone thing as it shares the resources with the frame it
186 was created of, but it's not a rootlevel frame any longer.
187 """
188 rv = copy(self)
189 rv.rootlevel = False
190 return rv
191
Armin Ronachere791c2a2008-04-07 18:39:54 +0200192
Armin Ronacherc9705c22008-04-27 21:28:03 +0200193class VisitorExit(RuntimeError):
194 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
195
196
197class DependencyFinderVisitor(NodeVisitor):
198 """A visitor that collects filter and test calls."""
199
200 def __init__(self):
201 self.filters = set()
202 self.tests = set()
203
204 def visit_Filter(self, node):
205 self.generic_visit(node)
206 self.filters.add(node.name)
207
208 def visit_Test(self, node):
209 self.generic_visit(node)
210 self.tests.add(node.name)
211
212 def visit_Block(self, node):
213 """Stop visiting at blocks."""
214
215
216class UndeclaredNameVisitor(NodeVisitor):
217 """A visitor that checks if a name is accessed without being
218 declared. This is different from the frame visitor as it will
219 not stop at closure frames.
220 """
221
222 def __init__(self, names):
223 self.names = set(names)
224 self.undeclared = set()
225
226 def visit_Name(self, node):
227 if node.ctx == 'load' and node.name in self.names:
228 self.undeclared.add(node.name)
229 if self.undeclared == self.names:
230 raise VisitorExit()
231 else:
232 self.names.discard(node.name)
233
234 def visit_Block(self, node):
235 """Stop visiting a blocks."""
236
237
Armin Ronachere791c2a2008-04-07 18:39:54 +0200238class FrameIdentifierVisitor(NodeVisitor):
239 """A visitor for `Frame.inspect`."""
240
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200241 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200242 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200243 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200244
Armin Ronacherc9705c22008-04-27 21:28:03 +0200245 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200246 """All assignments to names go through this function."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200247 if node.ctx in ('store', 'param'):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200248 self.identifiers.declared_locally.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200249 elif node.ctx == 'load' and not \
250 self.identifiers.is_declared(node.name, self.hard_scope):
251 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200252
Armin Ronacherc9705c22008-04-27 21:28:03 +0200253 def visit_Macro(self, node):
254 self.generic_visit(node)
255 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200256
Armin Ronacherc9705c22008-04-27 21:28:03 +0200257 def visit_Import(self, node):
258 self.generic_visit(node)
259 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200260
Armin Ronacherc9705c22008-04-27 21:28:03 +0200261 def visit_FromImport(self, node):
262 self.generic_visit(node)
263 for name in node.names:
264 if isinstance(name, tuple):
265 self.identifiers.declared_locally.add(name[1])
266 else:
267 self.identifiers.declared_locally.add(name)
268
269 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200270 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200271 self.visit(node.node)
272 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200273
Armin Ronacherc9705c22008-04-27 21:28:03 +0200274 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200275 """Visiting stops at for blocks. However the block sequence
276 is visited as part of the outer scope.
277 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200278 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200279
Armin Ronacherc9705c22008-04-27 21:28:03 +0200280 def visit_CallBlock(self, node):
281 for child in node.iter_child_nodes(exclude=('body',)):
282 self.visit(child)
283
284 def visit_FilterBlock(self, node):
285 self.visit(node.filter)
286
287 def visit_Block(self, node):
288 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200289
290
Armin Ronacher75cfb862008-04-11 13:47:22 +0200291class CompilerExit(Exception):
292 """Raised if the compiler encountered a situation where it just
293 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200294 raises such an exception is not further processed.
295 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200296
297
Armin Ronachere791c2a2008-04-07 18:39:54 +0200298class CodeGenerator(NodeVisitor):
299
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200300 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200301 if stream is None:
302 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200303 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200304 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200305 self.filename = filename
306 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200307
308 # a registry for all blocks. Because blocks are moved out
309 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200310 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200311
312 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200313 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200314
315 # some templates have a rootlevel extends. In this case we
316 # can safely assume that we're a child template and do some
317 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200318 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200319
Armin Ronacherba3757b2008-04-16 19:43:16 +0200320 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200321 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200322
323 # the debug information
324 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200325 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200326
Armin Ronacherfed44b52008-04-13 19:42:53 +0200327 # the number of new lines before the next write()
328 self._new_lines = 0
329
330 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200331 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200332
333 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200334 self._first_write = True
335
Armin Ronacherfed44b52008-04-13 19:42:53 +0200336 # used by the `temporary_identifier` method to get new
337 # unique, temporary identifier
338 self._last_identifier = 0
339
340 # the current indentation
341 self._indentation = 0
342
Armin Ronachere791c2a2008-04-07 18:39:54 +0200343 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200344 """Get a new unique identifier."""
345 self._last_identifier += 1
346 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200347
348 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200349 """Indent by one."""
350 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200351
Armin Ronacher8efc5222008-04-08 14:47:40 +0200352 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200353 """Outdent by step."""
354 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200355
Armin Ronacherc9705c22008-04-27 21:28:03 +0200356 def blockvisit(self, nodes, frame, force_generator=True):
357 """Visit a list of nodes as block in a frame. If the current frame
358 is no buffer a dummy ``if 0: yield None`` is written automatically
359 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200360 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200361 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200362 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200363 try:
364 for node in nodes:
365 self.visit(node, frame)
366 except CompilerExit:
367 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200368
369 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200370 """Write a string into the output stream."""
371 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200372 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200373 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200374 self.code_lineno += self._new_lines
375 if self._write_debug_info is not None:
376 self.debug_info.append((self._write_debug_info,
377 self.code_lineno))
378 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200379 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200380 self.stream.write(' ' * self._indentation)
381 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200382 self.stream.write(x)
383
384 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200385 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200386 self.newline(node, extra)
387 self.write(x)
388
389 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200390 """Add one or more newlines before the next write."""
391 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200392 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200393 self._write_debug_info = node.lineno
394 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200395
Armin Ronacher71082072008-04-12 14:19:36 +0200396 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200397 """Writes a function call to the stream for the current node.
398 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200399 disabled by setting have_comma to False. The extra keyword
400 arguments may not include python keywords otherwise a syntax
401 error could occour. The extra keyword arguments should be given
402 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200403 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200404 have_comma = have_comma and [True] or []
405 def touch_comma():
406 if have_comma:
407 self.write(', ')
408 else:
409 have_comma.append(True)
410
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200411 # if any of the given keyword arguments is a python keyword
412 # we have to make sure that no invalid call is created.
413 kwarg_workaround = False
414 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
415 if iskeyword(kwarg):
416 kwarg_workaround = True
417 break
418
Armin Ronacher8efc5222008-04-08 14:47:40 +0200419 for arg in node.args:
420 touch_comma()
421 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200422
423 if not kwarg_workaround:
424 for kwarg in node.kwargs:
425 touch_comma()
426 self.visit(kwarg, frame)
427 if extra_kwargs is not None:
428 for key, value in extra_kwargs.iteritems():
429 touch_comma()
430 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200431 if node.dyn_args:
432 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200433 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200434 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200435
436 if kwarg_workaround:
437 touch_comma()
438 if node.dyn_kwargs is not None:
439 self.write('**dict({')
440 else:
441 self.write('**{')
442 for kwarg in node.kwargs:
443 self.write('%r: ' % kwarg.key)
444 self.visit(kwarg.value, frame)
445 self.write(', ')
446 if extra_kwargs is not None:
447 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200448 self.write('%r: %s, ' % (key, value))
449 if node.dyn_kwargs is not None:
450 self.write('}, **')
451 self.visit(node.dyn_kwargs, frame)
452 self.write(')')
453 else:
454 self.write('}')
455
456 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200457 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200458 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200459 self.visit(node.dyn_kwargs, frame)
460
Armin Ronacherc9705c22008-04-27 21:28:03 +0200461 def pull_locals(self, frame):
462 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200463 for name in frame.identifiers.undeclared:
464 self.writeline('l_%s = context[%r]' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200465
466 def pull_dependencies(self, nodes):
467 """Pull all the dependencies."""
468 visitor = DependencyFinderVisitor()
469 for node in nodes:
470 visitor.visit(node)
471 for name in visitor.filters:
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200472 self.writeline('f_%s = environment.filters[%r]' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200473 for name in visitor.tests:
Armin Ronacherf059ec12008-04-11 22:21:00 +0200474 self.writeline('t_%s = environment.tests[%r]' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200475
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200476 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200477 """This function returns all the shadowed variables in a dict
478 in the form name: alias and will write the required assignments
479 into the current scope. No indentation takes place.
480 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200481 # make sure we "backup" overridden, local identifiers
482 # TODO: we should probably optimize this and check if the
483 # identifier is in use afterwards.
484 aliases = {}
485 for name in frame.identifiers.find_shadowed():
486 aliases[name] = ident = self.temporary_identifier()
487 self.writeline('%s = l_%s' % (ident, name))
488 return aliases
489
Armin Ronacherc9705c22008-04-27 21:28:03 +0200490 def function_scoping(self, node, frame, children=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200491 """In Jinja a few statements require the help of anonymous
492 functions. Those are currently macros and call blocks and in
493 the future also recursive loops. As there is currently
494 technical limitation that doesn't allow reading and writing a
495 variable in a scope where the initial value is coming from an
496 outer scope, this function tries to fall back with a common
497 error message. Additionally the frame passed is modified so
498 that the argumetns are collected and callers are looked up.
499
500 This will return the modified frame.
501 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200502 # we have to iterate twice over it, make sure that works
503 if children is None:
504 children = node.iter_child_nodes()
505 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200506 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200507 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200508
509 # variables that are undeclared (accessed before declaration) and
510 # declared locally *and* part of an outside scope raise a template
511 # assertion error. Reason: we can't generate reasonable code from
512 # it without aliasing all the variables. XXX: alias them ^^
513 overriden_closure_vars = (
514 func_frame.identifiers.undeclared &
515 func_frame.identifiers.declared &
516 (func_frame.identifiers.declared_locally |
517 func_frame.identifiers.declared_parameter)
518 )
519 if overriden_closure_vars:
520 vars = ', '.join(sorted(overriden_closure_vars))
521 raise TemplateAssertionError('It\'s not possible to set and '
522 'access variables derived from '
523 'an outer scope! (affects: %s' %
Armin Ronacher68f77672008-04-17 11:50:39 +0200524 vars, node.lineno, self.name)
Armin Ronacher71082072008-04-12 14:19:36 +0200525
526 # remove variables from a closure from the frame's undeclared
527 # identifiers.
528 func_frame.identifiers.undeclared -= (
529 func_frame.identifiers.undeclared &
530 func_frame.identifiers.declared
531 )
532
Armin Ronacher963f97d2008-04-25 11:44:59 +0200533 func_frame.accesses_kwargs = False
534 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200535 func_frame.accesses_caller = False
536 func_frame.arguments = args = ['l_' + x.name for x in node.args]
537
Armin Ronacherc9705c22008-04-27 21:28:03 +0200538 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
539
540 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200541 func_frame.accesses_caller = True
542 func_frame.identifiers.add_special('caller')
543 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200544 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200545 func_frame.accesses_kwargs = True
546 func_frame.identifiers.add_special('kwargs')
547 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200548 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200549 func_frame.accesses_varargs = True
550 func_frame.identifiers.add_special('varargs')
551 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200552 return func_frame
553
Armin Ronachere791c2a2008-04-07 18:39:54 +0200554 # -- Visitors
555
556 def visit_Template(self, node, frame=None):
557 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200558 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200559 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200560 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200561 self.writeline('name = %r' % self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200562
Armin Ronacher75cfb862008-04-11 13:47:22 +0200563 # do we have an extends tag at all? If not, we can save some
564 # overhead by just not processing any inheritance code.
565 have_extends = node.find(nodes.Extends) is not None
566
Armin Ronacher8edbe492008-04-10 20:43:43 +0200567 # find all blocks
568 for block in node.find_all(nodes.Block):
569 if block.name in self.blocks:
570 raise TemplateAssertionError('block %r defined twice' %
571 block.name, block.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200572 self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200573 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200574
Armin Ronacher8efc5222008-04-08 14:47:40 +0200575 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200576 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200577
578 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200579 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200580 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200581 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200582 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200583 if have_extends:
584 self.writeline('parent_template = None')
585 self.pull_locals(frame)
586 self.pull_dependencies(node.body)
587 if 'self' in find_undeclared(node.body, ('self',)):
588 frame.identifiers.add_special('self')
589 self.writeline('l_self = TemplateReference(context)')
590 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200591 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200592
Armin Ronacher8efc5222008-04-08 14:47:40 +0200593 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200594 if have_extends:
595 if not self.has_known_extends:
596 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200597 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200598 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200599 self.writeline('for event in parent_template.'
600 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200601 self.indent()
602 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200603 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200604
605 # at this point we now have the blocks collected and can visit them too.
606 for name, block in self.blocks.iteritems():
607 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200608 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200609 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200610 self.writeline('def block_%s(context, environment=environment):'
611 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200612 self.indent()
613 undeclared = find_undeclared(block.body, ('self', 'super'))
614 if 'self' in undeclared:
615 block_frame.identifiers.add_special('self')
616 self.writeline('l_self = TemplateReference(context)')
617 if 'super' in undeclared:
618 block_frame.identifiers.add_special('super')
619 self.writeline('l_super = context.super(%r, '
620 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200621 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200622 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200623 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200624 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200625
Armin Ronacher75cfb862008-04-11 13:47:22 +0200626 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200627 for x in self.blocks),
628 extra=1)
629
630 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200631 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
632 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200633
Armin Ronachere791c2a2008-04-07 18:39:54 +0200634 def visit_Block(self, node, frame):
635 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200636 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200637 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200638 # if we know that we are a child template, there is no need to
639 # check if we are one
640 if self.has_known_extends:
641 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200642 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200643 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200644 self.indent()
645 level += 1
Armin Ronacherc9705c22008-04-27 21:28:03 +0200646 self.writeline('for event in context.blocks[%r][-1](context):' %
647 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200648 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200649 if frame.buffer is None:
650 self.writeline('yield event')
651 else:
652 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200653 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200654
655 def visit_Extends(self, node, frame):
656 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200657 if not frame.toplevel:
658 raise TemplateAssertionError('cannot use extend from a non '
659 'top-level scope', node.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200660 self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200661
Armin Ronacher7fb38972008-04-11 13:54:28 +0200662 # if the number of extends statements in general is zero so
663 # far, we don't have to add a check if something extended
664 # the template before this one.
665 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200666
Armin Ronacher7fb38972008-04-11 13:54:28 +0200667 # if we have a known extends we just add a template runtime
668 # error into the generated code. We could catch that at compile
669 # time too, but i welcome it not to confuse users by throwing the
670 # same error at different times just "because we can".
671 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200672 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200673 self.indent()
674 self.writeline('raise TemplateRuntimeError(%r)' %
675 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200676
Armin Ronacher7fb38972008-04-11 13:54:28 +0200677 # if we have a known extends already we don't need that code here
678 # as we know that the template execution will end here.
679 if self.has_known_extends:
680 raise CompilerExit()
681 self.outdent()
682
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200683 self.writeline('parent_template = environment.get_template(', node, 1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200684 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200685 self.write(', %r)' % self.name)
686 self.writeline('for name, parent_block in parent_template.'
687 'blocks.iteritems():')
688 self.indent()
689 self.writeline('context.blocks.setdefault(name, []).'
690 'insert(0, parent_block)')
691 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200692
693 # if this extends statement was in the root level we can take
694 # advantage of that information and simplify the generated code
695 # in the top level from this point onwards
696 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200697
Armin Ronacher7fb38972008-04-11 13:54:28 +0200698 # and now we have one more
699 self.extends_so_far += 1
700
Armin Ronacherf059ec12008-04-11 22:21:00 +0200701 def visit_Include(self, node, frame):
702 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200703 if node.with_context:
704 self.writeline('template = environment.get_template(', node)
705 self.visit(node.template, frame)
706 self.write(', %r)' % self.name)
707 self.writeline('for event in template.root_render_func('
708 'template.new_context(context.parent, True)):')
709 else:
710 self.writeline('for event in environment.get_template(', node)
711 self.visit(node.template, frame)
712 self.write(', %r).module._TemplateModule__body_stream:' %
713 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200714 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200715 if frame.buffer is None:
716 self.writeline('yield event')
717 else:
718 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200719 self.outdent()
720
Armin Ronacher0611e492008-04-25 23:44:14 +0200721 def visit_Import(self, node, frame):
722 """Visit regular imports."""
723 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200724 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200725 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200726 self.write('environment.get_template(')
727 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200728 self.write(', %r).' % self.name)
729 if node.with_context:
730 self.write('make_module(context.parent, True)')
731 else:
732 self.write('module')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200733 if frame.toplevel and not node.target.startswith('__'):
Armin Ronacher53042292008-04-26 18:30:19 +0200734 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200735
736 def visit_FromImport(self, node, frame):
737 """Visit named imports."""
738 self.newline(node)
739 self.write('included_template = environment.get_template(')
740 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200741 self.write(', %r).' % self.name)
742 if node.with_context:
743 self.write('make_module(context.parent, True)')
744 else:
745 self.write('module')
Armin Ronacher0611e492008-04-25 23:44:14 +0200746 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200747 if isinstance(name, tuple):
748 name, alias = name
749 else:
750 alias = name
Armin Ronacher0611e492008-04-25 23:44:14 +0200751 self.writeline('l_%s = getattr(included_template, '
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200752 '%r, missing)' % (alias, name))
753 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200754 self.indent()
755 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200756 'included_template.name, '
757 'name=included_template.name)' %
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200758 (alias, 'the template %r does not export '
Armin Ronacher0611e492008-04-25 23:44:14 +0200759 'the requested name ' + repr(name)))
760 self.outdent()
761 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200762 self.writeline('context.vars[%r] = l_%s' % (alias, alias))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200763 if not alias.startswith('__'):
764 self.writeline('context.exported_vars.discard(%r)' % alias)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200765
Armin Ronachere791c2a2008-04-07 18:39:54 +0200766 def visit_For(self, node, frame):
767 loop_frame = frame.inner()
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200768 loop_frame.inspect(node.iter_child_nodes(exclude=('iter',)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200769 extended_loop = bool(node.else_) or \
770 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200771 if extended_loop:
772 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200773
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200774 aliases = self.collect_shadowed(loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200775 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200776 if node.else_:
777 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200778
779 self.newline(node)
780 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200781 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200782 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200783
784 # the expression pointing to the parent loop. We make the
785 # undefined a bit more debug friendly at the same time.
786 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200787 or "environment.undefined(%r, name='loop')" % "'loop' " \
788 'is undefined. "the filter section of a loop as well ' \
789 'as the else block doesn\'t have access to the ' \
790 "special 'loop' variable of the current loop. " \
791 "Because there is no parent loop it's undefined."
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200792
793 # if we have an extened loop and a node test, we filter in the
794 # "outer frame".
795 if extended_loop and node.test is not None:
796 self.write('(')
797 self.visit(node.target, loop_frame)
798 self.write(' for ')
799 self.visit(node.target, loop_frame)
800 self.write(' in ')
801 self.visit(node.iter, loop_frame)
802 self.write(' if (')
803 test_frame = loop_frame.copy()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200804 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200805 self.visit(node.test, test_frame)
806 self.write('))')
807
808 else:
809 self.visit(node.iter, loop_frame)
810
Armin Ronachere791c2a2008-04-07 18:39:54 +0200811 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200812
813 # tests in not extended loops become a continue
814 if not extended_loop and node.test is not None:
815 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +0200816 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200817 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200818 self.write(':')
819 self.indent()
820 self.writeline('continue')
821 self.outdent(2)
822
Armin Ronacherc9705c22008-04-27 21:28:03 +0200823 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200824 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200825 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200826
827 if node.else_:
828 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200829 self.indent()
830 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher625215e2008-04-13 16:31:08 +0200831 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200832 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200833
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200834 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200835 for name, alias in aliases.iteritems():
Armin Ronacher8efc5222008-04-08 14:47:40 +0200836 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200837
838 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200839 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200840 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200841 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200842 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200843 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200844 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200845 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200846 if node.else_:
847 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200848 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200849 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200850 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200851
Armin Ronacher8efc5222008-04-08 14:47:40 +0200852 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200853 macro_frame = self.function_scoping(node, frame)
854 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200855 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200856 macro_frame.buffer = buf = self.temporary_identifier()
857 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200858 self.pull_locals(macro_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200859 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200860 self.blockvisit(node.body, macro_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200861 if self.environment.autoescape:
862 self.writeline('return Markup(concat(%s))' % buf)
863 else:
864 self.writeline("return concat(%s)" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200865 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200866 self.newline()
867 if frame.toplevel:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200868 if not node.name.startswith('__'):
869 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +0200870 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200871 arg_tuple = ', '.join(repr(x.name) for x in node.args)
872 if len(node.args) == 1:
873 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200874 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
875 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200876 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200877 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200878 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200879 self.write('), %s, %s, %s)' % (
880 macro_frame.accesses_kwargs and '1' or '0',
881 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200882 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200883 ))
884
885 def visit_CallBlock(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200886 call_frame = self.function_scoping(node, frame, node.iter_child_nodes
887 (exclude=('call',)))
Armin Ronacher71082072008-04-12 14:19:36 +0200888 args = call_frame.arguments
889 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200890 call_frame.buffer = buf = self.temporary_identifier()
891 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200892 self.pull_locals(call_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200893 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200894 self.blockvisit(node.body, call_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200895 if self.environment.autoescape:
896 self.writeline("return Markup(concat(%s))" % buf)
897 else:
898 self.writeline('return concat(%s)' % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200899 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200900 arg_tuple = ', '.join(repr(x.name) for x in node.args)
901 if len(node.args) == 1:
902 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200903 self.writeline('caller = Macro(environment, call, None, (%s), (' %
904 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200905 for arg in node.defaults:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200906 self.visit(arg, call_frame)
Armin Ronacher71082072008-04-12 14:19:36 +0200907 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200908 self.write('), %s, %s, 0)' % (
909 call_frame.accesses_kwargs and '1' or '0',
910 call_frame.accesses_varargs and '1' or '0'
911 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200912 if frame.buffer is None:
913 self.writeline('yield ', node)
914 else:
915 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200916 self.visit_Call(node.call, call_frame,
917 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200918 if frame.buffer is not None:
919 self.write(')')
920
921 def visit_FilterBlock(self, node, frame):
922 filter_frame = frame.inner()
923 filter_frame.inspect(node.iter_child_nodes())
924
925 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200926 self.pull_locals(filter_frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200927 filter_frame.buffer = buf = self.temporary_identifier()
928
929 self.writeline('%s = []' % buf, node)
930 for child in node.body:
931 self.visit(child, filter_frame)
932
933 if frame.buffer is None:
934 self.writeline('yield ', node)
935 else:
936 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200937 self.visit_Filter(node.filter, filter_frame, 'concat(%s)' % buf)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200938 if frame.buffer is not None:
939 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200940
Armin Ronachere791c2a2008-04-07 18:39:54 +0200941 def visit_ExprStmt(self, node, frame):
942 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +0200943 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200944
945 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200946 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +0200947 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200948 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200949
Armin Ronacher75cfb862008-04-11 13:47:22 +0200950 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200951
Armin Ronacher7fb38972008-04-11 13:54:28 +0200952 # if we are in the toplevel scope and there was already an extends
953 # statement we have to add a check that disables our yield(s) here
954 # so that they don't appear in the output.
955 outdent_later = False
956 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200957 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200958 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200959 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +0200960
Armin Ronachere791c2a2008-04-07 18:39:54 +0200961 # try to evaluate as many chunks as possible into a static
962 # string at compile time.
963 body = []
964 for child in node.nodes:
965 try:
966 const = unicode(child.as_const())
967 except:
968 body.append(child)
969 continue
970 if body and isinstance(body[-1], list):
971 body[-1].append(const)
972 else:
973 body.append([const])
974
Armin Ronacher32a910f2008-04-26 23:21:03 +0200975 # if we have less than 3 nodes or less than 6 and a buffer we
976 # yield or extend
977 if len(body) < 3 or (frame.buffer is not None and len(body) < 6):
978 if frame.buffer is not None:
979 self.writeline('%s.extend((' % frame.buffer)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200980 for item in body:
981 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +0200982 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200983 if frame.buffer is None:
984 self.writeline('yield ' + val)
985 else:
Armin Ronacher32a910f2008-04-26 23:21:03 +0200986 self.write(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200987 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200988 if frame.buffer is None:
Armin Ronacher32a910f2008-04-26 23:21:03 +0200989 self.writeline('yield ')
Armin Ronacherd1342312008-04-28 12:20:12 +0200990 close = 1
991 if self.environment.autoescape:
992 self.write('escape(')
993 else:
994 self.write('unicode(')
995 if self.environment.finalize is not None:
996 self.write('environment.finalize(')
997 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200998 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200999 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001000 if frame.buffer is not None:
1001 self.write(', ')
1002 if frame.buffer is not None:
1003 self.write('))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001004
1005 # otherwise we create a format string as this is faster in that case
1006 else:
1007 format = []
1008 arguments = []
1009 for item in body:
1010 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001011 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001012 else:
1013 format.append('%s')
1014 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001015 if frame.buffer is None:
1016 self.writeline('yield ')
1017 else:
1018 self.writeline('%s.append(' % frame.buffer)
Armin Ronacherde6bf712008-04-26 01:44:14 +02001019 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001020 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001021 self.indent()
1022 for argument in arguments:
1023 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001024 close = 0
1025 if self.environment.autoescape:
1026 self.write('escape(')
1027 close += 1
1028 if self.environment.finalize is not None:
1029 self.write('environment.finalize(')
1030 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001031 self.visit(argument, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001032 self.write(')' * close + ',')
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001033 self.outdent()
1034 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001035 if frame.buffer is not None:
1036 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001037
Armin Ronacher7fb38972008-04-11 13:54:28 +02001038 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001039 self.outdent()
1040
Armin Ronacher8efc5222008-04-08 14:47:40 +02001041 def visit_Assign(self, node, frame):
1042 self.newline(node)
1043 # toplevel assignments however go into the local namespace and
1044 # the current template's context. We create a copy of the frame
1045 # here and add a set so that the Name visitor can add the assigned
1046 # names here.
1047 if frame.toplevel:
1048 assignment_frame = frame.copy()
1049 assignment_frame.assigned_names = set()
1050 else:
1051 assignment_frame = frame
1052 self.visit(node.target, assignment_frame)
1053 self.write(' = ')
1054 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001055
1056 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001057 if frame.toplevel:
1058 for name in assignment_frame.assigned_names:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001059 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +02001060 if not name.startswith('__'):
1061 self.writeline('context.exported_vars.add(%r)' % name)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001062
Armin Ronachere791c2a2008-04-07 18:39:54 +02001063 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001064 if node.ctx == 'store' and frame.toplevel:
1065 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001066 self.write('l_' + node.name)
1067
Armin Ronacherd84ec462008-04-29 13:43:16 +02001068 def visit_MarkSafe(self, node, frame):
1069 self.write('Markup(')
1070 self.visit(node.expr, frame)
1071 self.write(')')
1072
Armin Ronachere791c2a2008-04-07 18:39:54 +02001073 def visit_Const(self, node, frame):
1074 val = node.value
1075 if isinstance(val, float):
1076 # XXX: add checks for infinity and nan
1077 self.write(str(val))
1078 else:
1079 self.write(repr(val))
1080
Armin Ronacher8efc5222008-04-08 14:47:40 +02001081 def visit_Tuple(self, node, frame):
1082 self.write('(')
1083 idx = -1
1084 for idx, item in enumerate(node.items):
1085 if idx:
1086 self.write(', ')
1087 self.visit(item, frame)
1088 self.write(idx == 0 and ',)' or ')')
1089
Armin Ronacher8edbe492008-04-10 20:43:43 +02001090 def visit_List(self, node, frame):
1091 self.write('[')
1092 for idx, item in enumerate(node.items):
1093 if idx:
1094 self.write(', ')
1095 self.visit(item, frame)
1096 self.write(']')
1097
1098 def visit_Dict(self, node, frame):
1099 self.write('{')
1100 for idx, item in enumerate(node.items):
1101 if idx:
1102 self.write(', ')
1103 self.visit(item.key, frame)
1104 self.write(': ')
1105 self.visit(item.value, frame)
1106 self.write('}')
1107
Armin Ronachere791c2a2008-04-07 18:39:54 +02001108 def binop(operator):
1109 def visitor(self, node, frame):
1110 self.write('(')
1111 self.visit(node.left, frame)
1112 self.write(' %s ' % operator)
1113 self.visit(node.right, frame)
1114 self.write(')')
1115 return visitor
1116
1117 def uaop(operator):
1118 def visitor(self, node, frame):
1119 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001120 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001121 self.write(')')
1122 return visitor
1123
1124 visit_Add = binop('+')
1125 visit_Sub = binop('-')
1126 visit_Mul = binop('*')
1127 visit_Div = binop('/')
1128 visit_FloorDiv = binop('//')
1129 visit_Pow = binop('**')
1130 visit_Mod = binop('%')
1131 visit_And = binop('and')
1132 visit_Or = binop('or')
1133 visit_Pos = uaop('+')
1134 visit_Neg = uaop('-')
1135 visit_Not = uaop('not ')
1136 del binop, uaop
1137
Armin Ronacherd1342312008-04-28 12:20:12 +02001138 def visit_Concat(self, node, frame):
Armin Ronacher709f6e52008-04-28 18:18:16 +02001139 self.write('%s((' % self.environment.autoescape and
1140 'markup_join' or 'unicode_join')
Armin Ronacherd1342312008-04-28 12:20:12 +02001141 for arg in node.nodes:
1142 self.visit(arg, frame)
1143 self.write(', ')
1144 self.write('))')
1145
Armin Ronachere791c2a2008-04-07 18:39:54 +02001146 def visit_Compare(self, node, frame):
1147 self.visit(node.expr, frame)
1148 for op in node.ops:
1149 self.visit(op, frame)
1150
1151 def visit_Operand(self, node, frame):
1152 self.write(' %s ' % operators[node.op])
1153 self.visit(node.expr, frame)
1154
1155 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001156 if isinstance(node.arg, nodes.Slice):
1157 self.visit(node.node, frame)
1158 self.write('[')
1159 self.visit(node.arg, frame)
1160 self.write(']')
1161 return
1162 try:
1163 const = node.arg.as_const()
1164 have_const = True
1165 except nodes.Impossible:
1166 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001167 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001168 self.visit(node.node, frame)
1169 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001170 if have_const:
1171 self.write(repr(const))
1172 else:
1173 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001174 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001175
1176 def visit_Slice(self, node, frame):
1177 if node.start is not None:
1178 self.visit(node.start, frame)
1179 self.write(':')
1180 if node.stop is not None:
1181 self.visit(node.stop, frame)
1182 if node.step is not None:
1183 self.write(':')
1184 self.visit(node.step, frame)
1185
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001186 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001187 self.write('f_%s(' % node.name)
Christoph Hack80909862008-04-14 01:35:10 +02001188 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001189 if func is None:
1190 raise TemplateAssertionError('no filter named %r' % node.name,
1191 node.lineno, self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001192 if getattr(func, 'contextfilter', False):
1193 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001194 elif getattr(func, 'environmentfilter', False):
1195 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001196 if isinstance(node.node, nodes.Filter):
1197 self.visit_Filter(node.node, frame, initial)
1198 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001199 self.write(initial)
1200 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001201 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001202 self.signature(node, frame)
1203 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001204
1205 def visit_Test(self, node, frame):
Armin Ronacherf059ec12008-04-11 22:21:00 +02001206 self.write('t_%s(' % node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001207 if node.name not in self.environment.tests:
1208 raise TemplateAssertionError('no test named %r' % node.name,
1209 node.lineno, self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001210 self.visit(node.node, frame)
1211 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001212 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001213
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001214 def visit_CondExpr(self, node, frame):
1215 if not have_condexpr:
1216 self.write('((')
1217 self.visit(node.test, frame)
1218 self.write(') and (')
1219 self.visit(node.expr1, frame)
1220 self.write(',) or (')
1221 self.visit(node.expr2, frame)
1222 self.write(',))[0]')
1223 else:
1224 self.write('(')
1225 self.visit(node.expr1, frame)
1226 self.write(' if ')
1227 self.visit(node.test, frame)
1228 self.write(' else ')
1229 self.visit(node.expr2, frame)
1230 self.write(')')
1231
Armin Ronacher71082072008-04-12 14:19:36 +02001232 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001233 if self.environment.sandboxed:
1234 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001235 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001236 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001237 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001238 self.write(')')
1239
1240 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001241 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001242 self.visit(node.value, frame)