blob: 8d58fbe04740d1fbd35d0bb404dfb212cdc84355 [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 Ronacher8efc5222008-04-08 14:47:40 +020011from copy import copy
Armin Ronachere791c2a2008-04-07 18:39:54 +020012from random import randrange
Armin Ronacher2feed1d2008-04-26 16:26:52 +020013from keyword import iskeyword
Armin Ronachere791c2a2008-04-07 18:39:54 +020014from cStringIO import StringIO
Armin Ronacher2feed1d2008-04-26 16:26:52 +020015from itertools import chain
Armin Ronachere791c2a2008-04-07 18:39:54 +020016from jinja2 import nodes
17from jinja2.visitor import NodeVisitor, NodeTransformer
18from jinja2.exceptions import TemplateAssertionError
Armin Ronacherde6bf712008-04-26 01:44:14 +020019from jinja2.runtime import StaticLoopContext, concat
Armin Ronacher5236d8c2008-04-17 11:23:16 +020020from jinja2.utils import Markup
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
34
Armin Ronacher3d8b7842008-04-13 13:16:50 +020035try:
36 exec '(0 if 0 else 0)'
37except SyntaxError:
38 have_condexpr = False
39else:
40 have_condexpr = True
41
42
Armin Ronacher8e8d0712008-04-16 23:10:49 +020043def generate(node, environment, name, filename, stream=None):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020044 """Generate the python source for a node tree."""
Armin Ronacher8e8d0712008-04-16 23:10:49 +020045 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020046 generator.visit(node)
47 if stream is None:
48 return generator.stream.getvalue()
49
50
Armin Ronacher4dfc9752008-04-09 15:03:29 +020051def has_safe_repr(value):
52 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020053 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020054 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020055 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher5236d8c2008-04-17 11:23:16 +020056 xrange, StaticLoopContext, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020057 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020058 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020059 for item in value:
60 if not has_safe_repr(item):
61 return False
62 return True
63 elif isinstance(value, dict):
64 for key, value in value.iteritems():
65 if not has_safe_repr(key):
66 return False
67 if not has_safe_repr(value):
68 return False
69 return True
70 return False
71
72
Armin Ronachere791c2a2008-04-07 18:39:54 +020073class Identifiers(object):
74 """Tracks the status of identifiers in frames."""
75
76 def __init__(self):
77 # variables that are known to be declared (probably from outer
78 # frames or because they are special for the frame)
79 self.declared = set()
80
Armin Ronacher10f3ba22008-04-18 11:30:37 +020081 # undeclared variables from outer scopes
82 self.outer_undeclared = set()
83
Armin Ronachere791c2a2008-04-07 18:39:54 +020084 # names that are accessed without being explicitly declared by
85 # this one or any of the outer scopes. Names can appear both in
86 # declared and undeclared.
87 self.undeclared = set()
88
89 # names that are declared locally
90 self.declared_locally = set()
91
92 # names that are declared by parameters
93 self.declared_parameter = set()
94
Armin Ronacherf059ec12008-04-11 22:21:00 +020095 # filters/tests that are referenced
Armin Ronacherd4c64f72008-04-11 17:15:29 +020096 self.filters = set()
Armin Ronacherf059ec12008-04-11 22:21:00 +020097 self.tests = set()
Christoph Hack65642a52008-04-08 14:46:56 +020098
Armin Ronachere791c2a2008-04-07 18:39:54 +020099 def add_special(self, name):
100 """Register a special name like `loop`."""
101 self.undeclared.discard(name)
102 self.declared.add(name)
103
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200104 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200105 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200106 if name in self.declared_locally or name in self.declared_parameter:
107 return True
108 if local_only:
109 return False
110 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200111
112 def find_shadowed(self):
113 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200114 return (self.declared | self.outer_undeclared) & \
115 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200116
117
118class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200119 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200120
121 def __init__(self, parent=None):
122 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200123
Armin Ronacher75cfb862008-04-11 13:47:22 +0200124 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200125 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200126
Armin Ronacher75cfb862008-04-11 13:47:22 +0200127 # the root frame is basically just the outermost frame, so no if
128 # conditions. This information is used to optimize inheritance
129 # situations.
130 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200131
132 # inside some tags we are using a buffer rather than yield statements.
133 # this for example affects {% filter %} or {% macro %}. If a frame
134 # is buffered this variable points to the name of the list used as
135 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200136 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200137
138 # if a frame has name_overrides, all read access to a name in this
139 # dict is redirected to a string expression.
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200140 self.name_overrides = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200141
142 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200143 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200144
145 # the parent of this frame
146 self.parent = parent
147
Armin Ronachere791c2a2008-04-07 18:39:54 +0200148 if parent is not None:
149 self.identifiers.declared.update(
150 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200151 parent.identifiers.declared_locally |
152 parent.identifiers.declared_parameter
153 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200154 self.identifiers.outer_undeclared.update(
155 parent.identifiers.undeclared -
156 self.identifiers.declared
157 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200158 self.buffer = parent.buffer
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200159 self.name_overrides = parent.name_overrides.copy()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200160
Armin Ronacher8efc5222008-04-08 14:47:40 +0200161 def copy(self):
162 """Create a copy of the current one."""
163 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200164 rv.identifiers = copy(self.identifiers)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200165 rv.name_overrides = self.name_overrides.copy()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200166 return rv
167
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200168 def inspect(self, nodes, with_depenencies=False, hard_scope=False):
169 """Walk the node and check for identifiers. If the scope is hard (eg:
170 enforce on a python level) overrides from outer scopes are tracked
171 differently.
172
173 Per default filters and tests (dependencies) are not tracked. That's
174 the case because filters and tests are absolutely immutable and so we
175 can savely use them in closures too. The `Template` and `Block`
176 visitor visits the frame with dependencies to collect them.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200177 """
178 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200179 for node in nodes:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200180 visitor.visit(node, True, with_depenencies)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200181
182 def inner(self):
183 """Return an inner frame."""
184 return Frame(self)
185
Armin Ronacher75cfb862008-04-11 13:47:22 +0200186 def soft(self):
187 """Return a soft frame. A soft frame may not be modified as
188 standalone thing as it shares the resources with the frame it
189 was created of, but it's not a rootlevel frame any longer.
190 """
191 rv = copy(self)
192 rv.rootlevel = False
193 return rv
194
Armin Ronachere791c2a2008-04-07 18:39:54 +0200195
196class FrameIdentifierVisitor(NodeVisitor):
197 """A visitor for `Frame.inspect`."""
198
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200199 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200200 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200201 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200202
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200203 def visit_Name(self, node, visit_ident, visit_deps):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200204 """All assignments to names go through this function."""
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200205 if visit_ident:
206 if node.ctx in ('store', 'param'):
207 self.identifiers.declared_locally.add(node.name)
208 elif node.ctx == 'load' and not \
209 self.identifiers.is_declared(node.name, self.hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200210 self.identifiers.undeclared.add(node.name)
211
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200212 def visit_Filter(self, node, visit_ident, visit_deps):
213 if visit_deps:
214 self.generic_visit(node, visit_ident, True)
215 self.identifiers.filters.add(node.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200216
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200217 def visit_Test(self, node, visit_ident, visit_deps):
218 if visit_deps:
219 self.generic_visit(node, visit_ident, True)
220 self.identifiers.tests.add(node.name)
Christoph Hack65642a52008-04-08 14:46:56 +0200221
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200222 def visit_Macro(self, node, visit_ident, visit_deps):
223 if visit_ident:
224 self.identifiers.declared_locally.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200225
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200226 def visit_Import(self, node, visit_ident, visit_deps):
227 if visit_ident:
228 self.generic_visit(node, True, visit_deps)
229 self.identifiers.declared_locally.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200230
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200231 def visit_FromImport(self, node, visit_ident, visit_deps):
232 if visit_ident:
233 self.generic_visit(node, True, visit_deps)
234 for name in node.names:
235 if isinstance(name, tuple):
236 self.identifiers.declared_locally.add(name[1])
237 else:
238 self.identifiers.declared_locally.add(name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200239
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200240 def visit_Assign(self, node, visit_ident, visit_deps):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200241 """Visit assignments in the correct order."""
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200242 self.visit(node.node, visit_ident, visit_deps)
243 self.visit(node.target, visit_ident, visit_deps)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200244
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200245 def visit_For(self, node, visit_ident, visit_deps):
246 """Visiting stops at for blocks. However the block sequence
247 is visited as part of the outer scope.
248 """
249 if visit_ident:
250 self.visit(node.iter, True, visit_deps)
251 if visit_deps:
252 for child in node.iter_child_nodes(exclude=('iter',)):
253 self.visit(child, False, True)
254
255 def ident_stop(self, node, visit_ident, visit_deps):
256 if visit_deps:
257 self.generic_visit(node, False, True)
258 visit_CallBlock = visit_FilterBlock = ident_stop
259 visit_Block = lambda s, n, a, b: None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200260
261
Armin Ronacher75cfb862008-04-11 13:47:22 +0200262class CompilerExit(Exception):
263 """Raised if the compiler encountered a situation where it just
264 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200265 raises such an exception is not further processed.
266 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200267
268
Armin Ronachere791c2a2008-04-07 18:39:54 +0200269class CodeGenerator(NodeVisitor):
270
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200271 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200272 if stream is None:
273 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200274 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200275 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200276 self.filename = filename
277 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200278
279 # a registry for all blocks. Because blocks are moved out
280 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200281 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200282
283 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200284 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200285
286 # some templates have a rootlevel extends. In this case we
287 # can safely assume that we're a child template and do some
288 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200289 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200290
Armin Ronacherba3757b2008-04-16 19:43:16 +0200291 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200292 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200293
294 # the debug information
295 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200296 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200297
Armin Ronacherfed44b52008-04-13 19:42:53 +0200298 # the number of new lines before the next write()
299 self._new_lines = 0
300
301 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200302 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200303
304 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200305 self._first_write = True
306
Armin Ronacherfed44b52008-04-13 19:42:53 +0200307 # used by the `temporary_identifier` method to get new
308 # unique, temporary identifier
309 self._last_identifier = 0
310
311 # the current indentation
312 self._indentation = 0
313
Armin Ronachere791c2a2008-04-07 18:39:54 +0200314 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200315 """Get a new unique identifier."""
316 self._last_identifier += 1
317 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200318
319 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200320 """Indent by one."""
321 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200322
Armin Ronacher8efc5222008-04-08 14:47:40 +0200323 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200324 """Outdent by step."""
325 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200326
Armin Ronacher625215e2008-04-13 16:31:08 +0200327 def blockvisit(self, nodes, frame, indent=True, force_generator=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200328 """Visit a list of nodes as block in a frame. Per default the
329 code is indented, but this can be disabled by setting the indent
330 parameter to False. If the current frame is no buffer a dummy
331 ``if 0: yield None`` is written automatically unless the
332 force_generator parameter is set to False.
333 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200334 if indent:
335 self.indent()
336 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200337 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200338 try:
339 for node in nodes:
340 self.visit(node, frame)
341 except CompilerExit:
342 pass
Armin Ronacher625215e2008-04-13 16:31:08 +0200343 if indent:
344 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200345
346 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200347 """Write a string into the output stream."""
348 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200349 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200350 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200351 self.code_lineno += self._new_lines
352 if self._write_debug_info is not None:
353 self.debug_info.append((self._write_debug_info,
354 self.code_lineno))
355 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200356 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200357 self.stream.write(' ' * self._indentation)
358 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200359 self.stream.write(x)
360
361 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200362 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200363 self.newline(node, extra)
364 self.write(x)
365
366 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200367 """Add one or more newlines before the next write."""
368 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200369 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200370 self._write_debug_info = node.lineno
371 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200372
Armin Ronacher71082072008-04-12 14:19:36 +0200373 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200374 """Writes a function call to the stream for the current node.
375 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200376 disabled by setting have_comma to False. The extra keyword
377 arguments may not include python keywords otherwise a syntax
378 error could occour. The extra keyword arguments should be given
379 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200380 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200381 have_comma = have_comma and [True] or []
382 def touch_comma():
383 if have_comma:
384 self.write(', ')
385 else:
386 have_comma.append(True)
387
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200388 # if any of the given keyword arguments is a python keyword
389 # we have to make sure that no invalid call is created.
390 kwarg_workaround = False
391 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
392 if iskeyword(kwarg):
393 kwarg_workaround = True
394 break
395
Armin Ronacher8efc5222008-04-08 14:47:40 +0200396 for arg in node.args:
397 touch_comma()
398 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200399
400 if not kwarg_workaround:
401 for kwarg in node.kwargs:
402 touch_comma()
403 self.visit(kwarg, frame)
404 if extra_kwargs is not None:
405 for key, value in extra_kwargs.iteritems():
406 touch_comma()
407 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200408 if node.dyn_args:
409 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200410 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200411 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200412
413 if kwarg_workaround:
414 touch_comma()
415 if node.dyn_kwargs is not None:
416 self.write('**dict({')
417 else:
418 self.write('**{')
419 for kwarg in node.kwargs:
420 self.write('%r: ' % kwarg.key)
421 self.visit(kwarg.value, frame)
422 self.write(', ')
423 if extra_kwargs is not None:
424 for key, value in extra_kwargs.iteritems():
425 touch_comma()
426 self.write('%r: %s, ' % (key, value))
427 if node.dyn_kwargs is not None:
428 self.write('}, **')
429 self.visit(node.dyn_kwargs, frame)
430 self.write(')')
431 else:
432 self.write('}')
433
434 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200435 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200436 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200437 self.visit(node.dyn_kwargs, frame)
438
Armin Ronacher625215e2008-04-13 16:31:08 +0200439 def pull_locals(self, frame, indent=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200440 """Pull all the references identifiers into the local scope.
441 This affects regular names, filters and tests. If indent is
442 set to False, no automatic indentation will take place.
443 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200444 if indent:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200445 self.indent()
446 for name in frame.identifiers.undeclared:
447 self.writeline('l_%s = context[%r]' % (name, name))
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200448 for name in frame.identifiers.filters:
449 self.writeline('f_%s = environment.filters[%r]' % (name, name))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200450 for name in frame.identifiers.tests:
451 self.writeline('t_%s = environment.tests[%r]' % (name, name))
Armin Ronacher625215e2008-04-13 16:31:08 +0200452 if indent:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200453 self.outdent()
454
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200455 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200456 """This function returns all the shadowed variables in a dict
457 in the form name: alias and will write the required assignments
458 into the current scope. No indentation takes place.
459 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200460 # make sure we "backup" overridden, local identifiers
461 # TODO: we should probably optimize this and check if the
462 # identifier is in use afterwards.
463 aliases = {}
464 for name in frame.identifiers.find_shadowed():
465 aliases[name] = ident = self.temporary_identifier()
466 self.writeline('%s = l_%s' % (ident, name))
467 return aliases
468
Armin Ronacher71082072008-04-12 14:19:36 +0200469 def function_scoping(self, node, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200470 """In Jinja a few statements require the help of anonymous
471 functions. Those are currently macros and call blocks and in
472 the future also recursive loops. As there is currently
473 technical limitation that doesn't allow reading and writing a
474 variable in a scope where the initial value is coming from an
475 outer scope, this function tries to fall back with a common
476 error message. Additionally the frame passed is modified so
477 that the argumetns are collected and callers are looked up.
478
479 This will return the modified frame.
480 """
Armin Ronacher71082072008-04-12 14:19:36 +0200481 func_frame = frame.inner()
482 func_frame.inspect(node.iter_child_nodes(), hard_scope=True)
483
484 # variables that are undeclared (accessed before declaration) and
485 # declared locally *and* part of an outside scope raise a template
486 # assertion error. Reason: we can't generate reasonable code from
487 # it without aliasing all the variables. XXX: alias them ^^
488 overriden_closure_vars = (
489 func_frame.identifiers.undeclared &
490 func_frame.identifiers.declared &
491 (func_frame.identifiers.declared_locally |
492 func_frame.identifiers.declared_parameter)
493 )
494 if overriden_closure_vars:
495 vars = ', '.join(sorted(overriden_closure_vars))
496 raise TemplateAssertionError('It\'s not possible to set and '
497 'access variables derived from '
498 'an outer scope! (affects: %s' %
Armin Ronacher68f77672008-04-17 11:50:39 +0200499 vars, node.lineno, self.name)
Armin Ronacher71082072008-04-12 14:19:36 +0200500
501 # remove variables from a closure from the frame's undeclared
502 # identifiers.
503 func_frame.identifiers.undeclared -= (
504 func_frame.identifiers.undeclared &
505 func_frame.identifiers.declared
506 )
507
Armin Ronacher963f97d2008-04-25 11:44:59 +0200508 func_frame.accesses_kwargs = False
509 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200510 func_frame.accesses_caller = False
511 func_frame.arguments = args = ['l_' + x.name for x in node.args]
512
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200513 if 'caller' in func_frame.identifiers.undeclared:
514 func_frame.accesses_caller = True
515 func_frame.identifiers.add_special('caller')
516 args.append('l_caller')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200517 if 'kwargs' in func_frame.identifiers.undeclared:
518 func_frame.accesses_kwargs = True
519 func_frame.identifiers.add_special('kwargs')
520 args.append('l_kwargs')
521 if 'varargs' in func_frame.identifiers.undeclared:
522 func_frame.accesses_varargs = True
523 func_frame.identifiers.add_special('varargs')
524 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200525 return func_frame
526
Armin Ronachere791c2a2008-04-07 18:39:54 +0200527 # -- Visitors
528
529 def visit_Template(self, node, frame=None):
530 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200531 from jinja2.runtime import __all__ as exported
532 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200533 self.writeline('name = %r' % self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200534
Armin Ronacher75cfb862008-04-11 13:47:22 +0200535 # do we have an extends tag at all? If not, we can save some
536 # overhead by just not processing any inheritance code.
537 have_extends = node.find(nodes.Extends) is not None
538
Armin Ronacher8edbe492008-04-10 20:43:43 +0200539 # find all blocks
540 for block in node.find_all(nodes.Block):
541 if block.name in self.blocks:
542 raise TemplateAssertionError('block %r defined twice' %
543 block.name, block.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200544 self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200545 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200546
Armin Ronacher8efc5222008-04-08 14:47:40 +0200547 # generate the root render function.
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200548 self.writeline('def root(context, environment=environment'
549 '):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200550 if have_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200551 self.indent()
552 self.writeline('parent_template = None')
553 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200554
555 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200556 frame = Frame()
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200557 frame.inspect(node.body, with_depenencies=True)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200558 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200559 self.indent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200560 self.pull_locals(frame, indent=False)
Armin Ronacher625215e2008-04-13 16:31:08 +0200561 self.blockvisit(node.body, frame, indent=False)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200562 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200563
Armin Ronacher8efc5222008-04-08 14:47:40 +0200564 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200565 if have_extends:
566 if not self.has_known_extends:
567 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200568 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200569 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200570 self.writeline('for event in parent_template.'
571 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200572 self.indent()
573 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200574 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200575
576 # at this point we now have the blocks collected and can visit them too.
577 for name, block in self.blocks.iteritems():
578 block_frame = Frame()
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200579 block_frame.inspect(block.body, with_depenencies=True)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200580 block_frame.block = name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200581 block_frame.identifiers.add_special('super')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200582 block_frame.name_overrides['super'] = 'context.super(%r, ' \
583 'block_%s)' % (name, name)
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200584 self.writeline('def block_%s(context, environment=environment):'
585 % name, block, 1)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200586 self.pull_locals(block_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200587 self.blockvisit(block.body, block_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200588
Armin Ronacher75cfb862008-04-11 13:47:22 +0200589 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200590 for x in self.blocks),
591 extra=1)
592
593 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200594 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
595 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200596
Armin Ronachere791c2a2008-04-07 18:39:54 +0200597 def visit_Block(self, node, frame):
598 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200599 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200600 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200601 # if we know that we are a child template, there is no need to
602 # check if we are one
603 if self.has_known_extends:
604 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200605 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200606 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200607 self.indent()
608 level += 1
609 self.writeline('for event in context.blocks[%r][-1](context):' % node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200610 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200611 if frame.buffer is None:
612 self.writeline('yield event')
613 else:
614 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200615 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200616
617 def visit_Extends(self, node, frame):
618 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200619 if not frame.toplevel:
620 raise TemplateAssertionError('cannot use extend from a non '
621 'top-level scope', node.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200622 self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200623
Armin Ronacher7fb38972008-04-11 13:54:28 +0200624 # if the number of extends statements in general is zero so
625 # far, we don't have to add a check if something extended
626 # the template before this one.
627 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200628
Armin Ronacher7fb38972008-04-11 13:54:28 +0200629 # if we have a known extends we just add a template runtime
630 # error into the generated code. We could catch that at compile
631 # time too, but i welcome it not to confuse users by throwing the
632 # same error at different times just "because we can".
633 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200634 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200635 self.indent()
636 self.writeline('raise TemplateRuntimeError(%r)' %
637 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200638
Armin Ronacher7fb38972008-04-11 13:54:28 +0200639 # if we have a known extends already we don't need that code here
640 # as we know that the template execution will end here.
641 if self.has_known_extends:
642 raise CompilerExit()
643 self.outdent()
644
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200645 self.writeline('parent_template = environment.get_template(', node, 1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200646 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200647 self.write(', %r)' % self.name)
648 self.writeline('for name, parent_block in parent_template.'
649 'blocks.iteritems():')
650 self.indent()
651 self.writeline('context.blocks.setdefault(name, []).'
652 'insert(0, parent_block)')
653 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200654
655 # if this extends statement was in the root level we can take
656 # advantage of that information and simplify the generated code
657 # in the top level from this point onwards
658 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200659
Armin Ronacher7fb38972008-04-11 13:54:28 +0200660 # and now we have one more
661 self.extends_so_far += 1
662
Armin Ronacherf059ec12008-04-11 22:21:00 +0200663 def visit_Include(self, node, frame):
664 """Handles includes."""
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200665 self.writeline('included_template = environment.get_template(', node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200666 self.visit(node.template, frame)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200667 self.write(', %r)' % self.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200668 self.writeline('for event in included_template.root_render_func('
669 'included_template.new_context(context.get_root())):')
Armin Ronacherf059ec12008-04-11 22:21:00 +0200670 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200671 if frame.buffer is None:
672 self.writeline('yield event')
673 else:
674 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200675 self.outdent()
676
Armin Ronacher0611e492008-04-25 23:44:14 +0200677 def visit_Import(self, node, frame):
678 """Visit regular imports."""
679 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200680 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200681 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200682 self.write('environment.get_template(')
683 self.visit(node.template, frame)
684 self.write(', %r).include(context)' % self.name)
Armin Ronacher53042292008-04-26 18:30:19 +0200685 if frame.toplevel:
686 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200687
688 def visit_FromImport(self, node, frame):
689 """Visit named imports."""
690 self.newline(node)
691 self.write('included_template = environment.get_template(')
692 self.visit(node.template, frame)
693 self.write(', %r).include(context)' % self.name)
694 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200695 if isinstance(name, tuple):
696 name, alias = name
697 else:
698 alias = name
Armin Ronacher0611e492008-04-25 23:44:14 +0200699 self.writeline('l_%s = getattr(included_template, '
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200700 '%r, missing)' % (alias, name))
701 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200702 self.indent()
703 self.writeline('l_%s = environment.undefined(%r %% '
704 'included_template.name)' %
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200705 (alias, 'the template %r does not export '
Armin Ronacher0611e492008-04-25 23:44:14 +0200706 'the requested name ' + repr(name)))
707 self.outdent()
708 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200709 self.writeline('context.vars[%r] = l_%s' % (alias, alias))
710 self.writeline('context.exported_vars.discard(%r)' % alias)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200711
Armin Ronachere791c2a2008-04-07 18:39:54 +0200712 def visit_For(self, node, frame):
713 loop_frame = frame.inner()
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200714 loop_frame.inspect(node.iter_child_nodes(exclude=('iter',)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200715 extended_loop = bool(node.else_) or \
716 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200717 if extended_loop:
718 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200719
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200720 aliases = self.collect_shadowed(loop_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200721 self.pull_locals(loop_frame, indent=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200722 if node.else_:
723 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200724
725 self.newline(node)
726 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200727 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200728 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200729
730 # the expression pointing to the parent loop. We make the
731 # undefined a bit more debug friendly at the same time.
732 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200733 or "environment.undefined(%r)" % "'loop' is undefined. " \
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200734 'the filter section of a loop as well as the ' \
735 'else block doesn\'t have access to the special ' \
736 "'loop' variable of the current loop. Because " \
737 'there is no parent loop it\'s undefined.'
738
739 # if we have an extened loop and a node test, we filter in the
740 # "outer frame".
741 if extended_loop and node.test is not None:
742 self.write('(')
743 self.visit(node.target, loop_frame)
744 self.write(' for ')
745 self.visit(node.target, loop_frame)
746 self.write(' in ')
747 self.visit(node.iter, loop_frame)
748 self.write(' if (')
749 test_frame = loop_frame.copy()
750 test_frame.name_overrides['loop'] = parent_loop
751 self.visit(node.test, test_frame)
752 self.write('))')
753
754 else:
755 self.visit(node.iter, loop_frame)
756
Armin Ronachere791c2a2008-04-07 18:39:54 +0200757 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200758
759 # tests in not extended loops become a continue
760 if not extended_loop and node.test is not None:
761 self.indent()
762 self.writeline('if ')
763 self.visit(node.test)
764 self.write(':')
765 self.indent()
766 self.writeline('continue')
767 self.outdent(2)
768
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200769 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200770
771 if node.else_:
772 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200773 self.indent()
774 self.writeline('l_loop = ' + parent_loop)
775 self.outdent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200776 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200777
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200778 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200779 for name, alias in aliases.iteritems():
Armin Ronacher8efc5222008-04-08 14:47:40 +0200780 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200781
782 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200783 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200784 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200785 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200786 self.write(':')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200787 self.blockvisit(node.body, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200788 if node.else_:
789 self.writeline('else:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200790 self.blockvisit(node.else_, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200791
Armin Ronacher8efc5222008-04-08 14:47:40 +0200792 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200793 macro_frame = self.function_scoping(node, frame)
794 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200795 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200796 macro_frame.buffer = buf = self.temporary_identifier()
797 self.indent()
798 self.pull_locals(macro_frame, indent=False)
799 self.writeline('%s = []' % buf)
800 self.blockvisit(node.body, macro_frame, indent=False)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200801 self.writeline("return Markup(concat(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200802 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200803 self.newline()
804 if frame.toplevel:
805 self.write('context[%r] = ' % node.name)
806 arg_tuple = ', '.join(repr(x.name) for x in node.args)
807 if len(node.args) == 1:
808 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200809 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
810 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200811 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200812 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200813 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200814 self.write('), %s, %s, %s)' % (
815 macro_frame.accesses_kwargs and '1' or '0',
816 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200817 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200818 ))
819
820 def visit_CallBlock(self, node, frame):
821 call_frame = self.function_scoping(node, frame)
822 args = call_frame.arguments
823 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200824 call_frame.buffer = buf = self.temporary_identifier()
825 self.indent()
826 self.pull_locals(call_frame, indent=False)
827 self.writeline('%s = []' % buf)
828 self.blockvisit(node.body, call_frame, indent=False)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200829 self.writeline("return Markup(concat(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200830 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200831 arg_tuple = ', '.join(repr(x.name) for x in node.args)
832 if len(node.args) == 1:
833 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200834 self.writeline('caller = Macro(environment, call, None, (%s), (' %
835 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200836 for arg in node.defaults:
837 self.visit(arg)
838 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200839 self.write('), %s, %s, 0)' % (
840 call_frame.accesses_kwargs and '1' or '0',
841 call_frame.accesses_varargs and '1' or '0'
842 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200843 if frame.buffer is None:
844 self.writeline('yield ', node)
845 else:
846 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200847 self.visit_Call(node.call, call_frame,
848 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200849 if frame.buffer is not None:
850 self.write(')')
851
852 def visit_FilterBlock(self, node, frame):
853 filter_frame = frame.inner()
854 filter_frame.inspect(node.iter_child_nodes())
855
856 aliases = self.collect_shadowed(filter_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200857 self.pull_locals(filter_frame, indent=False)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200858 filter_frame.buffer = buf = self.temporary_identifier()
859
860 self.writeline('%s = []' % buf, node)
861 for child in node.body:
862 self.visit(child, filter_frame)
863
864 if frame.buffer is None:
865 self.writeline('yield ', node)
866 else:
867 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200868 self.visit_Filter(node.filter, filter_frame, 'concat(%s)' % buf)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200869 if frame.buffer is not None:
870 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200871
Armin Ronachere791c2a2008-04-07 18:39:54 +0200872 def visit_ExprStmt(self, node, frame):
873 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +0200874 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200875
876 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200877 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +0200878 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200879 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200880
Armin Ronacher75cfb862008-04-11 13:47:22 +0200881 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200882 if self.environment.finalize is unicode:
883 finalizer = 'unicode'
Armin Ronacherf059ec12008-04-11 22:21:00 +0200884 have_finalizer = False
Armin Ronacher8edbe492008-04-10 20:43:43 +0200885 else:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200886 finalizer = 'environment.finalize'
887 have_finalizer = True
Armin Ronacher8edbe492008-04-10 20:43:43 +0200888
Armin Ronacher7fb38972008-04-11 13:54:28 +0200889 # if we are in the toplevel scope and there was already an extends
890 # statement we have to add a check that disables our yield(s) here
891 # so that they don't appear in the output.
892 outdent_later = False
893 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200894 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200895 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200896 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +0200897
Armin Ronachere791c2a2008-04-07 18:39:54 +0200898 # try to evaluate as many chunks as possible into a static
899 # string at compile time.
900 body = []
901 for child in node.nodes:
902 try:
903 const = unicode(child.as_const())
904 except:
905 body.append(child)
906 continue
907 if body and isinstance(body[-1], list):
908 body[-1].append(const)
909 else:
910 body.append([const])
911
912 # if we have less than 3 nodes we just yield them
913 if len(body) < 3:
914 for item in body:
915 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +0200916 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200917 if frame.buffer is None:
918 self.writeline('yield ' + val)
919 else:
920 self.writeline('%s.append(%s)' % (frame.buffer, val))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200921 else:
922 self.newline(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200923 if frame.buffer is None:
924 self.write('yield ')
925 else:
926 self.write('%s.append(' % frame.buffer)
927 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200928 self.visit(item, frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200929 self.write(')' * (1 + (frame.buffer is not None)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200930
931 # otherwise we create a format string as this is faster in that case
932 else:
933 format = []
934 arguments = []
935 for item in body:
936 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +0200937 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200938 else:
939 format.append('%s')
940 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200941 if frame.buffer is None:
942 self.writeline('yield ')
943 else:
944 self.writeline('%s.append(' % frame.buffer)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200945 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200946 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200947 self.indent()
948 for argument in arguments:
949 self.newline(argument)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200950 if have_finalizer:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200951 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200952 self.visit(argument, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200953 if have_finalizer:
Armin Ronacher8edbe492008-04-10 20:43:43 +0200954 self.write(')')
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200955 self.write(',')
956 self.outdent()
957 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200958 if frame.buffer is not None:
959 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200960
Armin Ronacher7fb38972008-04-11 13:54:28 +0200961 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200962 self.outdent()
963
Armin Ronacher8efc5222008-04-08 14:47:40 +0200964 def visit_Assign(self, node, frame):
965 self.newline(node)
966 # toplevel assignments however go into the local namespace and
967 # the current template's context. We create a copy of the frame
968 # here and add a set so that the Name visitor can add the assigned
969 # names here.
970 if frame.toplevel:
971 assignment_frame = frame.copy()
972 assignment_frame.assigned_names = set()
973 else:
974 assignment_frame = frame
975 self.visit(node.target, assignment_frame)
976 self.write(' = ')
977 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200978
979 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200980 if frame.toplevel:
981 for name in assignment_frame.assigned_names:
982 self.writeline('context[%r] = l_%s' % (name, name))
983
Armin Ronachere791c2a2008-04-07 18:39:54 +0200984 def visit_Name(self, node, frame):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200985 if node.ctx == 'store':
986 if frame.toplevel:
987 frame.assigned_names.add(node.name)
988 frame.name_overrides.pop(node.name, None)
989 elif node.ctx == 'load':
990 if node.name in frame.name_overrides:
991 self.write(frame.name_overrides[node.name])
992 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200993 self.write('l_' + node.name)
994
995 def visit_Const(self, node, frame):
996 val = node.value
997 if isinstance(val, float):
998 # XXX: add checks for infinity and nan
999 self.write(str(val))
1000 else:
1001 self.write(repr(val))
1002
Armin Ronacher8efc5222008-04-08 14:47:40 +02001003 def visit_Tuple(self, node, frame):
1004 self.write('(')
1005 idx = -1
1006 for idx, item in enumerate(node.items):
1007 if idx:
1008 self.write(', ')
1009 self.visit(item, frame)
1010 self.write(idx == 0 and ',)' or ')')
1011
Armin Ronacher8edbe492008-04-10 20:43:43 +02001012 def visit_List(self, node, frame):
1013 self.write('[')
1014 for idx, item in enumerate(node.items):
1015 if idx:
1016 self.write(', ')
1017 self.visit(item, frame)
1018 self.write(']')
1019
1020 def visit_Dict(self, node, frame):
1021 self.write('{')
1022 for idx, item in enumerate(node.items):
1023 if idx:
1024 self.write(', ')
1025 self.visit(item.key, frame)
1026 self.write(': ')
1027 self.visit(item.value, frame)
1028 self.write('}')
1029
Armin Ronachere791c2a2008-04-07 18:39:54 +02001030 def binop(operator):
1031 def visitor(self, node, frame):
1032 self.write('(')
1033 self.visit(node.left, frame)
1034 self.write(' %s ' % operator)
1035 self.visit(node.right, frame)
1036 self.write(')')
1037 return visitor
1038
1039 def uaop(operator):
1040 def visitor(self, node, frame):
1041 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001042 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001043 self.write(')')
1044 return visitor
1045
1046 visit_Add = binop('+')
1047 visit_Sub = binop('-')
1048 visit_Mul = binop('*')
1049 visit_Div = binop('/')
1050 visit_FloorDiv = binop('//')
1051 visit_Pow = binop('**')
1052 visit_Mod = binop('%')
1053 visit_And = binop('and')
1054 visit_Or = binop('or')
1055 visit_Pos = uaop('+')
1056 visit_Neg = uaop('-')
1057 visit_Not = uaop('not ')
1058 del binop, uaop
1059
1060 def visit_Compare(self, node, frame):
1061 self.visit(node.expr, frame)
1062 for op in node.ops:
1063 self.visit(op, frame)
1064
1065 def visit_Operand(self, node, frame):
1066 self.write(' %s ' % operators[node.op])
1067 self.visit(node.expr, frame)
1068
1069 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001070 if isinstance(node.arg, nodes.Slice):
1071 self.visit(node.node, frame)
1072 self.write('[')
1073 self.visit(node.arg, frame)
1074 self.write(']')
1075 return
1076 try:
1077 const = node.arg.as_const()
1078 have_const = True
1079 except nodes.Impossible:
1080 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001081 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001082 self.visit(node.node, frame)
1083 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001084 if have_const:
1085 self.write(repr(const))
1086 else:
1087 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001088 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001089
1090 def visit_Slice(self, node, frame):
1091 if node.start is not None:
1092 self.visit(node.start, frame)
1093 self.write(':')
1094 if node.stop is not None:
1095 self.visit(node.stop, frame)
1096 if node.step is not None:
1097 self.write(':')
1098 self.visit(node.step, frame)
1099
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001100 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001101 self.write('f_%s(' % node.name)
Christoph Hack80909862008-04-14 01:35:10 +02001102 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001103 if func is None:
1104 raise TemplateAssertionError('no filter named %r' % node.name,
1105 node.lineno, self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001106 if getattr(func, 'contextfilter', False):
1107 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001108 elif getattr(func, 'environmentfilter', False):
1109 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001110 if isinstance(node.node, nodes.Filter):
1111 self.visit_Filter(node.node, frame, initial)
1112 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001113 self.write(initial)
1114 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001115 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001116 self.signature(node, frame)
1117 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001118
1119 def visit_Test(self, node, frame):
Armin Ronacherf059ec12008-04-11 22:21:00 +02001120 self.write('t_%s(' % node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001121 if node.name not in self.environment.tests:
1122 raise TemplateAssertionError('no test named %r' % node.name,
1123 node.lineno, self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001124 self.visit(node.node, frame)
1125 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001126 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001127
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001128 def visit_CondExpr(self, node, frame):
1129 if not have_condexpr:
1130 self.write('((')
1131 self.visit(node.test, frame)
1132 self.write(') and (')
1133 self.visit(node.expr1, frame)
1134 self.write(',) or (')
1135 self.visit(node.expr2, frame)
1136 self.write(',))[0]')
1137 else:
1138 self.write('(')
1139 self.visit(node.expr1, frame)
1140 self.write(' if ')
1141 self.visit(node.test, frame)
1142 self.write(' else ')
1143 self.visit(node.expr2, frame)
1144 self.write(')')
1145
Armin Ronacher71082072008-04-12 14:19:36 +02001146 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001147 if self.environment.sandboxed:
1148 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001149 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001150 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001151 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001152 self.write(')')
1153
1154 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001155 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001156 self.visit(node.value, frame)