blob: 3d4fcbe604e9fbfab03c394b0a0b63997d6fcbbd [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 Ronacher32a910f2008-04-26 23:21:03 +020020from jinja2.runtime import concat
Armin Ronacher5236d8c2008-04-17 11:23:16 +020021from jinja2.utils import Markup
Armin Ronachere791c2a2008-04-07 18:39:54 +020022
23
24operators = {
25 'eq': '==',
26 'ne': '!=',
27 'gt': '>',
28 'gteq': '>=',
29 'lt': '<',
30 'lteq': '<=',
31 'in': 'in',
32 'notin': 'not in'
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 Ronacher32a910f2008-04-26 23:21:03 +020056 xrange, 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 Ronacherc9705c22008-04-27 21:28:03 +020073def find_undeclared(nodes, names):
74 """Check if the names passed are accessed undeclared. The return value
75 is a set of all the undeclared names from the sequence of names found.
76 """
77 visitor = UndeclaredNameVisitor(names)
78 try:
79 for node in nodes:
80 visitor.visit(node)
81 except VisitorExit:
82 pass
83 return visitor.undeclared
84
85
Armin Ronachere791c2a2008-04-07 18:39:54 +020086class Identifiers(object):
87 """Tracks the status of identifiers in frames."""
88
89 def __init__(self):
90 # variables that are known to be declared (probably from outer
91 # frames or because they are special for the frame)
92 self.declared = set()
93
Armin Ronacher10f3ba22008-04-18 11:30:37 +020094 # undeclared variables from outer scopes
95 self.outer_undeclared = set()
96
Armin Ronachere791c2a2008-04-07 18:39:54 +020097 # names that are accessed without being explicitly declared by
98 # this one or any of the outer scopes. Names can appear both in
99 # declared and undeclared.
100 self.undeclared = set()
101
102 # names that are declared locally
103 self.declared_locally = set()
104
105 # names that are declared by parameters
106 self.declared_parameter = set()
107
108 def add_special(self, name):
109 """Register a special name like `loop`."""
110 self.undeclared.discard(name)
111 self.declared.add(name)
112
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200113 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200114 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200115 if name in self.declared_locally or name in self.declared_parameter:
116 return True
117 if local_only:
118 return False
119 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200120
121 def find_shadowed(self):
122 """Find all the shadowed names."""
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200123 return (self.declared | self.outer_undeclared) & \
124 (self.declared_locally | self.declared_parameter)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200125
126
127class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200128 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200129
130 def __init__(self, parent=None):
131 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200132
Armin Ronacher75cfb862008-04-11 13:47:22 +0200133 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200134 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200135
Armin Ronacher75cfb862008-04-11 13:47:22 +0200136 # the root frame is basically just the outermost frame, so no if
137 # conditions. This information is used to optimize inheritance
138 # situations.
139 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200140
141 # inside some tags we are using a buffer rather than yield statements.
142 # this for example affects {% filter %} or {% macro %}. If a frame
143 # is buffered this variable points to the name of the list used as
144 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200145 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200146
Armin Ronacherfed44b52008-04-13 19:42:53 +0200147 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200148 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200149
150 # the parent of this frame
151 self.parent = parent
152
Armin Ronachere791c2a2008-04-07 18:39:54 +0200153 if parent is not None:
154 self.identifiers.declared.update(
155 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200156 parent.identifiers.declared_locally |
157 parent.identifiers.declared_parameter
158 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200159 self.identifiers.outer_undeclared.update(
160 parent.identifiers.undeclared -
161 self.identifiers.declared
162 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200163 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200164
Armin Ronacher8efc5222008-04-08 14:47:40 +0200165 def copy(self):
166 """Create a copy of the current one."""
167 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200168 rv.identifiers = copy(self.identifiers)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200169 return rv
170
Armin Ronacherc9705c22008-04-27 21:28:03 +0200171 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200172 """Walk the node and check for identifiers. If the scope is hard (eg:
173 enforce on a python level) overrides from outer scopes are tracked
174 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200175 """
176 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200177 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200178 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200179
180 def inner(self):
181 """Return an inner frame."""
182 return Frame(self)
183
Armin Ronacher75cfb862008-04-11 13:47:22 +0200184 def soft(self):
185 """Return a soft frame. A soft frame may not be modified as
186 standalone thing as it shares the resources with the frame it
187 was created of, but it's not a rootlevel frame any longer.
188 """
189 rv = copy(self)
190 rv.rootlevel = False
191 return rv
192
Armin Ronachere791c2a2008-04-07 18:39:54 +0200193
Armin Ronacherc9705c22008-04-27 21:28:03 +0200194class VisitorExit(RuntimeError):
195 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
196
197
198class DependencyFinderVisitor(NodeVisitor):
199 """A visitor that collects filter and test calls."""
200
201 def __init__(self):
202 self.filters = set()
203 self.tests = set()
204
205 def visit_Filter(self, node):
206 self.generic_visit(node)
207 self.filters.add(node.name)
208
209 def visit_Test(self, node):
210 self.generic_visit(node)
211 self.tests.add(node.name)
212
213 def visit_Block(self, node):
214 """Stop visiting at blocks."""
215
216
217class UndeclaredNameVisitor(NodeVisitor):
218 """A visitor that checks if a name is accessed without being
219 declared. This is different from the frame visitor as it will
220 not stop at closure frames.
221 """
222
223 def __init__(self, names):
224 self.names = set(names)
225 self.undeclared = set()
226
227 def visit_Name(self, node):
228 if node.ctx == 'load' and node.name in self.names:
229 self.undeclared.add(node.name)
230 if self.undeclared == self.names:
231 raise VisitorExit()
232 else:
233 self.names.discard(node.name)
234
235 def visit_Block(self, node):
236 """Stop visiting a blocks."""
237
238
Armin Ronachere791c2a2008-04-07 18:39:54 +0200239class FrameIdentifierVisitor(NodeVisitor):
240 """A visitor for `Frame.inspect`."""
241
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200242 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200243 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200244 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200245
Armin Ronacherc9705c22008-04-27 21:28:03 +0200246 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200247 """All assignments to names go through this function."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200248 if node.ctx in ('store', 'param'):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200249 self.identifiers.declared_locally.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200250 elif node.ctx == 'load' and not \
251 self.identifiers.is_declared(node.name, self.hard_scope):
252 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200253
Armin Ronacherc9705c22008-04-27 21:28:03 +0200254 def visit_Macro(self, node):
255 self.generic_visit(node)
256 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200257
Armin Ronacherc9705c22008-04-27 21:28:03 +0200258 def visit_Import(self, node):
259 self.generic_visit(node)
260 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200261
Armin Ronacherc9705c22008-04-27 21:28:03 +0200262 def visit_FromImport(self, node):
263 self.generic_visit(node)
264 for name in node.names:
265 if isinstance(name, tuple):
266 self.identifiers.declared_locally.add(name[1])
267 else:
268 self.identifiers.declared_locally.add(name)
269
270 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200271 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200272 self.visit(node.node)
273 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200274
Armin Ronacherc9705c22008-04-27 21:28:03 +0200275 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200276 """Visiting stops at for blocks. However the block sequence
277 is visited as part of the outer scope.
278 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200279 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200280
Armin Ronacherc9705c22008-04-27 21:28:03 +0200281 def visit_CallBlock(self, node):
282 for child in node.iter_child_nodes(exclude=('body',)):
283 self.visit(child)
284
285 def visit_FilterBlock(self, node):
286 self.visit(node.filter)
287
288 def visit_Block(self, node):
289 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200290
291
Armin Ronacher75cfb862008-04-11 13:47:22 +0200292class CompilerExit(Exception):
293 """Raised if the compiler encountered a situation where it just
294 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200295 raises such an exception is not further processed.
296 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200297
298
Armin Ronachere791c2a2008-04-07 18:39:54 +0200299class CodeGenerator(NodeVisitor):
300
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200301 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200302 if stream is None:
303 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200304 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200305 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200306 self.filename = filename
307 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200308
309 # a registry for all blocks. Because blocks are moved out
310 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200311 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200312
313 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200314 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200315
316 # some templates have a rootlevel extends. In this case we
317 # can safely assume that we're a child template and do some
318 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200319 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200320
Armin Ronacherba3757b2008-04-16 19:43:16 +0200321 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200322 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200323
324 # the debug information
325 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200326 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200327
Armin Ronacherfed44b52008-04-13 19:42:53 +0200328 # the number of new lines before the next write()
329 self._new_lines = 0
330
331 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200332 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200333
334 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200335 self._first_write = True
336
Armin Ronacherfed44b52008-04-13 19:42:53 +0200337 # used by the `temporary_identifier` method to get new
338 # unique, temporary identifier
339 self._last_identifier = 0
340
341 # the current indentation
342 self._indentation = 0
343
Armin Ronachere791c2a2008-04-07 18:39:54 +0200344 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200345 """Get a new unique identifier."""
346 self._last_identifier += 1
347 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200348
349 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200350 """Indent by one."""
351 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200352
Armin Ronacher8efc5222008-04-08 14:47:40 +0200353 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200354 """Outdent by step."""
355 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200356
Armin Ronacherc9705c22008-04-27 21:28:03 +0200357 def blockvisit(self, nodes, frame, force_generator=True):
358 """Visit a list of nodes as block in a frame. If the current frame
359 is no buffer a dummy ``if 0: yield None`` is written automatically
360 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200361 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200362 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200363 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200364 try:
365 for node in nodes:
366 self.visit(node, frame)
367 except CompilerExit:
368 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200369
370 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200371 """Write a string into the output stream."""
372 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200373 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200374 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200375 self.code_lineno += self._new_lines
376 if self._write_debug_info is not None:
377 self.debug_info.append((self._write_debug_info,
378 self.code_lineno))
379 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200380 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200381 self.stream.write(' ' * self._indentation)
382 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200383 self.stream.write(x)
384
385 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200386 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200387 self.newline(node, extra)
388 self.write(x)
389
390 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200391 """Add one or more newlines before the next write."""
392 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200393 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200394 self._write_debug_info = node.lineno
395 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200396
Armin Ronacher71082072008-04-12 14:19:36 +0200397 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200398 """Writes a function call to the stream for the current node.
399 Per default it will write a leading comma but this can be
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200400 disabled by setting have_comma to False. The extra keyword
401 arguments may not include python keywords otherwise a syntax
402 error could occour. The extra keyword arguments should be given
403 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200404 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200405 have_comma = have_comma and [True] or []
406 def touch_comma():
407 if have_comma:
408 self.write(', ')
409 else:
410 have_comma.append(True)
411
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200412 # if any of the given keyword arguments is a python keyword
413 # we have to make sure that no invalid call is created.
414 kwarg_workaround = False
415 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
416 if iskeyword(kwarg):
417 kwarg_workaround = True
418 break
419
Armin Ronacher8efc5222008-04-08 14:47:40 +0200420 for arg in node.args:
421 touch_comma()
422 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200423
424 if not kwarg_workaround:
425 for kwarg in node.kwargs:
426 touch_comma()
427 self.visit(kwarg, frame)
428 if extra_kwargs is not None:
429 for key, value in extra_kwargs.iteritems():
430 touch_comma()
431 self.write('%s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200432 if node.dyn_args:
433 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200434 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200435 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200436
437 if kwarg_workaround:
438 touch_comma()
439 if node.dyn_kwargs is not None:
440 self.write('**dict({')
441 else:
442 self.write('**{')
443 for kwarg in node.kwargs:
444 self.write('%r: ' % kwarg.key)
445 self.visit(kwarg.value, frame)
446 self.write(', ')
447 if extra_kwargs is not None:
448 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200449 self.write('%r: %s, ' % (key, value))
450 if node.dyn_kwargs is not None:
451 self.write('}, **')
452 self.visit(node.dyn_kwargs, frame)
453 self.write(')')
454 else:
455 self.write('}')
456
457 elif node.dyn_kwargs is not None:
Armin Ronacher8efc5222008-04-08 14:47:40 +0200458 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200459 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200460 self.visit(node.dyn_kwargs, frame)
461
Armin Ronacherc9705c22008-04-27 21:28:03 +0200462 def pull_locals(self, frame):
463 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200464 for name in frame.identifiers.undeclared:
465 self.writeline('l_%s = context[%r]' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200466
467 def pull_dependencies(self, nodes):
468 """Pull all the dependencies."""
469 visitor = DependencyFinderVisitor()
470 for node in nodes:
471 visitor.visit(node)
472 for name in visitor.filters:
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200473 self.writeline('f_%s = environment.filters[%r]' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200474 for name in visitor.tests:
Armin Ronacherf059ec12008-04-11 22:21:00 +0200475 self.writeline('t_%s = environment.tests[%r]' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200476
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200477 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200478 """This function returns all the shadowed variables in a dict
479 in the form name: alias and will write the required assignments
480 into the current scope. No indentation takes place.
481 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200482 # make sure we "backup" overridden, local identifiers
483 # TODO: we should probably optimize this and check if the
484 # identifier is in use afterwards.
485 aliases = {}
486 for name in frame.identifiers.find_shadowed():
487 aliases[name] = ident = self.temporary_identifier()
488 self.writeline('%s = l_%s' % (ident, name))
489 return aliases
490
Armin Ronacherc9705c22008-04-27 21:28:03 +0200491 def function_scoping(self, node, frame, children=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200492 """In Jinja a few statements require the help of anonymous
493 functions. Those are currently macros and call blocks and in
494 the future also recursive loops. As there is currently
495 technical limitation that doesn't allow reading and writing a
496 variable in a scope where the initial value is coming from an
497 outer scope, this function tries to fall back with a common
498 error message. Additionally the frame passed is modified so
499 that the argumetns are collected and callers are looked up.
500
501 This will return the modified frame.
502 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200503 # we have to iterate twice over it, make sure that works
504 if children is None:
505 children = node.iter_child_nodes()
506 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200507 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200508 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200509
510 # variables that are undeclared (accessed before declaration) and
511 # declared locally *and* part of an outside scope raise a template
512 # assertion error. Reason: we can't generate reasonable code from
513 # it without aliasing all the variables. XXX: alias them ^^
514 overriden_closure_vars = (
515 func_frame.identifiers.undeclared &
516 func_frame.identifiers.declared &
517 (func_frame.identifiers.declared_locally |
518 func_frame.identifiers.declared_parameter)
519 )
520 if overriden_closure_vars:
521 vars = ', '.join(sorted(overriden_closure_vars))
522 raise TemplateAssertionError('It\'s not possible to set and '
523 'access variables derived from '
524 'an outer scope! (affects: %s' %
Armin Ronacher68f77672008-04-17 11:50:39 +0200525 vars, node.lineno, self.name)
Armin Ronacher71082072008-04-12 14:19:36 +0200526
527 # remove variables from a closure from the frame's undeclared
528 # identifiers.
529 func_frame.identifiers.undeclared -= (
530 func_frame.identifiers.undeclared &
531 func_frame.identifiers.declared
532 )
533
Armin Ronacher963f97d2008-04-25 11:44:59 +0200534 func_frame.accesses_kwargs = False
535 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200536 func_frame.accesses_caller = False
537 func_frame.arguments = args = ['l_' + x.name for x in node.args]
538
Armin Ronacherc9705c22008-04-27 21:28:03 +0200539 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
540
541 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200542 func_frame.accesses_caller = True
543 func_frame.identifiers.add_special('caller')
544 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200545 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200546 func_frame.accesses_kwargs = True
547 func_frame.identifiers.add_special('kwargs')
548 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200549 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200550 func_frame.accesses_varargs = True
551 func_frame.identifiers.add_special('varargs')
552 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200553 return func_frame
554
Armin Ronachere791c2a2008-04-07 18:39:54 +0200555 # -- Visitors
556
557 def visit_Template(self, node, frame=None):
558 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200559 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200560 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200561 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200562 self.writeline('name = %r' % self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200563
Armin Ronacher75cfb862008-04-11 13:47:22 +0200564 # do we have an extends tag at all? If not, we can save some
565 # overhead by just not processing any inheritance code.
566 have_extends = node.find(nodes.Extends) is not None
567
Armin Ronacher8edbe492008-04-10 20:43:43 +0200568 # find all blocks
569 for block in node.find_all(nodes.Block):
570 if block.name in self.blocks:
571 raise TemplateAssertionError('block %r defined twice' %
572 block.name, block.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200573 self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200574 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200575
Armin Ronacher8efc5222008-04-08 14:47:40 +0200576 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200577 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200578
579 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200580 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200581 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200582 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200583 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200584 if have_extends:
585 self.writeline('parent_template = None')
586 self.pull_locals(frame)
587 self.pull_dependencies(node.body)
588 if 'self' in find_undeclared(node.body, ('self',)):
589 frame.identifiers.add_special('self')
590 self.writeline('l_self = TemplateReference(context)')
591 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200592 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200593
Armin Ronacher8efc5222008-04-08 14:47:40 +0200594 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200595 if have_extends:
596 if not self.has_known_extends:
597 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200598 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200599 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200600 self.writeline('for event in parent_template.'
601 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200602 self.indent()
603 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200604 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200605
606 # at this point we now have the blocks collected and can visit them too.
607 for name, block in self.blocks.iteritems():
608 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200609 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200610 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200611 self.writeline('def block_%s(context, environment=environment):'
612 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200613 self.indent()
614 undeclared = find_undeclared(block.body, ('self', 'super'))
615 if 'self' in undeclared:
616 block_frame.identifiers.add_special('self')
617 self.writeline('l_self = TemplateReference(context)')
618 if 'super' in undeclared:
619 block_frame.identifiers.add_special('super')
620 self.writeline('l_super = context.super(%r, '
621 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200622 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200623 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200624 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200625 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200626
Armin Ronacher75cfb862008-04-11 13:47:22 +0200627 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200628 for x in self.blocks),
629 extra=1)
630
631 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200632 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
633 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200634
Armin Ronachere791c2a2008-04-07 18:39:54 +0200635 def visit_Block(self, node, frame):
636 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200637 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200638 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200639 # if we know that we are a child template, there is no need to
640 # check if we are one
641 if self.has_known_extends:
642 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200643 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200644 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200645 self.indent()
646 level += 1
Armin Ronacherc9705c22008-04-27 21:28:03 +0200647 self.writeline('for event in context.blocks[%r][-1](context):' %
648 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200649 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200650 if frame.buffer is None:
651 self.writeline('yield event')
652 else:
653 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200654 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200655
656 def visit_Extends(self, node, frame):
657 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200658 if not frame.toplevel:
659 raise TemplateAssertionError('cannot use extend from a non '
660 'top-level scope', node.lineno,
Armin Ronacher68f77672008-04-17 11:50:39 +0200661 self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200662
Armin Ronacher7fb38972008-04-11 13:54:28 +0200663 # if the number of extends statements in general is zero so
664 # far, we don't have to add a check if something extended
665 # the template before this one.
666 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200667
Armin Ronacher7fb38972008-04-11 13:54:28 +0200668 # if we have a known extends we just add a template runtime
669 # error into the generated code. We could catch that at compile
670 # time too, but i welcome it not to confuse users by throwing the
671 # same error at different times just "because we can".
672 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200673 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200674 self.indent()
675 self.writeline('raise TemplateRuntimeError(%r)' %
676 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200677
Armin Ronacher7fb38972008-04-11 13:54:28 +0200678 # if we have a known extends already we don't need that code here
679 # as we know that the template execution will end here.
680 if self.has_known_extends:
681 raise CompilerExit()
682 self.outdent()
683
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200684 self.writeline('parent_template = environment.get_template(', node, 1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200685 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200686 self.write(', %r)' % self.name)
687 self.writeline('for name, parent_block in parent_template.'
688 'blocks.iteritems():')
689 self.indent()
690 self.writeline('context.blocks.setdefault(name, []).'
691 'insert(0, parent_block)')
692 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200693
694 # if this extends statement was in the root level we can take
695 # advantage of that information and simplify the generated code
696 # in the top level from this point onwards
697 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200698
Armin Ronacher7fb38972008-04-11 13:54:28 +0200699 # and now we have one more
700 self.extends_so_far += 1
701
Armin Ronacherf059ec12008-04-11 22:21:00 +0200702 def visit_Include(self, node, frame):
703 """Handles includes."""
Armin Ronacherea847c52008-05-02 20:04:32 +0200704 if node.with_context:
705 self.writeline('template = environment.get_template(', node)
706 self.visit(node.template, frame)
707 self.write(', %r)' % self.name)
708 self.writeline('for event in template.root_render_func('
709 'template.new_context(context.parent, True)):')
710 else:
711 self.writeline('for event in environment.get_template(', node)
712 self.visit(node.template, frame)
713 self.write(', %r).module._TemplateModule__body_stream:' %
714 self.name)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200715 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200716 if frame.buffer is None:
717 self.writeline('yield event')
718 else:
719 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200720 self.outdent()
721
Armin Ronacher0611e492008-04-25 23:44:14 +0200722 def visit_Import(self, node, frame):
723 """Visit regular imports."""
724 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200725 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200726 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200727 self.write('environment.get_template(')
728 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200729 self.write(', %r).' % self.name)
730 if node.with_context:
731 self.write('make_module(context.parent, True)')
732 else:
733 self.write('module')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200734 if frame.toplevel and not node.target.startswith('__'):
Armin Ronacher53042292008-04-26 18:30:19 +0200735 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200736
737 def visit_FromImport(self, node, frame):
738 """Visit named imports."""
739 self.newline(node)
740 self.write('included_template = environment.get_template(')
741 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200742 self.write(', %r).' % self.name)
743 if node.with_context:
744 self.write('make_module(context.parent, True)')
745 else:
746 self.write('module')
Armin Ronacher0611e492008-04-25 23:44:14 +0200747 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200748 if isinstance(name, tuple):
749 name, alias = name
750 else:
751 alias = name
Armin Ronacher0611e492008-04-25 23:44:14 +0200752 self.writeline('l_%s = getattr(included_template, '
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200753 '%r, missing)' % (alias, name))
754 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200755 self.indent()
756 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200757 'included_template.name, '
758 'name=included_template.name)' %
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200759 (alias, 'the template %r does not export '
Armin Ronacher0611e492008-04-25 23:44:14 +0200760 'the requested name ' + repr(name)))
761 self.outdent()
762 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200763 self.writeline('context.vars[%r] = l_%s' % (alias, alias))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200764 if not alias.startswith('__'):
765 self.writeline('context.exported_vars.discard(%r)' % alias)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200766
Armin Ronachere791c2a2008-04-07 18:39:54 +0200767 def visit_For(self, node, frame):
768 loop_frame = frame.inner()
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200769 loop_frame.inspect(node.iter_child_nodes(exclude=('iter',)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200770 extended_loop = bool(node.else_) or \
771 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200772 if extended_loop:
773 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200774
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200775 aliases = self.collect_shadowed(loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200776 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200777 if node.else_:
778 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200779
780 self.newline(node)
781 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200782 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200783 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200784
785 # the expression pointing to the parent loop. We make the
786 # undefined a bit more debug friendly at the same time.
787 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200788 or "environment.undefined(%r, name='loop')" % "'loop' " \
789 'is undefined. "the filter section of a loop as well ' \
790 'as the else block doesn\'t have access to the ' \
791 "special 'loop' variable of the current loop. " \
792 "Because there is no parent loop it's undefined."
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200793
794 # if we have an extened loop and a node test, we filter in the
795 # "outer frame".
796 if extended_loop and node.test is not None:
797 self.write('(')
798 self.visit(node.target, loop_frame)
799 self.write(' for ')
800 self.visit(node.target, loop_frame)
801 self.write(' in ')
802 self.visit(node.iter, loop_frame)
803 self.write(' if (')
804 test_frame = loop_frame.copy()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200805 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200806 self.visit(node.test, test_frame)
807 self.write('))')
808
809 else:
810 self.visit(node.iter, loop_frame)
811
Armin Ronachere791c2a2008-04-07 18:39:54 +0200812 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200813
814 # tests in not extended loops become a continue
815 if not extended_loop and node.test is not None:
816 self.indent()
817 self.writeline('if ')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200818 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200819 self.write(':')
820 self.indent()
821 self.writeline('continue')
822 self.outdent(2)
823
Armin Ronacherc9705c22008-04-27 21:28:03 +0200824 self.indent()
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200825 self.blockvisit(node.body, loop_frame, force_generator=True)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200826 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200827
828 if node.else_:
829 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200830 self.indent()
831 self.writeline('l_loop = ' + parent_loop)
Armin Ronacher625215e2008-04-13 16:31:08 +0200832 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200833 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200834
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200835 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200836 for name, alias in aliases.iteritems():
Armin Ronacher8efc5222008-04-08 14:47:40 +0200837 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200838
839 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200840 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200841 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200842 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200843 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200844 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200845 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200846 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200847 if node.else_:
848 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200849 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200850 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200851 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200852
Armin Ronacher8efc5222008-04-08 14:47:40 +0200853 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200854 macro_frame = self.function_scoping(node, frame)
855 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200856 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200857 macro_frame.buffer = buf = self.temporary_identifier()
858 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200859 self.pull_locals(macro_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200860 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200861 self.blockvisit(node.body, macro_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200862 if self.environment.autoescape:
863 self.writeline('return Markup(concat(%s))' % buf)
864 else:
865 self.writeline("return concat(%s)" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200866 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200867 self.newline()
868 if frame.toplevel:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200869 if not node.name.startswith('__'):
870 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +0200871 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200872 arg_tuple = ', '.join(repr(x.name) for x in node.args)
873 if len(node.args) == 1:
874 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200875 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
876 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200877 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200878 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200879 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200880 self.write('), %s, %s, %s)' % (
881 macro_frame.accesses_kwargs and '1' or '0',
882 macro_frame.accesses_varargs and '1' or '0',
Armin Ronacher00d5d212008-04-13 01:10:18 +0200883 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200884 ))
885
886 def visit_CallBlock(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200887 call_frame = self.function_scoping(node, frame, node.iter_child_nodes
888 (exclude=('call',)))
Armin Ronacher71082072008-04-12 14:19:36 +0200889 args = call_frame.arguments
890 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200891 call_frame.buffer = buf = self.temporary_identifier()
892 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200893 self.pull_locals(call_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200894 self.writeline('%s = []' % buf)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200895 self.blockvisit(node.body, call_frame)
Armin Ronacherd1342312008-04-28 12:20:12 +0200896 if self.environment.autoescape:
897 self.writeline("return Markup(concat(%s))" % buf)
898 else:
899 self.writeline('return concat(%s)' % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200900 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200901 arg_tuple = ', '.join(repr(x.name) for x in node.args)
902 if len(node.args) == 1:
903 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200904 self.writeline('caller = Macro(environment, call, None, (%s), (' %
905 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200906 for arg in node.defaults:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200907 self.visit(arg, call_frame)
Armin Ronacher71082072008-04-12 14:19:36 +0200908 self.write(', ')
Armin Ronacher963f97d2008-04-25 11:44:59 +0200909 self.write('), %s, %s, 0)' % (
910 call_frame.accesses_kwargs and '1' or '0',
911 call_frame.accesses_varargs and '1' or '0'
912 ))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200913 if frame.buffer is None:
914 self.writeline('yield ', node)
915 else:
916 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200917 self.visit_Call(node.call, call_frame,
918 extra_kwargs={'caller': 'caller'})
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200919 if frame.buffer is not None:
920 self.write(')')
921
922 def visit_FilterBlock(self, node, frame):
923 filter_frame = frame.inner()
924 filter_frame.inspect(node.iter_child_nodes())
925
926 aliases = self.collect_shadowed(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200927 self.pull_locals(filter_frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200928 filter_frame.buffer = buf = self.temporary_identifier()
929
930 self.writeline('%s = []' % buf, node)
931 for child in node.body:
932 self.visit(child, filter_frame)
933
934 if frame.buffer is None:
935 self.writeline('yield ', node)
936 else:
937 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200938 self.visit_Filter(node.filter, filter_frame, 'concat(%s)' % buf)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200939 if frame.buffer is not None:
940 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200941
Armin Ronachere791c2a2008-04-07 18:39:54 +0200942 def visit_ExprStmt(self, node, frame):
943 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +0200944 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200945
946 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200947 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +0200948 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200949 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200950
Armin Ronacher75cfb862008-04-11 13:47:22 +0200951 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200952
Armin Ronacher7fb38972008-04-11 13:54:28 +0200953 # if we are in the toplevel scope and there was already an extends
954 # statement we have to add a check that disables our yield(s) here
955 # so that they don't appear in the output.
956 outdent_later = False
957 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200958 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200959 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200960 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +0200961
Armin Ronachere791c2a2008-04-07 18:39:54 +0200962 # try to evaluate as many chunks as possible into a static
963 # string at compile time.
964 body = []
965 for child in node.nodes:
966 try:
967 const = unicode(child.as_const())
968 except:
969 body.append(child)
970 continue
971 if body and isinstance(body[-1], list):
972 body[-1].append(const)
973 else:
974 body.append([const])
975
Armin Ronacher32a910f2008-04-26 23:21:03 +0200976 # if we have less than 3 nodes or less than 6 and a buffer we
977 # yield or extend
978 if len(body) < 3 or (frame.buffer is not None and len(body) < 6):
979 if frame.buffer is not None:
980 self.writeline('%s.extend((' % frame.buffer)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200981 for item in body:
982 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +0200983 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200984 if frame.buffer is None:
985 self.writeline('yield ' + val)
986 else:
Armin Ronacher32a910f2008-04-26 23:21:03 +0200987 self.write(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200988 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200989 if frame.buffer is None:
Armin Ronacher32a910f2008-04-26 23:21:03 +0200990 self.writeline('yield ')
Armin Ronacherd1342312008-04-28 12:20:12 +0200991 close = 1
992 if self.environment.autoescape:
993 self.write('escape(')
994 else:
995 self.write('unicode(')
996 if self.environment.finalize is not None:
997 self.write('environment.finalize(')
998 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200999 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001000 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001001 if frame.buffer is not None:
1002 self.write(', ')
1003 if frame.buffer is not None:
1004 self.write('))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001005
1006 # otherwise we create a format string as this is faster in that case
1007 else:
1008 format = []
1009 arguments = []
1010 for item in body:
1011 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001012 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001013 else:
1014 format.append('%s')
1015 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001016 if frame.buffer is None:
1017 self.writeline('yield ')
1018 else:
1019 self.writeline('%s.append(' % frame.buffer)
Armin Ronacherde6bf712008-04-26 01:44:14 +02001020 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001021 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001022 self.indent()
1023 for argument in arguments:
1024 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001025 close = 0
1026 if self.environment.autoescape:
1027 self.write('escape(')
1028 close += 1
1029 if self.environment.finalize is not None:
1030 self.write('environment.finalize(')
1031 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001032 self.visit(argument, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001033 self.write(')' * close + ',')
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001034 self.outdent()
1035 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001036 if frame.buffer is not None:
1037 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001038
Armin Ronacher7fb38972008-04-11 13:54:28 +02001039 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001040 self.outdent()
1041
Armin Ronacher8efc5222008-04-08 14:47:40 +02001042 def visit_Assign(self, node, frame):
1043 self.newline(node)
1044 # toplevel assignments however go into the local namespace and
1045 # the current template's context. We create a copy of the frame
1046 # here and add a set so that the Name visitor can add the assigned
1047 # names here.
1048 if frame.toplevel:
1049 assignment_frame = frame.copy()
1050 assignment_frame.assigned_names = set()
1051 else:
1052 assignment_frame = frame
1053 self.visit(node.target, assignment_frame)
1054 self.write(' = ')
1055 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001056
1057 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001058 if frame.toplevel:
1059 for name in assignment_frame.assigned_names:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001060 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +02001061 if not name.startswith('__'):
1062 self.writeline('context.exported_vars.add(%r)' % name)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001063
Armin Ronachere791c2a2008-04-07 18:39:54 +02001064 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001065 if node.ctx == 'store' and frame.toplevel:
1066 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001067 self.write('l_' + node.name)
1068
Armin Ronacherd84ec462008-04-29 13:43:16 +02001069 def visit_MarkSafe(self, node, frame):
1070 self.write('Markup(')
1071 self.visit(node.expr, frame)
1072 self.write(')')
1073
Armin Ronachere791c2a2008-04-07 18:39:54 +02001074 def visit_Const(self, node, frame):
1075 val = node.value
1076 if isinstance(val, float):
1077 # XXX: add checks for infinity and nan
1078 self.write(str(val))
1079 else:
1080 self.write(repr(val))
1081
Armin Ronacher8efc5222008-04-08 14:47:40 +02001082 def visit_Tuple(self, node, frame):
1083 self.write('(')
1084 idx = -1
1085 for idx, item in enumerate(node.items):
1086 if idx:
1087 self.write(', ')
1088 self.visit(item, frame)
1089 self.write(idx == 0 and ',)' or ')')
1090
Armin Ronacher8edbe492008-04-10 20:43:43 +02001091 def visit_List(self, node, frame):
1092 self.write('[')
1093 for idx, item in enumerate(node.items):
1094 if idx:
1095 self.write(', ')
1096 self.visit(item, frame)
1097 self.write(']')
1098
1099 def visit_Dict(self, node, frame):
1100 self.write('{')
1101 for idx, item in enumerate(node.items):
1102 if idx:
1103 self.write(', ')
1104 self.visit(item.key, frame)
1105 self.write(': ')
1106 self.visit(item.value, frame)
1107 self.write('}')
1108
Armin Ronachere791c2a2008-04-07 18:39:54 +02001109 def binop(operator):
1110 def visitor(self, node, frame):
1111 self.write('(')
1112 self.visit(node.left, frame)
1113 self.write(' %s ' % operator)
1114 self.visit(node.right, frame)
1115 self.write(')')
1116 return visitor
1117
1118 def uaop(operator):
1119 def visitor(self, node, frame):
1120 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001121 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001122 self.write(')')
1123 return visitor
1124
1125 visit_Add = binop('+')
1126 visit_Sub = binop('-')
1127 visit_Mul = binop('*')
1128 visit_Div = binop('/')
1129 visit_FloorDiv = binop('//')
1130 visit_Pow = binop('**')
1131 visit_Mod = binop('%')
1132 visit_And = binop('and')
1133 visit_Or = binop('or')
1134 visit_Pos = uaop('+')
1135 visit_Neg = uaop('-')
1136 visit_Not = uaop('not ')
1137 del binop, uaop
1138
Armin Ronacherd1342312008-04-28 12:20:12 +02001139 def visit_Concat(self, node, frame):
Armin Ronacher709f6e52008-04-28 18:18:16 +02001140 self.write('%s((' % self.environment.autoescape and
1141 'markup_join' or 'unicode_join')
Armin Ronacherd1342312008-04-28 12:20:12 +02001142 for arg in node.nodes:
1143 self.visit(arg, frame)
1144 self.write(', ')
1145 self.write('))')
1146
Armin Ronachere791c2a2008-04-07 18:39:54 +02001147 def visit_Compare(self, node, frame):
1148 self.visit(node.expr, frame)
1149 for op in node.ops:
1150 self.visit(op, frame)
1151
1152 def visit_Operand(self, node, frame):
1153 self.write(' %s ' % operators[node.op])
1154 self.visit(node.expr, frame)
1155
1156 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001157 if isinstance(node.arg, nodes.Slice):
1158 self.visit(node.node, frame)
1159 self.write('[')
1160 self.visit(node.arg, frame)
1161 self.write(']')
1162 return
1163 try:
1164 const = node.arg.as_const()
1165 have_const = True
1166 except nodes.Impossible:
1167 have_const = False
Armin Ronacherc63243e2008-04-14 22:53:58 +02001168 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001169 self.visit(node.node, frame)
1170 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001171 if have_const:
1172 self.write(repr(const))
1173 else:
1174 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +02001175 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001176
1177 def visit_Slice(self, node, frame):
1178 if node.start is not None:
1179 self.visit(node.start, frame)
1180 self.write(':')
1181 if node.stop is not None:
1182 self.visit(node.stop, frame)
1183 if node.step is not None:
1184 self.write(':')
1185 self.visit(node.step, frame)
1186
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001187 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001188 self.write('f_%s(' % node.name)
Christoph Hack80909862008-04-14 01:35:10 +02001189 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001190 if func is None:
1191 raise TemplateAssertionError('no filter named %r' % node.name,
1192 node.lineno, self.filename)
Christoph Hack80909862008-04-14 01:35:10 +02001193 if getattr(func, 'contextfilter', False):
1194 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001195 elif getattr(func, 'environmentfilter', False):
1196 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001197 if isinstance(node.node, nodes.Filter):
1198 self.visit_Filter(node.node, frame, initial)
1199 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001200 self.write(initial)
1201 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001202 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001203 self.signature(node, frame)
1204 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001205
1206 def visit_Test(self, node, frame):
Armin Ronacherf059ec12008-04-11 22:21:00 +02001207 self.write('t_%s(' % node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001208 if node.name not in self.environment.tests:
1209 raise TemplateAssertionError('no test named %r' % node.name,
1210 node.lineno, self.filename)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001211 self.visit(node.node, frame)
1212 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001213 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001214
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001215 def visit_CondExpr(self, node, frame):
1216 if not have_condexpr:
1217 self.write('((')
1218 self.visit(node.test, frame)
1219 self.write(') and (')
1220 self.visit(node.expr1, frame)
1221 self.write(',) or (')
1222 self.visit(node.expr2, frame)
1223 self.write(',))[0]')
1224 else:
1225 self.write('(')
1226 self.visit(node.expr1, frame)
1227 self.write(' if ')
1228 self.visit(node.test, frame)
1229 self.write(' else ')
1230 self.visit(node.expr2, frame)
1231 self.write(')')
1232
Armin Ronacher71082072008-04-12 14:19:36 +02001233 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001234 if self.environment.sandboxed:
1235 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001236 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001237 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001238 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001239 self.write(')')
1240
1241 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001242 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001243 self.visit(node.value, frame)