blob: a52b1c7bc3420ef6a9add9a6bd1cb4d8cf1af22a [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
Armin Ronacher55494e42010-01-22 09:41:48 +01008 :copyright: (c) 2010 by the Jinja Team.
Armin Ronacher7af781c2010-02-09 16:05:08 +01009 :license: BSD, see LICENSE for more details.
Armin Ronachere791c2a2008-04-07 18:39:54 +020010"""
Armin Ronachere791c2a2008-04-07 18:39:54 +020011from cStringIO import StringIO
Armin Ronacherd1ff8582008-05-11 00:30:43 +020012from itertools import chain
Armin Ronacher74230e62009-10-25 12:46:31 +010013from copy import deepcopy
Armin Ronachere791c2a2008-04-07 18:39:54 +020014from jinja2 import nodes
15from jinja2.visitor import NodeVisitor, NodeTransformer
16from jinja2.exceptions import TemplateAssertionError
Armin Ronacherbd357722009-08-05 20:25:06 +020017from jinja2.utils import Markup, concat, escape, is_python_keyword, next
Armin Ronachere791c2a2008-04-07 18:39:54 +020018
19
20operators = {
21 'eq': '==',
22 'ne': '!=',
23 'gt': '>',
24 'gteq': '>=',
25 'lt': '<',
26 'lteq': '<=',
27 'in': 'in',
28 'notin': 'not in'
29}
30
Armin Ronacher3d8b7842008-04-13 13:16:50 +020031try:
32 exec '(0 if 0 else 0)'
33except SyntaxError:
34 have_condexpr = False
35else:
36 have_condexpr = True
37
38
Armin Ronacher0d242be2010-02-10 01:35:13 +010039# what method to iterate over items do we want to use for dict iteration
40# in generated code? on 2.x let's go with iteritems, on 3.x with items
41if hasattr(dict, 'iteritems'):
42 dict_item_iter = 'iteritems'
43else:
44 dict_item_iter = 'items'
45
46
Armin Ronacher821a4232010-02-17 07:59:38 +010047# does if 0: dummy(x) get us x into the scope?
48def unoptimize_before_dead_code():
49 x = 42
50 def f():
51 if 0: dummy(x)
52 return f
53unoptimize_before_dead_code = bool(unoptimize_before_dead_code().func_closure)
54
55
Armin Ronacher8e8d0712008-04-16 23:10:49 +020056def generate(node, environment, name, filename, stream=None):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020057 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020058 if not isinstance(node, nodes.Template):
59 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher8e8d0712008-04-16 23:10:49 +020060 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020061 generator.visit(node)
62 if stream is None:
63 return generator.stream.getvalue()
64
65
Armin Ronacher4dfc9752008-04-09 15:03:29 +020066def has_safe_repr(value):
67 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020068 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020069 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020070 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher32a910f2008-04-26 23:21:03 +020071 xrange, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020072 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020073 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020074 for item in value:
75 if not has_safe_repr(item):
76 return False
77 return True
78 elif isinstance(value, dict):
79 for key, value in value.iteritems():
80 if not has_safe_repr(key):
81 return False
82 if not has_safe_repr(value):
83 return False
84 return True
85 return False
86
87
Armin Ronacherc9705c22008-04-27 21:28:03 +020088def find_undeclared(nodes, names):
89 """Check if the names passed are accessed undeclared. The return value
90 is a set of all the undeclared names from the sequence of names found.
91 """
92 visitor = UndeclaredNameVisitor(names)
93 try:
94 for node in nodes:
95 visitor.visit(node)
96 except VisitorExit:
97 pass
98 return visitor.undeclared
99
100
Armin Ronachere791c2a2008-04-07 18:39:54 +0200101class Identifiers(object):
102 """Tracks the status of identifiers in frames."""
103
104 def __init__(self):
105 # variables that are known to be declared (probably from outer
106 # frames or because they are special for the frame)
107 self.declared = set()
108
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200109 # undeclared variables from outer scopes
110 self.outer_undeclared = set()
111
Armin Ronachere791c2a2008-04-07 18:39:54 +0200112 # names that are accessed without being explicitly declared by
113 # this one or any of the outer scopes. Names can appear both in
114 # declared and undeclared.
115 self.undeclared = set()
116
117 # names that are declared locally
118 self.declared_locally = set()
119
120 # names that are declared by parameters
121 self.declared_parameter = set()
122
123 def add_special(self, name):
124 """Register a special name like `loop`."""
125 self.undeclared.discard(name)
126 self.declared.add(name)
127
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200128 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200129 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200130 if name in self.declared_locally or name in self.declared_parameter:
131 return True
132 if local_only:
133 return False
134 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200135
Armin Ronacher74230e62009-10-25 12:46:31 +0100136 def copy(self):
137 return deepcopy(self)
138
Armin Ronachere791c2a2008-04-07 18:39:54 +0200139
140class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200141 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200142
143 def __init__(self, parent=None):
144 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200145
Armin Ronacher75cfb862008-04-11 13:47:22 +0200146 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200147 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200148
Armin Ronacher75cfb862008-04-11 13:47:22 +0200149 # the root frame is basically just the outermost frame, so no if
150 # conditions. This information is used to optimize inheritance
151 # situations.
152 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200153
Armin Ronacher79668952008-09-23 22:52:46 +0200154 # in some dynamic inheritance situations the compiler needs to add
155 # write tests around output statements.
156 self.require_output_check = parent and parent.require_output_check
Armin Ronacherf40c8842008-09-17 18:51:26 +0200157
Armin Ronacherfed44b52008-04-13 19:42:53 +0200158 # inside some tags we are using a buffer rather than yield statements.
159 # this for example affects {% filter %} or {% macro %}. If a frame
160 # is buffered this variable points to the name of the list used as
161 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200162 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200163
Armin Ronacherfed44b52008-04-13 19:42:53 +0200164 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200165 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200166
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100167 # a set of actually assigned names
168 self.assigned_names = set()
169
Armin Ronacherfed44b52008-04-13 19:42:53 +0200170 # the parent of this frame
171 self.parent = parent
172
Armin Ronachere791c2a2008-04-07 18:39:54 +0200173 if parent is not None:
174 self.identifiers.declared.update(
175 parent.identifiers.declared |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200176 parent.identifiers.declared_parameter |
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100177 parent.assigned_names
Armin Ronachere791c2a2008-04-07 18:39:54 +0200178 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200179 self.identifiers.outer_undeclared.update(
180 parent.identifiers.undeclared -
181 self.identifiers.declared
182 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200183 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200184
Armin Ronacher8efc5222008-04-08 14:47:40 +0200185 def copy(self):
186 """Create a copy of the current one."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200187 rv = object.__new__(self.__class__)
188 rv.__dict__.update(self.__dict__)
189 rv.identifiers = object.__new__(self.identifiers.__class__)
190 rv.identifiers.__dict__.update(self.identifiers.__dict__)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200191 return rv
192
Armin Ronacherc9705c22008-04-27 21:28:03 +0200193 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200194 """Walk the node and check for identifiers. If the scope is hard (eg:
195 enforce on a python level) overrides from outer scopes are tracked
196 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200197 """
198 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200199 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200200 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200201
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100202 def find_shadowed(self, extra=()):
203 """Find all the shadowed names. extra is an iterable of variables
204 that may be defined with `add_special` which may occour scoped.
205 """
206 i = self.identifiers
207 return (i.declared | i.outer_undeclared) & \
208 (i.declared_locally | i.declared_parameter) | \
209 set(x for x in extra if i.is_declared(x))
210
Armin Ronachere791c2a2008-04-07 18:39:54 +0200211 def inner(self):
212 """Return an inner frame."""
213 return Frame(self)
214
Armin Ronacher75cfb862008-04-11 13:47:22 +0200215 def soft(self):
216 """Return a soft frame. A soft frame may not be modified as
217 standalone thing as it shares the resources with the frame it
218 was created of, but it's not a rootlevel frame any longer.
219 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200220 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200221 rv.rootlevel = False
222 return rv
223
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200224 __copy__ = copy
225
Armin Ronachere791c2a2008-04-07 18:39:54 +0200226
Armin Ronacherc9705c22008-04-27 21:28:03 +0200227class VisitorExit(RuntimeError):
228 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
229
230
231class DependencyFinderVisitor(NodeVisitor):
232 """A visitor that collects filter and test calls."""
233
234 def __init__(self):
235 self.filters = set()
236 self.tests = set()
237
238 def visit_Filter(self, node):
239 self.generic_visit(node)
240 self.filters.add(node.name)
241
242 def visit_Test(self, node):
243 self.generic_visit(node)
244 self.tests.add(node.name)
245
246 def visit_Block(self, node):
247 """Stop visiting at blocks."""
248
249
250class UndeclaredNameVisitor(NodeVisitor):
251 """A visitor that checks if a name is accessed without being
252 declared. This is different from the frame visitor as it will
253 not stop at closure frames.
254 """
255
256 def __init__(self, names):
257 self.names = set(names)
258 self.undeclared = set()
259
260 def visit_Name(self, node):
261 if node.ctx == 'load' and node.name in self.names:
262 self.undeclared.add(node.name)
263 if self.undeclared == self.names:
264 raise VisitorExit()
265 else:
266 self.names.discard(node.name)
267
268 def visit_Block(self, node):
269 """Stop visiting a blocks."""
270
271
Armin Ronachere791c2a2008-04-07 18:39:54 +0200272class FrameIdentifierVisitor(NodeVisitor):
273 """A visitor for `Frame.inspect`."""
274
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200275 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200276 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200277 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200278
Armin Ronacherc9705c22008-04-27 21:28:03 +0200279 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200280 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200281 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200282 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200283 elif node.ctx == 'param':
284 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200285 elif node.ctx == 'load' and not \
286 self.identifiers.is_declared(node.name, self.hard_scope):
287 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200288
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200289 def visit_If(self, node):
290 self.visit(node.test)
Armin Ronacher74230e62009-10-25 12:46:31 +0100291 real_identifiers = self.identifiers
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200292
Armin Ronacher74230e62009-10-25 12:46:31 +0100293 old_names = real_identifiers.declared | \
294 real_identifiers.declared_locally | \
295 real_identifiers.declared_parameter
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200296
Armin Ronacher74230e62009-10-25 12:46:31 +0100297 def inner_visit(nodes):
Armin Ronacher1965e312009-10-25 13:03:08 +0100298 if not nodes:
299 return set()
Armin Ronacher74230e62009-10-25 12:46:31 +0100300 self.identifiers = real_identifiers.copy()
301 for subnode in nodes:
302 self.visit(subnode)
303 rv = self.identifiers.declared_locally - old_names
304 # we have to remember the undeclared variables of this branch
305 # because we will have to pull them.
306 real_identifiers.undeclared.update(self.identifiers.undeclared)
307 self.identifiers = real_identifiers
308 return rv
309
310 body = inner_visit(node.body)
311 else_ = inner_visit(node.else_ or ())
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200312
313 # the differences between the two branches are also pulled as
314 # undeclared variables
Armin Ronacher74230e62009-10-25 12:46:31 +0100315 real_identifiers.undeclared.update(body.symmetric_difference(else_))
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200316
Armin Ronacher74230e62009-10-25 12:46:31 +0100317 # remember those that are declared.
318 real_identifiers.declared_locally.update(body | else_)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200319
Armin Ronacherc9705c22008-04-27 21:28:03 +0200320 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200321 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200322
Armin Ronacherc9705c22008-04-27 21:28:03 +0200323 def visit_Import(self, node):
324 self.generic_visit(node)
325 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200326
Armin Ronacherc9705c22008-04-27 21:28:03 +0200327 def visit_FromImport(self, node):
328 self.generic_visit(node)
329 for name in node.names:
330 if isinstance(name, tuple):
331 self.identifiers.declared_locally.add(name[1])
332 else:
333 self.identifiers.declared_locally.add(name)
334
335 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200336 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200337 self.visit(node.node)
338 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200339
Armin Ronacherc9705c22008-04-27 21:28:03 +0200340 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200341 """Visiting stops at for blocks. However the block sequence
342 is visited as part of the outer scope.
343 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200344 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200345
Armin Ronacherc9705c22008-04-27 21:28:03 +0200346 def visit_CallBlock(self, node):
Armin Ronacheref189442010-01-14 01:26:40 +0100347 self.visit(node.call)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200348
349 def visit_FilterBlock(self, node):
350 self.visit(node.filter)
351
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100352 def visit_Scope(self, node):
353 """Stop visiting at scopes."""
354
Armin Ronacherc9705c22008-04-27 21:28:03 +0200355 def visit_Block(self, node):
356 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200357
358
Armin Ronacher75cfb862008-04-11 13:47:22 +0200359class CompilerExit(Exception):
360 """Raised if the compiler encountered a situation where it just
361 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200362 raises such an exception is not further processed.
363 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200364
365
Armin Ronachere791c2a2008-04-07 18:39:54 +0200366class CodeGenerator(NodeVisitor):
367
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200368 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200369 if stream is None:
370 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200371 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200372 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200373 self.filename = filename
374 self.stream = stream
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100375 self.created_block_context = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200376
Armin Ronacher023b5e92008-05-08 11:03:10 +0200377 # aliases for imports
378 self.import_aliases = {}
379
Armin Ronacherfed44b52008-04-13 19:42:53 +0200380 # a registry for all blocks. Because blocks are moved out
381 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200382 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200383
384 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200385 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200386
387 # some templates have a rootlevel extends. In this case we
388 # can safely assume that we're a child template and do some
389 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200390 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200391
Armin Ronacherba3757b2008-04-16 19:43:16 +0200392 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200393 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200394
Armin Ronacherb9e78752008-05-10 23:36:28 +0200395 # registry of all filters and tests (global, not block local)
396 self.tests = {}
397 self.filters = {}
398
Armin Ronacherba3757b2008-04-16 19:43:16 +0200399 # the debug information
400 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200401 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200402
Armin Ronacherfed44b52008-04-13 19:42:53 +0200403 # the number of new lines before the next write()
404 self._new_lines = 0
405
406 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200407 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200408
409 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200410 self._first_write = True
411
Armin Ronacherfed44b52008-04-13 19:42:53 +0200412 # used by the `temporary_identifier` method to get new
413 # unique, temporary identifier
414 self._last_identifier = 0
415
416 # the current indentation
417 self._indentation = 0
418
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200419 # -- Various compilation helpers
420
Armin Ronachere2244882008-05-19 09:25:57 +0200421 def fail(self, msg, lineno):
422 """Fail with a `TemplateAssertionError`."""
423 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
424
Armin Ronachere791c2a2008-04-07 18:39:54 +0200425 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200426 """Get a new unique identifier."""
427 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200428 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200429
Armin Ronachered1e0d42008-05-18 20:25:28 +0200430 def buffer(self, frame):
431 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200432 frame.buffer = self.temporary_identifier()
433 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200434
435 def return_buffer_contents(self, frame):
436 """Return the buffer contents of the frame."""
437 if self.environment.autoescape:
438 self.writeline('return Markup(concat(%s))' % frame.buffer)
439 else:
440 self.writeline('return concat(%s)' % frame.buffer)
441
Armin Ronachere791c2a2008-04-07 18:39:54 +0200442 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200443 """Indent by one."""
444 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200445
Armin Ronacher8efc5222008-04-08 14:47:40 +0200446 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200447 """Outdent by step."""
448 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200449
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200450 def start_write(self, frame, node=None):
451 """Yield or write into the frame buffer."""
452 if frame.buffer is None:
453 self.writeline('yield ', node)
454 else:
455 self.writeline('%s.append(' % frame.buffer, node)
456
457 def end_write(self, frame):
458 """End the writing process started by `start_write`."""
459 if frame.buffer is not None:
460 self.write(')')
461
462 def simple_write(self, s, frame, node=None):
463 """Simple shortcut for start_write + write + end_write."""
464 self.start_write(frame, node)
465 self.write(s)
466 self.end_write(frame)
467
Armin Ronacherf40c8842008-09-17 18:51:26 +0200468 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200469 """Visit a list of nodes as block in a frame. If the current frame
470 is no buffer a dummy ``if 0: yield None`` is written automatically
471 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200472 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200473 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200474 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200475 else:
476 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200477 try:
478 for node in nodes:
479 self.visit(node, frame)
480 except CompilerExit:
481 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200482
483 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200484 """Write a string into the output stream."""
485 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200486 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200487 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200488 self.code_lineno += self._new_lines
489 if self._write_debug_info is not None:
490 self.debug_info.append((self._write_debug_info,
491 self.code_lineno))
492 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200493 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200494 self.stream.write(' ' * self._indentation)
495 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200496 self.stream.write(x)
497
498 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200499 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200500 self.newline(node, extra)
501 self.write(x)
502
503 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200504 """Add one or more newlines before the next write."""
505 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200506 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200507 self._write_debug_info = node.lineno
508 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200509
Armin Ronacherfd310492008-05-25 00:16:51 +0200510 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200511 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200512 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200513 arguments may not include python keywords otherwise a syntax
514 error could occour. The extra keyword arguments should be given
515 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200516 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200517 # if any of the given keyword arguments is a python keyword
518 # we have to make sure that no invalid call is created.
519 kwarg_workaround = False
520 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200521 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200522 kwarg_workaround = True
523 break
524
Armin Ronacher8efc5222008-04-08 14:47:40 +0200525 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200526 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200527 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200528
529 if not kwarg_workaround:
530 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200531 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200532 self.visit(kwarg, frame)
533 if extra_kwargs is not None:
534 for key, value in extra_kwargs.iteritems():
Armin Ronacherfd310492008-05-25 00:16:51 +0200535 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200536 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200537 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200538 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200539
540 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200541 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200542 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200543 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200544 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200545 for kwarg in node.kwargs:
546 self.write('%r: ' % kwarg.key)
547 self.visit(kwarg.value, frame)
548 self.write(', ')
549 if extra_kwargs is not None:
550 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200551 self.write('%r: %s, ' % (key, value))
552 if node.dyn_kwargs is not None:
553 self.write('}, **')
554 self.visit(node.dyn_kwargs, frame)
555 self.write(')')
556 else:
557 self.write('}')
558
559 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200560 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200561 self.visit(node.dyn_kwargs, frame)
562
Armin Ronacherc9705c22008-04-27 21:28:03 +0200563 def pull_locals(self, frame):
564 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200565 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200566 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200567
568 def pull_dependencies(self, nodes):
569 """Pull all the dependencies."""
570 visitor = DependencyFinderVisitor()
571 for node in nodes:
572 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200573 for dependency in 'filters', 'tests':
574 mapping = getattr(self, dependency)
575 for name in getattr(visitor, dependency):
576 if name not in mapping:
577 mapping[name] = self.temporary_identifier()
578 self.writeline('%s = environment.%s[%r]' %
579 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200580
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100581 def unoptimize_scope(self, frame):
582 """Disable Python optimizations for the frame."""
583 # XXX: this is not that nice but it has no real overhead. It
584 # mainly works because python finds the locals before dead code
585 # is removed. If that breaks we have to add a dummy function
586 # that just accepts the arguments and does nothing.
587 if frame.identifiers.declared:
Armin Ronacher821a4232010-02-17 07:59:38 +0100588 self.writeline('%sdummy(%s)' % (
589 unoptimize_before_dead_code and 'if 0: ' or '',
590 ', '.join('l_' + name for name in frame.identifiers.declared)
591 ))
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100592
Armin Ronacher673aa882008-10-04 18:06:57 +0200593 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200594 """This function returns all the shadowed variables in a dict
595 in the form name: alias and will write the required assignments
596 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200597
Armin Ronacher673aa882008-10-04 18:06:57 +0200598 This also predefines locally declared variables from the loop
599 body because under some circumstances it may be the case that
600
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100601 `extra_vars` is passed to `Frame.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200602 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200603 aliases = {}
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100604 for name in frame.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200605 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200606 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200607 to_declare = set()
608 for name in frame.identifiers.declared_locally:
609 if name not in aliases:
610 to_declare.add('l_' + name)
611 if to_declare:
612 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200613 return aliases
614
Armin Ronacher673aa882008-10-04 18:06:57 +0200615 def pop_scope(self, aliases, frame):
616 """Restore all aliases and delete unused variables."""
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200617 for name, alias in aliases.iteritems():
618 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200619 to_delete = set()
620 for name in frame.identifiers.declared_locally:
621 if name not in aliases:
622 to_delete.add('l_' + name)
623 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100624 # we cannot use the del statement here because enclosed
625 # scopes can trigger a SyntaxError:
626 # a = 42; b = lambda: a; del a
627 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200628
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200629 def function_scoping(self, node, frame, children=None,
630 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200631 """In Jinja a few statements require the help of anonymous
632 functions. Those are currently macros and call blocks and in
633 the future also recursive loops. As there is currently
634 technical limitation that doesn't allow reading and writing a
635 variable in a scope where the initial value is coming from an
636 outer scope, this function tries to fall back with a common
637 error message. Additionally the frame passed is modified so
638 that the argumetns are collected and callers are looked up.
639
640 This will return the modified frame.
641 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200642 # we have to iterate twice over it, make sure that works
643 if children is None:
644 children = node.iter_child_nodes()
645 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200646 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200647 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200648
649 # variables that are undeclared (accessed before declaration) and
650 # declared locally *and* part of an outside scope raise a template
651 # assertion error. Reason: we can't generate reasonable code from
Armin Ronacher02b42a82009-03-18 00:59:32 +0100652 # it without aliasing all the variables.
653 # this could be fixed in Python 3 where we have the nonlocal
654 # keyword or if we switch to bytecode generation
Armin Ronacher71082072008-04-12 14:19:36 +0200655 overriden_closure_vars = (
656 func_frame.identifiers.undeclared &
657 func_frame.identifiers.declared &
658 (func_frame.identifiers.declared_locally |
659 func_frame.identifiers.declared_parameter)
660 )
661 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200662 self.fail('It\'s not possible to set and access variables '
Armin Ronacherefcc0e52009-09-13 00:22:50 -0700663 'derived from an outer scope! (affects: %s)' %
Armin Ronachere2244882008-05-19 09:25:57 +0200664 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200665
666 # remove variables from a closure from the frame's undeclared
667 # identifiers.
668 func_frame.identifiers.undeclared -= (
669 func_frame.identifiers.undeclared &
670 func_frame.identifiers.declared
671 )
672
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200673 # no special variables for this scope, abort early
674 if not find_special:
675 return func_frame
676
Armin Ronacher963f97d2008-04-25 11:44:59 +0200677 func_frame.accesses_kwargs = False
678 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200679 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200680 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200681
Armin Ronacherc9705c22008-04-27 21:28:03 +0200682 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
683
684 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200685 func_frame.accesses_caller = True
686 func_frame.identifiers.add_special('caller')
687 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200688 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200689 func_frame.accesses_kwargs = True
690 func_frame.identifiers.add_special('kwargs')
691 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200692 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200693 func_frame.accesses_varargs = True
694 func_frame.identifiers.add_special('varargs')
695 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200696 return func_frame
697
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200698 def macro_body(self, node, frame, children=None):
699 """Dump the function def of a macro or call block."""
700 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100701 # macros are delayed, they never require output checks
702 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200703 args = frame.arguments
Armin Ronachereabf3dd2009-09-12 23:48:18 -0700704 # XXX: this is an ugly fix for the loop nesting bug
705 # (tests.test_old_bugs.test_loop_call_bug). This works around
706 # a identifier nesting problem we have in general. It's just more
707 # likely to happen in loops which is why we work around it. The
708 # real solution would be "nonlocal" all the identifiers that are
709 # leaking into a new python frame and might be used both unassigned
710 # and assigned.
711 if 'loop' in frame.identifiers.declared:
Armin Ronacherb4044392009-09-13 15:56:58 -0700712 args = args + ['l_loop=l_loop']
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200713 self.writeline('def macro(%s):' % ', '.join(args), node)
714 self.indent()
715 self.buffer(frame)
716 self.pull_locals(frame)
717 self.blockvisit(node.body, frame)
718 self.return_buffer_contents(frame)
719 self.outdent()
720 return frame
721
722 def macro_def(self, node, frame):
723 """Dump the macro definition for the def created by macro_body."""
724 arg_tuple = ', '.join(repr(x.name) for x in node.args)
725 name = getattr(node, 'name', None)
726 if len(node.args) == 1:
727 arg_tuple += ','
728 self.write('Macro(environment, macro, %r, (%s), (' %
729 (name, arg_tuple))
730 for arg in node.defaults:
731 self.visit(arg, frame)
732 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200733 self.write('), %r, %r, %r)' % (
734 bool(frame.accesses_kwargs),
735 bool(frame.accesses_varargs),
736 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200737 ))
738
Armin Ronacher547d0b62008-07-04 16:35:10 +0200739 def position(self, node):
740 """Return a human readable position for the node."""
741 rv = 'line %d' % node.lineno
742 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100743 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200744 return rv
745
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200746 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200747
748 def visit_Template(self, node, frame=None):
749 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200750 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200751 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200752 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher821a4232010-02-17 07:59:38 +0100753 if not unoptimize_before_dead_code:
754 self.writeline('dummy = lambda *x: None')
Armin Ronacher8edbe492008-04-10 20:43:43 +0200755
Armin Ronacher75cfb862008-04-11 13:47:22 +0200756 # do we have an extends tag at all? If not, we can save some
757 # overhead by just not processing any inheritance code.
758 have_extends = node.find(nodes.Extends) is not None
759
Armin Ronacher8edbe492008-04-10 20:43:43 +0200760 # find all blocks
761 for block in node.find_all(nodes.Block):
762 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200763 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200764 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200765
Armin Ronacher023b5e92008-05-08 11:03:10 +0200766 # find all imports and import them
767 for import_ in node.find_all(nodes.ImportedName):
768 if import_.importname not in self.import_aliases:
769 imp = import_.importname
770 self.import_aliases[imp] = alias = self.temporary_identifier()
771 if '.' in imp:
772 module, obj = imp.rsplit('.', 1)
773 self.writeline('from %s import %s as %s' %
774 (module, obj, alias))
775 else:
776 self.writeline('import %s as %s' % (imp, alias))
777
778 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200779 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200780
Armin Ronacher8efc5222008-04-08 14:47:40 +0200781 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200782 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200783
784 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200785 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200786 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200787 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200788 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200789 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200790 if have_extends:
791 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200792 if 'self' in find_undeclared(node.body, ('self',)):
793 frame.identifiers.add_special('self')
794 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200795 self.pull_locals(frame)
796 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200797 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200798 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200799
Armin Ronacher8efc5222008-04-08 14:47:40 +0200800 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200801 if have_extends:
802 if not self.has_known_extends:
803 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200804 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200805 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200806 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200807 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200808 self.indent()
809 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200810 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200811
812 # at this point we now have the blocks collected and can visit them too.
813 for name, block in self.blocks.iteritems():
814 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200815 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200816 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200817 self.writeline('def block_%s(context, environment=environment):'
818 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200819 self.indent()
820 undeclared = find_undeclared(block.body, ('self', 'super'))
821 if 'self' in undeclared:
822 block_frame.identifiers.add_special('self')
823 self.writeline('l_self = TemplateReference(context)')
824 if 'super' in undeclared:
825 block_frame.identifiers.add_special('super')
826 self.writeline('l_super = context.super(%r, '
827 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200828 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200829 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200830 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200831 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200832
Armin Ronacher75cfb862008-04-11 13:47:22 +0200833 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200834 for x in self.blocks),
835 extra=1)
836
837 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200838 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
839 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200840
Armin Ronachere791c2a2008-04-07 18:39:54 +0200841 def visit_Block(self, node, frame):
842 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200843 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200844 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200845 # if we know that we are a child template, there is no need to
846 # check if we are one
847 if self.has_known_extends:
848 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200849 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200850 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200851 self.indent()
852 level += 1
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100853 context = node.scoped and 'context.derived(locals())' or 'context'
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100854 self.writeline('for event in context.blocks[%r][0](%s):' % (
855 node.name, context), node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200856 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200857 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200858 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200859
860 def visit_Extends(self, node, frame):
861 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200862 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200863 self.fail('cannot use extend from a non top-level scope',
864 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200865
Armin Ronacher7fb38972008-04-11 13:54:28 +0200866 # if the number of extends statements in general is zero so
867 # far, we don't have to add a check if something extended
868 # the template before this one.
869 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200870
Armin Ronacher7fb38972008-04-11 13:54:28 +0200871 # if we have a known extends we just add a template runtime
872 # error into the generated code. We could catch that at compile
873 # time too, but i welcome it not to confuse users by throwing the
874 # same error at different times just "because we can".
875 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200876 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200877 self.indent()
878 self.writeline('raise TemplateRuntimeError(%r)' %
879 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200880 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200881
Armin Ronacher7fb38972008-04-11 13:54:28 +0200882 # if we have a known extends already we don't need that code here
883 # as we know that the template execution will end here.
884 if self.has_known_extends:
885 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200886
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200887 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200888 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200889 self.write(', %r)' % self.name)
890 self.writeline('for name, parent_block in parent_template.'
Armin Ronacher0d242be2010-02-10 01:35:13 +0100891 'blocks.%s():' % dict_item_iter)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200892 self.indent()
893 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200894 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200895 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200896
897 # if this extends statement was in the root level we can take
898 # advantage of that information and simplify the generated code
899 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200900 if frame.rootlevel:
901 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200902
Armin Ronacher7fb38972008-04-11 13:54:28 +0200903 # and now we have one more
904 self.extends_so_far += 1
905
Armin Ronacherf059ec12008-04-11 22:21:00 +0200906 def visit_Include(self, node, frame):
907 """Handles includes."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100908 if node.with_context:
909 self.unoptimize_scope(frame)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100910 if node.ignore_missing:
911 self.writeline('try:')
912 self.indent()
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100913
914 func_name = 'get_or_select_template'
915 if isinstance(node.template, nodes.Const):
916 if isinstance(node.template.value, basestring):
917 func_name = 'get_template'
918 elif isinstance(node.template.value, (tuple, list)):
919 func_name = 'select_template'
920 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
921 func_name = 'select_template'
922
923 self.writeline('template = environment.%s(' % func_name, node)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100924 self.visit(node.template, frame)
925 self.write(', %r)' % self.name)
926 if node.ignore_missing:
927 self.outdent()
928 self.writeline('except TemplateNotFound:')
929 self.indent()
930 self.writeline('pass')
931 self.outdent()
932 self.writeline('else:')
933 self.indent()
934
Armin Ronacherea847c52008-05-02 20:04:32 +0200935 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200936 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200937 'template.new_context(context.parent, True, '
938 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200939 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100940 self.writeline('for event in template.module._body_stream:')
941
Armin Ronacherf059ec12008-04-11 22:21:00 +0200942 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200943 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200944 self.outdent()
945
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100946 if node.ignore_missing:
947 self.outdent()
948
Armin Ronacher0611e492008-04-25 23:44:14 +0200949 def visit_Import(self, node, frame):
950 """Visit regular imports."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100951 if node.with_context:
952 self.unoptimize_scope(frame)
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200953 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200954 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200955 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200956 self.write('environment.get_template(')
957 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200958 self.write(', %r).' % self.name)
959 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200960 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200961 else:
962 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200963 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200964 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100965 frame.assigned_names.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200966
967 def visit_FromImport(self, node, frame):
968 """Visit named imports."""
969 self.newline(node)
970 self.write('included_template = environment.get_template(')
971 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200972 self.write(', %r).' % self.name)
973 if node.with_context:
974 self.write('make_module(context.parent, True)')
975 else:
976 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200977
978 var_names = []
979 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200980 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200981 if isinstance(name, tuple):
982 name, alias = name
983 else:
984 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200985 self.writeline('l_%s = getattr(included_template, '
986 '%r, missing)' % (alias, name))
987 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200988 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200989 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +0200990 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200991 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +0200992 (alias, 'the template %%r (imported on %s) does '
993 'not export the requested name %s' % (
994 self.position(node),
995 repr(name)
996 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +0200997 self.outdent()
998 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +0200999 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +02001000 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +02001001 discarded_names.append(alias)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001002 frame.assigned_names.add(alias)
Armin Ronachera78d2762008-05-15 23:18:07 +02001003
1004 if var_names:
1005 if len(var_names) == 1:
1006 name = var_names[0]
1007 self.writeline('context.vars[%r] = l_%s' % (name, name))
1008 else:
1009 self.writeline('context.vars.update({%s})' % ', '.join(
1010 '%r: l_%s' % (name, name) for name in var_names
1011 ))
1012 if discarded_names:
1013 if len(discarded_names) == 1:
1014 self.writeline('context.exported_vars.discard(%r)' %
1015 discarded_names[0])
1016 else:
1017 self.writeline('context.exported_vars.difference_'
1018 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +02001019
Armin Ronachere791c2a2008-04-07 18:39:54 +02001020 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001021 # when calculating the nodes for the inner frame we have to exclude
1022 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001023 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001024 if node.recursive:
1025 loop_frame = self.function_scoping(node, frame, children,
1026 find_special=False)
1027 else:
1028 loop_frame = frame.inner()
1029 loop_frame.inspect(children)
1030
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001031 # try to figure out if we have an extended loop. An extended loop
1032 # is necessary if the loop is in recursive mode if the special loop
1033 # variable is accessed in the body.
1034 extended_loop = node.recursive or 'loop' in \
1035 find_undeclared(node.iter_child_nodes(
1036 only=('body',)), ('loop',))
1037
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001038 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +02001039 # variables at that point. Because loops can be nested but the loop
1040 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001041 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +02001042 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001043
1044 # otherwise we set up a buffer and add a function def
1045 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001046 self.writeline('def loop(reciter, loop_render_func):', node)
1047 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +02001048 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001049 aliases = {}
1050
Armin Ronacherff53c782008-08-13 18:55:50 +02001051 # make sure the loop variable is a special one and raise a template
1052 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +02001053 if extended_loop:
1054 loop_frame.identifiers.add_special('loop')
Armin Ronacherff53c782008-08-13 18:55:50 +02001055 for name in node.find_all(nodes.Name):
1056 if name.ctx == 'store' and name.name == 'loop':
1057 self.fail('Can\'t assign to special loop variable '
1058 'in for-loop target', name.lineno)
1059
Armin Ronacherc9705c22008-04-27 21:28:03 +02001060 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001061 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001062 iteration_indicator = self.temporary_identifier()
1063 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001064
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001065 # Create a fake parent loop if the else or test section of a
1066 # loop is accessing the special loop variable and no parent loop
1067 # exists.
1068 if 'loop' not in aliases and 'loop' in find_undeclared(
1069 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1070 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001071 ("'loop' is undefined. the filter section of a loop as well "
1072 "as the else block doesn't have access to the special 'loop'"
1073 " variable of the current loop. Because there is no parent "
1074 "loop it's undefined. Happened in loop on %s" %
1075 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001076
1077 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001078 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +02001079 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001080
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001081 # if we have an extened loop and a node test, we filter in the
1082 # "outer frame".
1083 if extended_loop and node.test is not None:
1084 self.write('(')
1085 self.visit(node.target, loop_frame)
1086 self.write(' for ')
1087 self.visit(node.target, loop_frame)
1088 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001089 if node.recursive:
1090 self.write('reciter')
1091 else:
1092 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001093 self.write(' if (')
1094 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001095 self.visit(node.test, test_frame)
1096 self.write('))')
1097
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001098 elif node.recursive:
1099 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001100 else:
1101 self.visit(node.iter, loop_frame)
1102
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001103 if node.recursive:
1104 self.write(', recurse=loop_render_func):')
1105 else:
1106 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001107
1108 # tests in not extended loops become a continue
1109 if not extended_loop and node.test is not None:
1110 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +02001111 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +02001112 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001113 self.write(':')
1114 self.indent()
1115 self.writeline('continue')
1116 self.outdent(2)
1117
Armin Ronacherc9705c22008-04-27 21:28:03 +02001118 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001119 self.blockvisit(node.body, loop_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001120 if node.else_:
1121 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001122 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001123
1124 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001125 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001126 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001127 self.blockvisit(node.else_, loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001128 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001129
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001130 # reset the aliases if there are any.
Armin Ronachercebd8382008-12-25 18:33:46 +01001131 if not node.recursive:
1132 self.pop_scope(aliases, loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001133
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001134 # if the node was recursive we have to return the buffer contents
1135 # and start the iteration code
1136 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001137 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001138 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001139 self.start_write(frame, node)
1140 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001141 self.visit(node.iter, frame)
1142 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001143 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001144
Armin Ronachere791c2a2008-04-07 18:39:54 +02001145 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001146 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001147 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001148 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001149 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001150 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001151 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001152 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001153 if node.else_:
1154 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001155 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001156 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001157 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001158
Armin Ronacher8efc5222008-04-08 14:47:40 +02001159 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001160 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001161 self.newline()
1162 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001163 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001164 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001165 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001166 self.write('l_%s = ' % node.name)
1167 self.macro_def(node, macro_frame)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001168 frame.assigned_names.add(node.name)
Armin Ronacher71082072008-04-12 14:19:36 +02001169
1170 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001171 children = node.iter_child_nodes(exclude=('call',))
1172 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001173 self.writeline('caller = ')
1174 self.macro_def(node, call_frame)
1175 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001176 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001177 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001178
1179 def visit_FilterBlock(self, node, frame):
1180 filter_frame = frame.inner()
1181 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacher673aa882008-10-04 18:06:57 +02001182 aliases = self.push_scope(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001183 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001184 self.buffer(filter_frame)
Armin Ronacherf40c8842008-09-17 18:51:26 +02001185 self.blockvisit(node.body, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001186 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001187 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001188 self.end_write(frame)
Armin Ronacher673aa882008-10-04 18:06:57 +02001189 self.pop_scope(aliases, filter_frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001190
Armin Ronachere791c2a2008-04-07 18:39:54 +02001191 def visit_ExprStmt(self, node, frame):
1192 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001193 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001194
1195 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001196 # if we have a known extends statement, we don't output anything
Armin Ronacher79668952008-09-23 22:52:46 +02001197 # if we are in a require_output_check section
1198 if self.has_known_extends and frame.require_output_check:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001199 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001200
Armin Ronacher665bfb82008-07-14 13:41:46 +02001201 if self.environment.finalize:
1202 finalize = lambda x: unicode(self.environment.finalize(x))
1203 else:
1204 finalize = unicode
1205
Armin Ronacher75cfb862008-04-11 13:47:22 +02001206 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001207
Armin Ronacher79668952008-09-23 22:52:46 +02001208 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001209 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001210 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001211 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001212 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001213 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001214
Armin Ronachere791c2a2008-04-07 18:39:54 +02001215 # try to evaluate as many chunks as possible into a static
1216 # string at compile time.
1217 body = []
1218 for child in node.nodes:
1219 try:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001220 const = child.as_const()
1221 except nodes.Impossible:
1222 body.append(child)
1223 continue
1224 try:
1225 if self.environment.autoescape:
1226 if hasattr(const, '__html__'):
1227 const = const.__html__()
1228 else:
1229 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001230 const = finalize(const)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001231 except:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001232 # if something goes wrong here we evaluate the node
1233 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001234 body.append(child)
1235 continue
1236 if body and isinstance(body[-1], list):
1237 body[-1].append(const)
1238 else:
1239 body.append([const])
1240
Armin Ronachered1e0d42008-05-18 20:25:28 +02001241 # if we have less than 3 nodes or a buffer we yield or extend/append
1242 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001243 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001244 # for one item we append, for more we extend
1245 if len(body) == 1:
1246 self.writeline('%s.append(' % frame.buffer)
1247 else:
1248 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001249 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001250 for item in body:
1251 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001252 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001253 if frame.buffer is None:
1254 self.writeline('yield ' + val)
1255 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001256 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001257 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001258 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001259 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001260 else:
1261 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001262 close = 1
1263 if self.environment.autoescape:
1264 self.write('escape(')
1265 else:
Armin Ronacherbd357722009-08-05 20:25:06 +02001266 self.write('to_string(')
Armin Ronacherd1342312008-04-28 12:20:12 +02001267 if self.environment.finalize is not None:
1268 self.write('environment.finalize(')
1269 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001270 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001271 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001272 if frame.buffer is not None:
1273 self.write(', ')
1274 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001275 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001276 self.outdent()
1277 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001278
1279 # otherwise we create a format string as this is faster in that case
1280 else:
1281 format = []
1282 arguments = []
1283 for item in body:
1284 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001285 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001286 else:
1287 format.append('%s')
1288 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001289 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001290 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001291 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001292 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001293 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001294 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001295 close = 0
1296 if self.environment.autoescape:
1297 self.write('escape(')
1298 close += 1
1299 if self.environment.finalize is not None:
1300 self.write('environment.finalize(')
1301 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001302 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001303 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001304 self.outdent()
1305 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001306
Armin Ronacher7fb38972008-04-11 13:54:28 +02001307 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001308 self.outdent()
1309
Armin Ronacher8efc5222008-04-08 14:47:40 +02001310 def visit_Assign(self, node, frame):
1311 self.newline(node)
1312 # toplevel assignments however go into the local namespace and
1313 # the current template's context. We create a copy of the frame
1314 # here and add a set so that the Name visitor can add the assigned
1315 # names here.
1316 if frame.toplevel:
1317 assignment_frame = frame.copy()
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001318 assignment_frame.toplevel_assignments = set()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001319 else:
1320 assignment_frame = frame
1321 self.visit(node.target, assignment_frame)
1322 self.write(' = ')
1323 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001324
1325 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001326 if frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001327 public_names = [x for x in assignment_frame.toplevel_assignments
Armin Ronacher903d1682008-05-23 00:51:58 +02001328 if not x.startswith('_')]
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001329 if len(assignment_frame.toplevel_assignments) == 1:
Armin Ronacherbd357722009-08-05 20:25:06 +02001330 name = next(iter(assignment_frame.toplevel_assignments))
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001331 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001332 else:
1333 self.writeline('context.vars.update({')
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001334 for idx, name in enumerate(assignment_frame.toplevel_assignments):
Armin Ronacher69e12db2008-05-12 09:00:03 +02001335 if idx:
1336 self.write(', ')
1337 self.write('%r: l_%s' % (name, name))
1338 self.write('})')
1339 if public_names:
1340 if len(public_names) == 1:
1341 self.writeline('context.exported_vars.add(%r)' %
1342 public_names[0])
1343 else:
1344 self.writeline('context.exported_vars.update((%s))' %
1345 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001346
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001347 # -- Expression Visitors
1348
Armin Ronachere791c2a2008-04-07 18:39:54 +02001349 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001350 if node.ctx == 'store' and frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001351 frame.toplevel_assignments.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001352 self.write('l_' + node.name)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001353 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001354
1355 def visit_Const(self, node, frame):
1356 val = node.value
1357 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001358 self.write(str(val))
1359 else:
1360 self.write(repr(val))
1361
Armin Ronacher5411ce72008-05-25 11:36:22 +02001362 def visit_TemplateData(self, node, frame):
1363 self.write(repr(node.as_const()))
1364
Armin Ronacher8efc5222008-04-08 14:47:40 +02001365 def visit_Tuple(self, node, frame):
1366 self.write('(')
1367 idx = -1
1368 for idx, item in enumerate(node.items):
1369 if idx:
1370 self.write(', ')
1371 self.visit(item, frame)
1372 self.write(idx == 0 and ',)' or ')')
1373
Armin Ronacher8edbe492008-04-10 20:43:43 +02001374 def visit_List(self, node, frame):
1375 self.write('[')
1376 for idx, item in enumerate(node.items):
1377 if idx:
1378 self.write(', ')
1379 self.visit(item, frame)
1380 self.write(']')
1381
1382 def visit_Dict(self, node, frame):
1383 self.write('{')
1384 for idx, item in enumerate(node.items):
1385 if idx:
1386 self.write(', ')
1387 self.visit(item.key, frame)
1388 self.write(': ')
1389 self.visit(item.value, frame)
1390 self.write('}')
1391
Armin Ronachere791c2a2008-04-07 18:39:54 +02001392 def binop(operator):
1393 def visitor(self, node, frame):
1394 self.write('(')
1395 self.visit(node.left, frame)
1396 self.write(' %s ' % operator)
1397 self.visit(node.right, frame)
1398 self.write(')')
1399 return visitor
1400
1401 def uaop(operator):
1402 def visitor(self, node, frame):
1403 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001404 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001405 self.write(')')
1406 return visitor
1407
1408 visit_Add = binop('+')
1409 visit_Sub = binop('-')
1410 visit_Mul = binop('*')
1411 visit_Div = binop('/')
1412 visit_FloorDiv = binop('//')
1413 visit_Pow = binop('**')
1414 visit_Mod = binop('%')
1415 visit_And = binop('and')
1416 visit_Or = binop('or')
1417 visit_Pos = uaop('+')
1418 visit_Neg = uaop('-')
1419 visit_Not = uaop('not ')
1420 del binop, uaop
1421
Armin Ronacherd1342312008-04-28 12:20:12 +02001422 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001423 self.write('%s((' % (self.environment.autoescape and
1424 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001425 for arg in node.nodes:
1426 self.visit(arg, frame)
1427 self.write(', ')
1428 self.write('))')
1429
Armin Ronachere791c2a2008-04-07 18:39:54 +02001430 def visit_Compare(self, node, frame):
1431 self.visit(node.expr, frame)
1432 for op in node.ops:
1433 self.visit(op, frame)
1434
1435 def visit_Operand(self, node, frame):
1436 self.write(' %s ' % operators[node.op])
1437 self.visit(node.expr, frame)
1438
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001439 def visit_Getattr(self, node, frame):
1440 self.write('environment.getattr(')
1441 self.visit(node.node, frame)
1442 self.write(', %r)' % node.attr)
1443
1444 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001445 # slices bypass the environment getitem method.
1446 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001447 self.visit(node.node, frame)
1448 self.write('[')
1449 self.visit(node.arg, frame)
1450 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001451 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001452 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001453 self.visit(node.node, frame)
1454 self.write(', ')
1455 self.visit(node.arg, frame)
1456 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001457
1458 def visit_Slice(self, node, frame):
1459 if node.start is not None:
1460 self.visit(node.start, frame)
1461 self.write(':')
1462 if node.stop is not None:
1463 self.visit(node.stop, frame)
1464 if node.step is not None:
1465 self.write(':')
1466 self.visit(node.step, frame)
1467
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001468 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001469 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001470 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001471 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001472 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001473 if getattr(func, 'contextfilter', False):
1474 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001475 elif getattr(func, 'environmentfilter', False):
1476 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001477
1478 # if the filter node is None we are inside a filter block
1479 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001480 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001481 self.visit(node.node, frame)
Armin Ronacher3da90312008-05-23 16:37:28 +02001482 elif self.environment.autoescape:
1483 self.write('Markup(concat(%s))' % frame.buffer)
1484 else:
1485 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001486 self.signature(node, frame)
1487 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001488
1489 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001490 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001491 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001492 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001493 self.visit(node.node, frame)
1494 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001495 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001496
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001497 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001498 def write_expr2():
1499 if node.expr2 is not None:
1500 return self.visit(node.expr2, frame)
1501 self.write('environment.undefined(%r)' % ('the inline if-'
1502 'expression on %s evaluated to false and '
1503 'no else section was defined.' % self.position(node)))
1504
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001505 if not have_condexpr:
1506 self.write('((')
1507 self.visit(node.test, frame)
1508 self.write(') and (')
1509 self.visit(node.expr1, frame)
1510 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001511 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001512 self.write(',))[0]')
1513 else:
1514 self.write('(')
1515 self.visit(node.expr1, frame)
1516 self.write(' if ')
1517 self.visit(node.test, frame)
1518 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001519 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001520 self.write(')')
1521
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001522 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001523 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001524 self.write('environment.call(context, ')
1525 else:
1526 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001527 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001528 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001529 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001530 self.write(')')
1531
1532 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001533 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001534 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001535
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001536 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001537
1538 def visit_MarkSafe(self, node, frame):
1539 self.write('Markup(')
1540 self.visit(node.expr, frame)
1541 self.write(')')
1542
1543 def visit_EnvironmentAttribute(self, node, frame):
1544 self.write('environment.' + node.name)
1545
1546 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001547 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001548
1549 def visit_ImportedName(self, node, frame):
1550 self.write(self.import_aliases[node.importname])
1551
1552 def visit_InternalName(self, node, frame):
1553 self.write(node.name)
1554
Armin Ronacher6df604e2008-05-23 22:18:38 +02001555 def visit_ContextReference(self, node, frame):
1556 self.write('context')
1557
Armin Ronachered1e0d42008-05-18 20:25:28 +02001558 def visit_Continue(self, node, frame):
1559 self.writeline('continue', node)
1560
1561 def visit_Break(self, node, frame):
1562 self.writeline('break', node)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001563
1564 def visit_Scope(self, node, frame):
1565 scope_frame = frame.inner()
1566 scope_frame.inspect(node.iter_child_nodes())
1567 aliases = self.push_scope(scope_frame)
1568 self.pull_locals(scope_frame)
1569 self.blockvisit(node.body, scope_frame)
1570 self.pop_scope(aliases, scope_frame)