blob: 64a75cc300255b019b56e6cb7ad41b45daededca [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 Ronacherd1ff8582008-05-11 00:30:43 +020011from itertools import chain
Armin Ronacher74230e62009-10-25 12:46:31 +010012from copy import deepcopy
Armin Ronachere791c2a2008-04-07 18:39:54 +020013from jinja2 import nodes
Armin Ronacher8346bd72010-03-14 19:43:47 +010014from jinja2.nodes import EvalContext
Armin Ronacher9573b662010-12-21 00:44:34 +010015from jinja2.visitor import NodeVisitor
Armin Ronachere791c2a2008-04-07 18:39:54 +020016from jinja2.exceptions import TemplateAssertionError
Thomas Waldmann7d295622013-05-18 00:06:22 +020017from jinja2.utils import Markup, concat, escape, is_python_keyword
Thomas Waldmanne0003552013-05-17 23:52:14 +020018import six
Thomas Waldmann7d295622013-05-18 00:06:22 +020019from six.moves import cStringIO as StringIO
20from six.moves import map, zip
Armin Ronachere791c2a2008-04-07 18:39:54 +020021
Cory Benfieldd5a0edf2013-05-18 11:41:24 +010022# TODO: Move this to the compat module.
23try:
24 range_type = xrange
25except NameError:
26 range_type = range
27
Armin Ronachere791c2a2008-04-07 18:39:54 +020028
29operators = {
30 'eq': '==',
31 'ne': '!=',
32 'gt': '>',
33 'gteq': '>=',
34 'lt': '<',
35 'lteq': '<=',
36 'in': 'in',
37 'notin': 'not in'
38}
39
Armin Ronacher3d8b7842008-04-13 13:16:50 +020040try:
Thomas Waldmanne0003552013-05-17 23:52:14 +020041 exec('(0 if 0 else 0)')
Armin Ronacher3d8b7842008-04-13 13:16:50 +020042except SyntaxError:
43 have_condexpr = False
44else:
45 have_condexpr = True
46
47
Armin Ronacher0d242be2010-02-10 01:35:13 +010048# what method to iterate over items do we want to use for dict iteration
49# in generated code? on 2.x let's go with iteritems, on 3.x with items
50if hasattr(dict, 'iteritems'):
51 dict_item_iter = 'iteritems'
52else:
53 dict_item_iter = 'items'
54
55
Armin Ronacher821a4232010-02-17 07:59:38 +010056# does if 0: dummy(x) get us x into the scope?
57def unoptimize_before_dead_code():
58 x = 42
59 def f():
60 if 0: dummy(x)
61 return f
Thomas Waldmanne0003552013-05-17 23:52:14 +020062unoptimize_before_dead_code = bool(unoptimize_before_dead_code().__closure__)
Armin Ronacher821a4232010-02-17 07:59:38 +010063
64
Armin Ronacher64b08a02010-03-12 03:17:41 +010065def generate(node, environment, name, filename, stream=None,
66 defer_init=False):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020067 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020068 if not isinstance(node, nodes.Template):
69 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher64b08a02010-03-12 03:17:41 +010070 generator = CodeGenerator(environment, name, filename, stream, defer_init)
Armin Ronachere791c2a2008-04-07 18:39:54 +020071 generator.visit(node)
72 if stream is None:
73 return generator.stream.getvalue()
74
75
Armin Ronacher4dfc9752008-04-09 15:03:29 +020076def has_safe_repr(value):
77 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020078 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020079 return True
Thomas Waldmann7d295622013-05-18 00:06:22 +020080 if isinstance(value, (bool, int, float, complex, range_type, Markup) + six.string_types):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020081 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020082 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020083 for item in value:
84 if not has_safe_repr(item):
85 return False
86 return True
87 elif isinstance(value, dict):
Thomas Waldmanne0003552013-05-17 23:52:14 +020088 for key, value in six.iteritems(value):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020089 if not has_safe_repr(key):
90 return False
91 if not has_safe_repr(value):
92 return False
93 return True
94 return False
95
96
Armin Ronacherc9705c22008-04-27 21:28:03 +020097def find_undeclared(nodes, names):
98 """Check if the names passed are accessed undeclared. The return value
99 is a set of all the undeclared names from the sequence of names found.
100 """
101 visitor = UndeclaredNameVisitor(names)
102 try:
103 for node in nodes:
104 visitor.visit(node)
105 except VisitorExit:
106 pass
107 return visitor.undeclared
108
109
Armin Ronachere791c2a2008-04-07 18:39:54 +0200110class Identifiers(object):
111 """Tracks the status of identifiers in frames."""
112
113 def __init__(self):
114 # variables that are known to be declared (probably from outer
115 # frames or because they are special for the frame)
116 self.declared = set()
117
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200118 # undeclared variables from outer scopes
119 self.outer_undeclared = set()
120
Armin Ronachere791c2a2008-04-07 18:39:54 +0200121 # names that are accessed without being explicitly declared by
122 # this one or any of the outer scopes. Names can appear both in
123 # declared and undeclared.
124 self.undeclared = set()
125
126 # names that are declared locally
127 self.declared_locally = set()
128
129 # names that are declared by parameters
130 self.declared_parameter = set()
131
132 def add_special(self, name):
133 """Register a special name like `loop`."""
134 self.undeclared.discard(name)
135 self.declared.add(name)
136
Armin Ronacherda632622011-03-13 14:33:27 -0400137 def is_declared(self, name):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200138 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200139 if name in self.declared_locally or name in self.declared_parameter:
140 return True
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200141 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200142
Armin Ronacher74230e62009-10-25 12:46:31 +0100143 def copy(self):
144 return deepcopy(self)
145
Armin Ronachere791c2a2008-04-07 18:39:54 +0200146
147class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200148 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200149
Armin Ronacher8346bd72010-03-14 19:43:47 +0100150 def __init__(self, eval_ctx, parent=None):
151 self.eval_ctx = eval_ctx
Armin Ronachere791c2a2008-04-07 18:39:54 +0200152 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200153
Armin Ronacher75cfb862008-04-11 13:47:22 +0200154 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200155 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200156
Armin Ronacher75cfb862008-04-11 13:47:22 +0200157 # the root frame is basically just the outermost frame, so no if
158 # conditions. This information is used to optimize inheritance
159 # situations.
160 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200161
Armin Ronacher79668952008-09-23 22:52:46 +0200162 # in some dynamic inheritance situations the compiler needs to add
163 # write tests around output statements.
164 self.require_output_check = parent and parent.require_output_check
Armin Ronacherf40c8842008-09-17 18:51:26 +0200165
Armin Ronacherfed44b52008-04-13 19:42:53 +0200166 # inside some tags we are using a buffer rather than yield statements.
167 # this for example affects {% filter %} or {% macro %}. If a frame
168 # is buffered this variable points to the name of the list used as
169 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200170 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200171
Armin Ronacherfed44b52008-04-13 19:42:53 +0200172 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200173 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200174
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100175 # a set of actually assigned names
176 self.assigned_names = set()
177
Armin Ronacherfed44b52008-04-13 19:42:53 +0200178 # the parent of this frame
179 self.parent = parent
180
Armin Ronachere791c2a2008-04-07 18:39:54 +0200181 if parent is not None:
182 self.identifiers.declared.update(
183 parent.identifiers.declared |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200184 parent.identifiers.declared_parameter |
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100185 parent.assigned_names
Armin Ronachere791c2a2008-04-07 18:39:54 +0200186 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200187 self.identifiers.outer_undeclared.update(
188 parent.identifiers.undeclared -
189 self.identifiers.declared
190 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200191 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200192
Armin Ronacher8efc5222008-04-08 14:47:40 +0200193 def copy(self):
194 """Create a copy of the current one."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200195 rv = object.__new__(self.__class__)
196 rv.__dict__.update(self.__dict__)
197 rv.identifiers = object.__new__(self.identifiers.__class__)
198 rv.identifiers.__dict__.update(self.identifiers.__dict__)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200199 return rv
200
Armin Ronacherda632622011-03-13 14:33:27 -0400201 def inspect(self, nodes):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200202 """Walk the node and check for identifiers. If the scope is hard (eg:
203 enforce on a python level) overrides from outer scopes are tracked
204 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200205 """
Armin Ronacherda632622011-03-13 14:33:27 -0400206 visitor = FrameIdentifierVisitor(self.identifiers)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200207 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200208 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200209
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100210 def find_shadowed(self, extra=()):
211 """Find all the shadowed names. extra is an iterable of variables
212 that may be defined with `add_special` which may occour scoped.
213 """
214 i = self.identifiers
215 return (i.declared | i.outer_undeclared) & \
216 (i.declared_locally | i.declared_parameter) | \
217 set(x for x in extra if i.is_declared(x))
218
Armin Ronachere791c2a2008-04-07 18:39:54 +0200219 def inner(self):
220 """Return an inner frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100221 return Frame(self.eval_ctx, self)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200222
Armin Ronacher75cfb862008-04-11 13:47:22 +0200223 def soft(self):
224 """Return a soft frame. A soft frame may not be modified as
225 standalone thing as it shares the resources with the frame it
226 was created of, but it's not a rootlevel frame any longer.
227 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200228 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200229 rv.rootlevel = False
230 return rv
231
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200232 __copy__ = copy
233
Armin Ronachere791c2a2008-04-07 18:39:54 +0200234
Armin Ronacherc9705c22008-04-27 21:28:03 +0200235class VisitorExit(RuntimeError):
236 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
237
238
239class DependencyFinderVisitor(NodeVisitor):
240 """A visitor that collects filter and test calls."""
241
242 def __init__(self):
243 self.filters = set()
244 self.tests = set()
245
246 def visit_Filter(self, node):
247 self.generic_visit(node)
248 self.filters.add(node.name)
249
250 def visit_Test(self, node):
251 self.generic_visit(node)
252 self.tests.add(node.name)
253
254 def visit_Block(self, node):
255 """Stop visiting at blocks."""
256
257
258class UndeclaredNameVisitor(NodeVisitor):
259 """A visitor that checks if a name is accessed without being
260 declared. This is different from the frame visitor as it will
261 not stop at closure frames.
262 """
263
264 def __init__(self, names):
265 self.names = set(names)
266 self.undeclared = set()
267
268 def visit_Name(self, node):
269 if node.ctx == 'load' and node.name in self.names:
270 self.undeclared.add(node.name)
271 if self.undeclared == self.names:
272 raise VisitorExit()
273 else:
274 self.names.discard(node.name)
275
276 def visit_Block(self, node):
277 """Stop visiting a blocks."""
278
279
Armin Ronachere791c2a2008-04-07 18:39:54 +0200280class FrameIdentifierVisitor(NodeVisitor):
281 """A visitor for `Frame.inspect`."""
282
Armin Ronacherda632622011-03-13 14:33:27 -0400283 def __init__(self, identifiers):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200284 self.identifiers = identifiers
285
Armin Ronacherc9705c22008-04-27 21:28:03 +0200286 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200287 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200288 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200289 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200290 elif node.ctx == 'param':
291 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200292 elif node.ctx == 'load' and not \
Armin Ronacherda632622011-03-13 14:33:27 -0400293 self.identifiers.is_declared(node.name):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200294 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200295
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200296 def visit_If(self, node):
297 self.visit(node.test)
Armin Ronacher74230e62009-10-25 12:46:31 +0100298 real_identifiers = self.identifiers
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200299
Armin Ronacher8a672512010-04-05 18:43:07 +0200300 old_names = real_identifiers.declared_locally | \
Armin Ronacher74230e62009-10-25 12:46:31 +0100301 real_identifiers.declared_parameter
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200302
Armin Ronacher74230e62009-10-25 12:46:31 +0100303 def inner_visit(nodes):
Armin Ronacher1965e312009-10-25 13:03:08 +0100304 if not nodes:
305 return set()
Armin Ronacher74230e62009-10-25 12:46:31 +0100306 self.identifiers = real_identifiers.copy()
307 for subnode in nodes:
308 self.visit(subnode)
309 rv = self.identifiers.declared_locally - old_names
310 # we have to remember the undeclared variables of this branch
311 # because we will have to pull them.
312 real_identifiers.undeclared.update(self.identifiers.undeclared)
313 self.identifiers = real_identifiers
314 return rv
315
316 body = inner_visit(node.body)
317 else_ = inner_visit(node.else_ or ())
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200318
319 # the differences between the two branches are also pulled as
320 # undeclared variables
Armin Ronacher8a672512010-04-05 18:43:07 +0200321 real_identifiers.undeclared.update(body.symmetric_difference(else_) -
322 real_identifiers.declared)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200323
Armin Ronacher74230e62009-10-25 12:46:31 +0100324 # remember those that are declared.
325 real_identifiers.declared_locally.update(body | else_)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200326
Armin Ronacherc9705c22008-04-27 21:28:03 +0200327 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200328 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200329
Armin Ronacherc9705c22008-04-27 21:28:03 +0200330 def visit_Import(self, node):
331 self.generic_visit(node)
332 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200333
Armin Ronacherc9705c22008-04-27 21:28:03 +0200334 def visit_FromImport(self, node):
335 self.generic_visit(node)
336 for name in node.names:
337 if isinstance(name, tuple):
338 self.identifiers.declared_locally.add(name[1])
339 else:
340 self.identifiers.declared_locally.add(name)
341
342 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200343 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200344 self.visit(node.node)
345 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200346
Armin Ronacherc9705c22008-04-27 21:28:03 +0200347 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200348 """Visiting stops at for blocks. However the block sequence
349 is visited as part of the outer scope.
350 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200351 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200352
Armin Ronacherc9705c22008-04-27 21:28:03 +0200353 def visit_CallBlock(self, node):
Armin Ronacheref189442010-01-14 01:26:40 +0100354 self.visit(node.call)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200355
356 def visit_FilterBlock(self, node):
357 self.visit(node.filter)
358
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100359 def visit_Scope(self, node):
360 """Stop visiting at scopes."""
361
Armin Ronacherc9705c22008-04-27 21:28:03 +0200362 def visit_Block(self, node):
363 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200364
365
Armin Ronacher75cfb862008-04-11 13:47:22 +0200366class CompilerExit(Exception):
367 """Raised if the compiler encountered a situation where it just
368 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200369 raises such an exception is not further processed.
370 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200371
372
Armin Ronachere791c2a2008-04-07 18:39:54 +0200373class CodeGenerator(NodeVisitor):
374
Armin Ronacher64b08a02010-03-12 03:17:41 +0100375 def __init__(self, environment, name, filename, stream=None,
376 defer_init=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200377 if stream is None:
378 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200379 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200380 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200381 self.filename = filename
382 self.stream = stream
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100383 self.created_block_context = False
Armin Ronacher64b08a02010-03-12 03:17:41 +0100384 self.defer_init = defer_init
Armin Ronacherfed44b52008-04-13 19:42:53 +0200385
Armin Ronacher023b5e92008-05-08 11:03:10 +0200386 # aliases for imports
387 self.import_aliases = {}
388
Armin Ronacherfed44b52008-04-13 19:42:53 +0200389 # a registry for all blocks. Because blocks are moved out
390 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200391 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200392
393 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200394 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200395
396 # some templates have a rootlevel extends. In this case we
397 # can safely assume that we're a child template and do some
398 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200399 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200400
Armin Ronacherba3757b2008-04-16 19:43:16 +0200401 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200402 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200403
Armin Ronacherb9e78752008-05-10 23:36:28 +0200404 # registry of all filters and tests (global, not block local)
405 self.tests = {}
406 self.filters = {}
407
Armin Ronacherba3757b2008-04-16 19:43:16 +0200408 # the debug information
409 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200410 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200411
Armin Ronacherfed44b52008-04-13 19:42:53 +0200412 # the number of new lines before the next write()
413 self._new_lines = 0
414
415 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200416 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200417
418 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200419 self._first_write = True
420
Armin Ronacherfed44b52008-04-13 19:42:53 +0200421 # used by the `temporary_identifier` method to get new
422 # unique, temporary identifier
423 self._last_identifier = 0
424
425 # the current indentation
426 self._indentation = 0
427
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200428 # -- Various compilation helpers
429
Armin Ronachere2244882008-05-19 09:25:57 +0200430 def fail(self, msg, lineno):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100431 """Fail with a :exc:`TemplateAssertionError`."""
Armin Ronachere2244882008-05-19 09:25:57 +0200432 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
433
Armin Ronachere791c2a2008-04-07 18:39:54 +0200434 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200435 """Get a new unique identifier."""
436 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200437 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200438
Armin Ronachered1e0d42008-05-18 20:25:28 +0200439 def buffer(self, frame):
440 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200441 frame.buffer = self.temporary_identifier()
442 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200443
444 def return_buffer_contents(self, frame):
445 """Return the buffer contents of the frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100446 if frame.eval_ctx.volatile:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100447 self.writeline('if context.eval_ctx.autoescape:')
448 self.indent()
449 self.writeline('return Markup(concat(%s))' % frame.buffer)
450 self.outdent()
451 self.writeline('else:')
452 self.indent()
453 self.writeline('return concat(%s)' % frame.buffer)
454 self.outdent()
Armin Ronacher8346bd72010-03-14 19:43:47 +0100455 elif frame.eval_ctx.autoescape:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100456 self.writeline('return Markup(concat(%s))' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200457 else:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100458 self.writeline('return concat(%s)' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200459
Armin Ronachere791c2a2008-04-07 18:39:54 +0200460 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200461 """Indent by one."""
462 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200463
Armin Ronacher8efc5222008-04-08 14:47:40 +0200464 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200465 """Outdent by step."""
466 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200467
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200468 def start_write(self, frame, node=None):
469 """Yield or write into the frame buffer."""
470 if frame.buffer is None:
471 self.writeline('yield ', node)
472 else:
473 self.writeline('%s.append(' % frame.buffer, node)
474
475 def end_write(self, frame):
476 """End the writing process started by `start_write`."""
477 if frame.buffer is not None:
478 self.write(')')
479
480 def simple_write(self, s, frame, node=None):
481 """Simple shortcut for start_write + write + end_write."""
482 self.start_write(frame, node)
483 self.write(s)
484 self.end_write(frame)
485
Armin Ronacherf40c8842008-09-17 18:51:26 +0200486 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200487 """Visit a list of nodes as block in a frame. If the current frame
488 is no buffer a dummy ``if 0: yield None`` is written automatically
489 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200490 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200491 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200492 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200493 else:
494 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200495 try:
496 for node in nodes:
497 self.visit(node, frame)
498 except CompilerExit:
499 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200500
501 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200502 """Write a string into the output stream."""
503 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200504 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200505 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200506 self.code_lineno += self._new_lines
507 if self._write_debug_info is not None:
508 self.debug_info.append((self._write_debug_info,
509 self.code_lineno))
510 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200511 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200512 self.stream.write(' ' * self._indentation)
513 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200514 self.stream.write(x)
515
516 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200517 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200518 self.newline(node, extra)
519 self.write(x)
520
521 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200522 """Add one or more newlines before the next write."""
523 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200524 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200525 self._write_debug_info = node.lineno
526 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200527
Armin Ronacherfd310492008-05-25 00:16:51 +0200528 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200529 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200530 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200531 arguments may not include python keywords otherwise a syntax
532 error could occour. The extra keyword arguments should be given
533 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200534 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200535 # if any of the given keyword arguments is a python keyword
536 # we have to make sure that no invalid call is created.
537 kwarg_workaround = False
538 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200539 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200540 kwarg_workaround = True
541 break
542
Armin Ronacher8efc5222008-04-08 14:47:40 +0200543 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200544 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200545 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200546
547 if not kwarg_workaround:
548 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200549 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200550 self.visit(kwarg, frame)
551 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200552 for key, value in six.iteritems(extra_kwargs):
Armin Ronacherfd310492008-05-25 00:16:51 +0200553 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200554 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200555 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200556 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200557
558 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200559 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200560 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200561 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200562 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200563 for kwarg in node.kwargs:
564 self.write('%r: ' % kwarg.key)
565 self.visit(kwarg.value, frame)
566 self.write(', ')
567 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200568 for key, value in six.iteritems(extra_kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200569 self.write('%r: %s, ' % (key, value))
570 if node.dyn_kwargs is not None:
571 self.write('}, **')
572 self.visit(node.dyn_kwargs, frame)
573 self.write(')')
574 else:
575 self.write('}')
576
577 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200578 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200579 self.visit(node.dyn_kwargs, frame)
580
Armin Ronacherc9705c22008-04-27 21:28:03 +0200581 def pull_locals(self, frame):
582 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200583 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200584 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200585
586 def pull_dependencies(self, nodes):
587 """Pull all the dependencies."""
588 visitor = DependencyFinderVisitor()
589 for node in nodes:
590 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200591 for dependency in 'filters', 'tests':
592 mapping = getattr(self, dependency)
593 for name in getattr(visitor, dependency):
594 if name not in mapping:
595 mapping[name] = self.temporary_identifier()
596 self.writeline('%s = environment.%s[%r]' %
597 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200598
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100599 def unoptimize_scope(self, frame):
600 """Disable Python optimizations for the frame."""
601 # XXX: this is not that nice but it has no real overhead. It
602 # mainly works because python finds the locals before dead code
603 # is removed. If that breaks we have to add a dummy function
604 # that just accepts the arguments and does nothing.
605 if frame.identifiers.declared:
Armin Ronacher821a4232010-02-17 07:59:38 +0100606 self.writeline('%sdummy(%s)' % (
607 unoptimize_before_dead_code and 'if 0: ' or '',
608 ', '.join('l_' + name for name in frame.identifiers.declared)
609 ))
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100610
Armin Ronacher673aa882008-10-04 18:06:57 +0200611 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200612 """This function returns all the shadowed variables in a dict
613 in the form name: alias and will write the required assignments
614 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200615
Armin Ronacher673aa882008-10-04 18:06:57 +0200616 This also predefines locally declared variables from the loop
617 body because under some circumstances it may be the case that
618
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100619 `extra_vars` is passed to `Frame.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200620 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200621 aliases = {}
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100622 for name in frame.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200623 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200624 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200625 to_declare = set()
626 for name in frame.identifiers.declared_locally:
627 if name not in aliases:
628 to_declare.add('l_' + name)
629 if to_declare:
630 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200631 return aliases
632
Armin Ronacher673aa882008-10-04 18:06:57 +0200633 def pop_scope(self, aliases, frame):
634 """Restore all aliases and delete unused variables."""
Thomas Waldmanne0003552013-05-17 23:52:14 +0200635 for name, alias in six.iteritems(aliases):
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200636 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200637 to_delete = set()
638 for name in frame.identifiers.declared_locally:
639 if name not in aliases:
640 to_delete.add('l_' + name)
641 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100642 # we cannot use the del statement here because enclosed
643 # scopes can trigger a SyntaxError:
644 # a = 42; b = lambda: a; del a
645 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200646
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200647 def function_scoping(self, node, frame, children=None,
648 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200649 """In Jinja a few statements require the help of anonymous
650 functions. Those are currently macros and call blocks and in
651 the future also recursive loops. As there is currently
652 technical limitation that doesn't allow reading and writing a
653 variable in a scope where the initial value is coming from an
654 outer scope, this function tries to fall back with a common
655 error message. Additionally the frame passed is modified so
656 that the argumetns are collected and callers are looked up.
657
658 This will return the modified frame.
659 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200660 # we have to iterate twice over it, make sure that works
661 if children is None:
662 children = node.iter_child_nodes()
663 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200664 func_frame = frame.inner()
Armin Ronacherda632622011-03-13 14:33:27 -0400665 func_frame.inspect(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200666
667 # variables that are undeclared (accessed before declaration) and
668 # declared locally *and* part of an outside scope raise a template
669 # assertion error. Reason: we can't generate reasonable code from
Armin Ronacher02b42a82009-03-18 00:59:32 +0100670 # it without aliasing all the variables.
671 # this could be fixed in Python 3 where we have the nonlocal
672 # keyword or if we switch to bytecode generation
Armin Ronacher71082072008-04-12 14:19:36 +0200673 overriden_closure_vars = (
674 func_frame.identifiers.undeclared &
675 func_frame.identifiers.declared &
676 (func_frame.identifiers.declared_locally |
677 func_frame.identifiers.declared_parameter)
678 )
679 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200680 self.fail('It\'s not possible to set and access variables '
Armin Ronacherefcc0e52009-09-13 00:22:50 -0700681 'derived from an outer scope! (affects: %s)' %
Armin Ronachere2244882008-05-19 09:25:57 +0200682 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200683
684 # remove variables from a closure from the frame's undeclared
685 # identifiers.
686 func_frame.identifiers.undeclared -= (
687 func_frame.identifiers.undeclared &
688 func_frame.identifiers.declared
689 )
690
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200691 # no special variables for this scope, abort early
692 if not find_special:
693 return func_frame
694
Armin Ronacher963f97d2008-04-25 11:44:59 +0200695 func_frame.accesses_kwargs = False
696 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200697 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200698 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200699
Armin Ronacherc9705c22008-04-27 21:28:03 +0200700 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
701
702 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200703 func_frame.accesses_caller = True
704 func_frame.identifiers.add_special('caller')
705 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200706 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200707 func_frame.accesses_kwargs = True
708 func_frame.identifiers.add_special('kwargs')
709 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200710 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200711 func_frame.accesses_varargs = True
712 func_frame.identifiers.add_special('varargs')
713 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200714 return func_frame
715
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200716 def macro_body(self, node, frame, children=None):
717 """Dump the function def of a macro or call block."""
718 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100719 # macros are delayed, they never require output checks
720 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200721 args = frame.arguments
Armin Ronachereabf3dd2009-09-12 23:48:18 -0700722 # XXX: this is an ugly fix for the loop nesting bug
723 # (tests.test_old_bugs.test_loop_call_bug). This works around
724 # a identifier nesting problem we have in general. It's just more
725 # likely to happen in loops which is why we work around it. The
726 # real solution would be "nonlocal" all the identifiers that are
727 # leaking into a new python frame and might be used both unassigned
728 # and assigned.
729 if 'loop' in frame.identifiers.declared:
Armin Ronacherb4044392009-09-13 15:56:58 -0700730 args = args + ['l_loop=l_loop']
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200731 self.writeline('def macro(%s):' % ', '.join(args), node)
732 self.indent()
733 self.buffer(frame)
734 self.pull_locals(frame)
735 self.blockvisit(node.body, frame)
736 self.return_buffer_contents(frame)
737 self.outdent()
738 return frame
739
740 def macro_def(self, node, frame):
741 """Dump the macro definition for the def created by macro_body."""
742 arg_tuple = ', '.join(repr(x.name) for x in node.args)
743 name = getattr(node, 'name', None)
744 if len(node.args) == 1:
745 arg_tuple += ','
746 self.write('Macro(environment, macro, %r, (%s), (' %
747 (name, arg_tuple))
748 for arg in node.defaults:
749 self.visit(arg, frame)
750 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200751 self.write('), %r, %r, %r)' % (
752 bool(frame.accesses_kwargs),
753 bool(frame.accesses_varargs),
754 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200755 ))
756
Armin Ronacher547d0b62008-07-04 16:35:10 +0200757 def position(self, node):
758 """Return a human readable position for the node."""
759 rv = 'line %d' % node.lineno
760 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100761 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200762 return rv
763
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200764 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200765
766 def visit_Template(self, node, frame=None):
767 assert frame is None, 'no root frame allowed'
Armin Ronacher1da23d12010-04-05 18:11:18 +0200768 eval_ctx = EvalContext(self.environment, self.name)
Armin Ronacher8346bd72010-03-14 19:43:47 +0100769
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200770 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200771 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200772 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher821a4232010-02-17 07:59:38 +0100773 if not unoptimize_before_dead_code:
774 self.writeline('dummy = lambda *x: None')
Armin Ronacher8edbe492008-04-10 20:43:43 +0200775
Armin Ronacher64b08a02010-03-12 03:17:41 +0100776 # if we want a deferred initialization we cannot move the
777 # environment into a local name
778 envenv = not self.defer_init and ', environment=environment' or ''
779
Armin Ronacher75cfb862008-04-11 13:47:22 +0200780 # do we have an extends tag at all? If not, we can save some
781 # overhead by just not processing any inheritance code.
782 have_extends = node.find(nodes.Extends) is not None
783
Armin Ronacher8edbe492008-04-10 20:43:43 +0200784 # find all blocks
785 for block in node.find_all(nodes.Block):
786 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200787 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200788 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200789
Armin Ronacher023b5e92008-05-08 11:03:10 +0200790 # find all imports and import them
791 for import_ in node.find_all(nodes.ImportedName):
792 if import_.importname not in self.import_aliases:
793 imp = import_.importname
794 self.import_aliases[imp] = alias = self.temporary_identifier()
795 if '.' in imp:
796 module, obj = imp.rsplit('.', 1)
797 self.writeline('from %s import %s as %s' %
798 (module, obj, alias))
799 else:
800 self.writeline('import %s as %s' % (imp, alias))
801
802 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200803 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200804
Armin Ronacher8efc5222008-04-08 14:47:40 +0200805 # generate the root render function.
Armin Ronacher64b08a02010-03-12 03:17:41 +0100806 self.writeline('def root(context%s):' % envenv, extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200807
808 # process the root
Armin Ronacher8346bd72010-03-14 19:43:47 +0100809 frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200810 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200811 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200812 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200813 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200814 if have_extends:
815 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200816 if 'self' in find_undeclared(node.body, ('self',)):
817 frame.identifiers.add_special('self')
818 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200819 self.pull_locals(frame)
820 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200821 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200822 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200823
Armin Ronacher8efc5222008-04-08 14:47:40 +0200824 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200825 if have_extends:
826 if not self.has_known_extends:
827 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200828 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200829 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200830 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200831 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200832 self.indent()
833 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200834 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200835
836 # at this point we now have the blocks collected and can visit them too.
Thomas Waldmanne0003552013-05-17 23:52:14 +0200837 for name, block in six.iteritems(self.blocks):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100838 block_frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200839 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200840 block_frame.block = name
Armin Ronacher64b08a02010-03-12 03:17:41 +0100841 self.writeline('def block_%s(context%s):' % (name, envenv),
842 block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200843 self.indent()
844 undeclared = find_undeclared(block.body, ('self', 'super'))
845 if 'self' in undeclared:
846 block_frame.identifiers.add_special('self')
847 self.writeline('l_self = TemplateReference(context)')
848 if 'super' in undeclared:
849 block_frame.identifiers.add_special('super')
850 self.writeline('l_super = context.super(%r, '
851 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200852 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200853 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200854 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200855 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200856
Armin Ronacher75cfb862008-04-11 13:47:22 +0200857 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200858 for x in self.blocks),
859 extra=1)
860
861 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200862 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
863 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200864
Armin Ronachere791c2a2008-04-07 18:39:54 +0200865 def visit_Block(self, node, frame):
866 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200867 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200868 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200869 # if we know that we are a child template, there is no need to
870 # check if we are one
871 if self.has_known_extends:
872 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200873 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200874 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200875 self.indent()
876 level += 1
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100877 context = node.scoped and 'context.derived(locals())' or 'context'
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100878 self.writeline('for event in context.blocks[%r][0](%s):' % (
879 node.name, context), node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200880 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200881 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200882 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200883
884 def visit_Extends(self, node, frame):
885 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200886 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200887 self.fail('cannot use extend from a non top-level scope',
888 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200889
Armin Ronacher7fb38972008-04-11 13:54:28 +0200890 # if the number of extends statements in general is zero so
891 # far, we don't have to add a check if something extended
892 # the template before this one.
893 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200894
Armin Ronacher7fb38972008-04-11 13:54:28 +0200895 # if we have a known extends we just add a template runtime
896 # error into the generated code. We could catch that at compile
897 # time too, but i welcome it not to confuse users by throwing the
898 # same error at different times just "because we can".
899 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200900 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200901 self.indent()
902 self.writeline('raise TemplateRuntimeError(%r)' %
903 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200904 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200905
Armin Ronacher7fb38972008-04-11 13:54:28 +0200906 # if we have a known extends already we don't need that code here
907 # as we know that the template execution will end here.
908 if self.has_known_extends:
909 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200910
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200911 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200912 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200913 self.write(', %r)' % self.name)
914 self.writeline('for name, parent_block in parent_template.'
Armin Ronacher0d242be2010-02-10 01:35:13 +0100915 'blocks.%s():' % dict_item_iter)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200916 self.indent()
917 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200918 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200919 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200920
921 # if this extends statement was in the root level we can take
922 # advantage of that information and simplify the generated code
923 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200924 if frame.rootlevel:
925 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200926
Armin Ronacher7fb38972008-04-11 13:54:28 +0200927 # and now we have one more
928 self.extends_so_far += 1
929
Armin Ronacherf059ec12008-04-11 22:21:00 +0200930 def visit_Include(self, node, frame):
931 """Handles includes."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100932 if node.with_context:
933 self.unoptimize_scope(frame)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100934 if node.ignore_missing:
935 self.writeline('try:')
936 self.indent()
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100937
938 func_name = 'get_or_select_template'
939 if isinstance(node.template, nodes.Const):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200940 if isinstance(node.template.value, six.string_types):
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100941 func_name = 'get_template'
942 elif isinstance(node.template.value, (tuple, list)):
943 func_name = 'select_template'
944 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
945 func_name = 'select_template'
946
947 self.writeline('template = environment.%s(' % func_name, node)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100948 self.visit(node.template, frame)
949 self.write(', %r)' % self.name)
950 if node.ignore_missing:
951 self.outdent()
952 self.writeline('except TemplateNotFound:')
953 self.indent()
954 self.writeline('pass')
955 self.outdent()
956 self.writeline('else:')
957 self.indent()
958
Armin Ronacherea847c52008-05-02 20:04:32 +0200959 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200960 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200961 'template.new_context(context.parent, True, '
962 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200963 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100964 self.writeline('for event in template.module._body_stream:')
965
Armin Ronacherf059ec12008-04-11 22:21:00 +0200966 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200967 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200968 self.outdent()
969
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100970 if node.ignore_missing:
971 self.outdent()
972
Armin Ronacher0611e492008-04-25 23:44:14 +0200973 def visit_Import(self, node, frame):
974 """Visit regular imports."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100975 if node.with_context:
976 self.unoptimize_scope(frame)
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200977 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200978 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200979 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200980 self.write('environment.get_template(')
981 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200982 self.write(', %r).' % self.name)
983 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200984 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200985 else:
986 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200987 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200988 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100989 frame.assigned_names.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200990
991 def visit_FromImport(self, node, frame):
992 """Visit named imports."""
993 self.newline(node)
994 self.write('included_template = environment.get_template(')
995 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200996 self.write(', %r).' % self.name)
997 if node.with_context:
998 self.write('make_module(context.parent, True)')
999 else:
1000 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +02001001
1002 var_names = []
1003 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +02001004 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +02001005 if isinstance(name, tuple):
1006 name, alias = name
1007 else:
1008 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001009 self.writeline('l_%s = getattr(included_template, '
1010 '%r, missing)' % (alias, name))
1011 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +02001012 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001013 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +02001014 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +02001015 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001016 (alias, 'the template %%r (imported on %s) does '
1017 'not export the requested name %s' % (
1018 self.position(node),
1019 repr(name)
1020 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +02001021 self.outdent()
1022 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +02001023 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +02001024 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +02001025 discarded_names.append(alias)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001026 frame.assigned_names.add(alias)
Armin Ronachera78d2762008-05-15 23:18:07 +02001027
1028 if var_names:
1029 if len(var_names) == 1:
1030 name = var_names[0]
1031 self.writeline('context.vars[%r] = l_%s' % (name, name))
1032 else:
1033 self.writeline('context.vars.update({%s})' % ', '.join(
1034 '%r: l_%s' % (name, name) for name in var_names
1035 ))
1036 if discarded_names:
1037 if len(discarded_names) == 1:
1038 self.writeline('context.exported_vars.discard(%r)' %
1039 discarded_names[0])
1040 else:
1041 self.writeline('context.exported_vars.difference_'
1042 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +02001043
Armin Ronachere791c2a2008-04-07 18:39:54 +02001044 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001045 # when calculating the nodes for the inner frame we have to exclude
1046 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001047 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001048 if node.recursive:
1049 loop_frame = self.function_scoping(node, frame, children,
1050 find_special=False)
1051 else:
1052 loop_frame = frame.inner()
1053 loop_frame.inspect(children)
1054
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001055 # try to figure out if we have an extended loop. An extended loop
1056 # is necessary if the loop is in recursive mode if the special loop
1057 # variable is accessed in the body.
1058 extended_loop = node.recursive or 'loop' in \
1059 find_undeclared(node.iter_child_nodes(
1060 only=('body',)), ('loop',))
1061
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001062 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +02001063 # variables at that point. Because loops can be nested but the loop
1064 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001065 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +02001066 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001067
1068 # otherwise we set up a buffer and add a function def
1069 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001070 self.writeline('def loop(reciter, loop_render_func):', node)
1071 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +02001072 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001073 aliases = {}
1074
Armin Ronacherff53c782008-08-13 18:55:50 +02001075 # make sure the loop variable is a special one and raise a template
1076 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +02001077 if extended_loop:
1078 loop_frame.identifiers.add_special('loop')
Armin Ronacherff53c782008-08-13 18:55:50 +02001079 for name in node.find_all(nodes.Name):
1080 if name.ctx == 'store' and name.name == 'loop':
1081 self.fail('Can\'t assign to special loop variable '
1082 'in for-loop target', name.lineno)
1083
Armin Ronacherc9705c22008-04-27 21:28:03 +02001084 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001085 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001086 iteration_indicator = self.temporary_identifier()
1087 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001088
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001089 # Create a fake parent loop if the else or test section of a
1090 # loop is accessing the special loop variable and no parent loop
1091 # exists.
1092 if 'loop' not in aliases and 'loop' in find_undeclared(
1093 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1094 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001095 ("'loop' is undefined. the filter section of a loop as well "
Armin Ronacherbc56cd22011-01-15 18:35:45 +01001096 "as the else block don't have access to the special 'loop'"
Armin Ronacher547d0b62008-07-04 16:35:10 +02001097 " variable of the current loop. Because there is no parent "
1098 "loop it's undefined. Happened in loop on %s" %
1099 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001100
1101 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001102 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +02001103 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001104
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001105 # if we have an extened loop and a node test, we filter in the
1106 # "outer frame".
1107 if extended_loop and node.test is not None:
1108 self.write('(')
1109 self.visit(node.target, loop_frame)
1110 self.write(' for ')
1111 self.visit(node.target, loop_frame)
1112 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001113 if node.recursive:
1114 self.write('reciter')
1115 else:
1116 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001117 self.write(' if (')
1118 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001119 self.visit(node.test, test_frame)
1120 self.write('))')
1121
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001122 elif node.recursive:
1123 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001124 else:
1125 self.visit(node.iter, loop_frame)
1126
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001127 if node.recursive:
1128 self.write(', recurse=loop_render_func):')
1129 else:
1130 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001131
1132 # tests in not extended loops become a continue
1133 if not extended_loop and node.test is not None:
1134 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +02001135 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +02001136 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001137 self.write(':')
1138 self.indent()
1139 self.writeline('continue')
1140 self.outdent(2)
1141
Armin Ronacherc9705c22008-04-27 21:28:03 +02001142 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001143 self.blockvisit(node.body, loop_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001144 if node.else_:
1145 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001146 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001147
1148 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001149 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001150 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001151 self.blockvisit(node.else_, loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001152 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001153
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001154 # reset the aliases if there are any.
Armin Ronachercebd8382008-12-25 18:33:46 +01001155 if not node.recursive:
1156 self.pop_scope(aliases, loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001157
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001158 # if the node was recursive we have to return the buffer contents
1159 # and start the iteration code
1160 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001161 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001162 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001163 self.start_write(frame, node)
1164 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001165 self.visit(node.iter, frame)
1166 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001167 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001168
Armin Ronachere791c2a2008-04-07 18:39:54 +02001169 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001170 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001171 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001172 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001173 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001174 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001175 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001176 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001177 if node.else_:
1178 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001179 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001180 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001181 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001182
Armin Ronacher8efc5222008-04-08 14:47:40 +02001183 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001184 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001185 self.newline()
1186 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001187 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001188 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001189 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001190 self.write('l_%s = ' % node.name)
1191 self.macro_def(node, macro_frame)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001192 frame.assigned_names.add(node.name)
Armin Ronacher71082072008-04-12 14:19:36 +02001193
1194 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001195 children = node.iter_child_nodes(exclude=('call',))
1196 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001197 self.writeline('caller = ')
1198 self.macro_def(node, call_frame)
1199 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001200 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001201 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001202
1203 def visit_FilterBlock(self, node, frame):
1204 filter_frame = frame.inner()
1205 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacher673aa882008-10-04 18:06:57 +02001206 aliases = self.push_scope(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001207 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001208 self.buffer(filter_frame)
Armin Ronacherf40c8842008-09-17 18:51:26 +02001209 self.blockvisit(node.body, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001210 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001211 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001212 self.end_write(frame)
Armin Ronacher673aa882008-10-04 18:06:57 +02001213 self.pop_scope(aliases, filter_frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001214
Armin Ronachere791c2a2008-04-07 18:39:54 +02001215 def visit_ExprStmt(self, node, frame):
1216 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001217 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001218
1219 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001220 # if we have a known extends statement, we don't output anything
Armin Ronacher79668952008-09-23 22:52:46 +02001221 # if we are in a require_output_check section
1222 if self.has_known_extends and frame.require_output_check:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001223 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001224
Armin Ronacher665bfb82008-07-14 13:41:46 +02001225 if self.environment.finalize:
Thomas Waldmanne0003552013-05-17 23:52:14 +02001226 finalize = lambda x: six.text_type(self.environment.finalize(x))
Armin Ronacher665bfb82008-07-14 13:41:46 +02001227 else:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001228 finalize = six.text_type
Armin Ronacher665bfb82008-07-14 13:41:46 +02001229
Armin Ronacher79668952008-09-23 22:52:46 +02001230 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001231 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001232 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001233 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001234 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001235 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001236
Armin Ronachere791c2a2008-04-07 18:39:54 +02001237 # try to evaluate as many chunks as possible into a static
1238 # string at compile time.
1239 body = []
1240 for child in node.nodes:
1241 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001242 const = child.as_const(frame.eval_ctx)
Armin Ronacher9cf95912008-05-24 19:54:43 +02001243 except nodes.Impossible:
1244 body.append(child)
1245 continue
Armin Ronacher8346bd72010-03-14 19:43:47 +01001246 # the frame can't be volatile here, becaus otherwise the
1247 # as_const() function would raise an Impossible exception
1248 # at that point.
Armin Ronacher9cf95912008-05-24 19:54:43 +02001249 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001250 if frame.eval_ctx.autoescape:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001251 if hasattr(const, '__html__'):
1252 const = const.__html__()
1253 else:
1254 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001255 const = finalize(const)
Ian Lewisab014bd2010-10-31 20:29:28 +09001256 except Exception:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001257 # if something goes wrong here we evaluate the node
1258 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001259 body.append(child)
1260 continue
1261 if body and isinstance(body[-1], list):
1262 body[-1].append(const)
1263 else:
1264 body.append([const])
1265
Armin Ronachered1e0d42008-05-18 20:25:28 +02001266 # if we have less than 3 nodes or a buffer we yield or extend/append
1267 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001268 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001269 # for one item we append, for more we extend
1270 if len(body) == 1:
1271 self.writeline('%s.append(' % frame.buffer)
1272 else:
1273 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001274 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001275 for item in body:
1276 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001277 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001278 if frame.buffer is None:
1279 self.writeline('yield ' + val)
1280 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001281 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001282 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001283 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001284 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001285 else:
1286 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001287 close = 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001288 if frame.eval_ctx.volatile:
1289 self.write('(context.eval_ctx.autoescape and'
1290 ' escape or to_string)(')
1291 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001292 self.write('escape(')
1293 else:
Armin Ronacherbd357722009-08-05 20:25:06 +02001294 self.write('to_string(')
Armin Ronacherd1342312008-04-28 12:20:12 +02001295 if self.environment.finalize is not None:
1296 self.write('environment.finalize(')
1297 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001298 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001299 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001300 if frame.buffer is not None:
1301 self.write(', ')
1302 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001303 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001304 self.outdent()
1305 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001306
1307 # otherwise we create a format string as this is faster in that case
1308 else:
1309 format = []
1310 arguments = []
1311 for item in body:
1312 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001313 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001314 else:
1315 format.append('%s')
1316 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001317 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001318 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001319 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001320 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001321 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001322 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001323 close = 0
Armin Ronacher8346bd72010-03-14 19:43:47 +01001324 if frame.eval_ctx.volatile:
1325 self.write('(context.eval_ctx.autoescape and'
1326 ' escape or to_string)(')
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001327 close += 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001328 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001329 self.write('escape(')
1330 close += 1
1331 if self.environment.finalize is not None:
1332 self.write('environment.finalize(')
1333 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001334 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001335 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001336 self.outdent()
1337 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001338
Armin Ronacher7fb38972008-04-11 13:54:28 +02001339 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001340 self.outdent()
1341
Armin Ronacher8efc5222008-04-08 14:47:40 +02001342 def visit_Assign(self, node, frame):
1343 self.newline(node)
1344 # toplevel assignments however go into the local namespace and
1345 # the current template's context. We create a copy of the frame
1346 # here and add a set so that the Name visitor can add the assigned
1347 # names here.
1348 if frame.toplevel:
1349 assignment_frame = frame.copy()
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001350 assignment_frame.toplevel_assignments = set()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001351 else:
1352 assignment_frame = frame
1353 self.visit(node.target, assignment_frame)
1354 self.write(' = ')
1355 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001356
1357 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001358 if frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001359 public_names = [x for x in assignment_frame.toplevel_assignments
Armin Ronacher903d1682008-05-23 00:51:58 +02001360 if not x.startswith('_')]
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001361 if len(assignment_frame.toplevel_assignments) == 1:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001362 name = six.advance_iterator(iter(assignment_frame.toplevel_assignments))
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001363 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001364 else:
1365 self.writeline('context.vars.update({')
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001366 for idx, name in enumerate(assignment_frame.toplevel_assignments):
Armin Ronacher69e12db2008-05-12 09:00:03 +02001367 if idx:
1368 self.write(', ')
1369 self.write('%r: l_%s' % (name, name))
1370 self.write('})')
1371 if public_names:
1372 if len(public_names) == 1:
1373 self.writeline('context.exported_vars.add(%r)' %
1374 public_names[0])
1375 else:
1376 self.writeline('context.exported_vars.update((%s))' %
1377 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001378
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001379 # -- Expression Visitors
1380
Armin Ronachere791c2a2008-04-07 18:39:54 +02001381 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001382 if node.ctx == 'store' and frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001383 frame.toplevel_assignments.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001384 self.write('l_' + node.name)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001385 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001386
1387 def visit_Const(self, node, frame):
1388 val = node.value
1389 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001390 self.write(str(val))
1391 else:
1392 self.write(repr(val))
1393
Armin Ronacher5411ce72008-05-25 11:36:22 +02001394 def visit_TemplateData(self, node, frame):
Armin Ronacherffaa2e72010-05-29 20:57:16 +02001395 try:
1396 self.write(repr(node.as_const(frame.eval_ctx)))
1397 except nodes.Impossible:
1398 self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)'
1399 % node.data)
Armin Ronacher5411ce72008-05-25 11:36:22 +02001400
Armin Ronacher8efc5222008-04-08 14:47:40 +02001401 def visit_Tuple(self, node, frame):
1402 self.write('(')
1403 idx = -1
1404 for idx, item in enumerate(node.items):
1405 if idx:
1406 self.write(', ')
1407 self.visit(item, frame)
1408 self.write(idx == 0 and ',)' or ')')
1409
Armin Ronacher8edbe492008-04-10 20:43:43 +02001410 def visit_List(self, node, frame):
1411 self.write('[')
1412 for idx, item in enumerate(node.items):
1413 if idx:
1414 self.write(', ')
1415 self.visit(item, frame)
1416 self.write(']')
1417
1418 def visit_Dict(self, node, frame):
1419 self.write('{')
1420 for idx, item in enumerate(node.items):
1421 if idx:
1422 self.write(', ')
1423 self.visit(item.key, frame)
1424 self.write(': ')
1425 self.visit(item.value, frame)
1426 self.write('}')
1427
Armin Ronachera9195382010-11-29 13:21:57 +01001428 def binop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001429 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001430 if self.environment.sandboxed and \
1431 operator in self.environment.intercepted_binops:
1432 self.write('environment.call_binop(context, %r, ' % operator)
1433 self.visit(node.left, frame)
1434 self.write(', ')
1435 self.visit(node.right, frame)
1436 else:
1437 self.write('(')
1438 self.visit(node.left, frame)
1439 self.write(' %s ' % operator)
1440 self.visit(node.right, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001441 self.write(')')
1442 return visitor
1443
Armin Ronachera9195382010-11-29 13:21:57 +01001444 def uaop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001445 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001446 if self.environment.sandboxed and \
1447 operator in self.environment.intercepted_unops:
1448 self.write('environment.call_unop(context, %r, ' % operator)
1449 self.visit(node.node, frame)
1450 else:
1451 self.write('(' + operator)
1452 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001453 self.write(')')
1454 return visitor
1455
1456 visit_Add = binop('+')
1457 visit_Sub = binop('-')
1458 visit_Mul = binop('*')
1459 visit_Div = binop('/')
1460 visit_FloorDiv = binop('//')
1461 visit_Pow = binop('**')
1462 visit_Mod = binop('%')
Armin Ronachera9195382010-11-29 13:21:57 +01001463 visit_And = binop('and', interceptable=False)
1464 visit_Or = binop('or', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001465 visit_Pos = uaop('+')
1466 visit_Neg = uaop('-')
Armin Ronachera9195382010-11-29 13:21:57 +01001467 visit_Not = uaop('not ', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001468 del binop, uaop
1469
Armin Ronacherd1342312008-04-28 12:20:12 +02001470 def visit_Concat(self, node, frame):
Armin Ronacher8346bd72010-03-14 19:43:47 +01001471 if frame.eval_ctx.volatile:
1472 func_name = '(context.eval_ctx.volatile and' \
1473 ' markup_join or unicode_join)'
1474 elif frame.eval_ctx.autoescape:
1475 func_name = 'markup_join'
1476 else:
1477 func_name = 'unicode_join'
1478 self.write('%s((' % func_name)
Armin Ronacherd1342312008-04-28 12:20:12 +02001479 for arg in node.nodes:
1480 self.visit(arg, frame)
1481 self.write(', ')
1482 self.write('))')
1483
Armin Ronachere791c2a2008-04-07 18:39:54 +02001484 def visit_Compare(self, node, frame):
1485 self.visit(node.expr, frame)
1486 for op in node.ops:
1487 self.visit(op, frame)
1488
1489 def visit_Operand(self, node, frame):
1490 self.write(' %s ' % operators[node.op])
1491 self.visit(node.expr, frame)
1492
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001493 def visit_Getattr(self, node, frame):
1494 self.write('environment.getattr(')
1495 self.visit(node.node, frame)
1496 self.write(', %r)' % node.attr)
1497
1498 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001499 # slices bypass the environment getitem method.
1500 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001501 self.visit(node.node, frame)
1502 self.write('[')
1503 self.visit(node.arg, frame)
1504 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001505 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001506 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001507 self.visit(node.node, frame)
1508 self.write(', ')
1509 self.visit(node.arg, frame)
1510 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001511
1512 def visit_Slice(self, node, frame):
1513 if node.start is not None:
1514 self.visit(node.start, frame)
1515 self.write(':')
1516 if node.stop is not None:
1517 self.visit(node.stop, frame)
1518 if node.step is not None:
1519 self.write(':')
1520 self.visit(node.step, frame)
1521
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001522 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001523 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001524 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001525 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001526 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001527 if getattr(func, 'contextfilter', False):
1528 self.write('context, ')
Armin Ronacher8346bd72010-03-14 19:43:47 +01001529 elif getattr(func, 'evalcontextfilter', False):
1530 self.write('context.eval_ctx, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001531 elif getattr(func, 'environmentfilter', False):
1532 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001533
1534 # if the filter node is None we are inside a filter block
1535 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001536 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001537 self.visit(node.node, frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001538 elif frame.eval_ctx.volatile:
1539 self.write('(context.eval_ctx.autoescape and'
1540 ' Markup(concat(%s)) or concat(%s))' %
1541 (frame.buffer, frame.buffer))
1542 elif frame.eval_ctx.autoescape:
Armin Ronacher3da90312008-05-23 16:37:28 +02001543 self.write('Markup(concat(%s))' % frame.buffer)
1544 else:
1545 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001546 self.signature(node, frame)
1547 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001548
1549 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001550 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001551 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001552 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001553 self.visit(node.node, frame)
1554 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001555 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001556
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001557 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001558 def write_expr2():
1559 if node.expr2 is not None:
1560 return self.visit(node.expr2, frame)
1561 self.write('environment.undefined(%r)' % ('the inline if-'
1562 'expression on %s evaluated to false and '
1563 'no else section was defined.' % self.position(node)))
1564
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001565 if not have_condexpr:
1566 self.write('((')
1567 self.visit(node.test, frame)
1568 self.write(') and (')
1569 self.visit(node.expr1, frame)
1570 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001571 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001572 self.write(',))[0]')
1573 else:
1574 self.write('(')
1575 self.visit(node.expr1, frame)
1576 self.write(' if ')
1577 self.visit(node.test, frame)
1578 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001579 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001580 self.write(')')
1581
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001582 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001583 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001584 self.write('environment.call(context, ')
1585 else:
1586 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001587 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001588 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001589 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001590 self.write(')')
1591
1592 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001593 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001594 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001595
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001596 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001597
1598 def visit_MarkSafe(self, node, frame):
1599 self.write('Markup(')
1600 self.visit(node.expr, frame)
1601 self.write(')')
1602
Armin Ronacher4da90342010-05-29 17:35:10 +02001603 def visit_MarkSafeIfAutoescape(self, node, frame):
1604 self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1605 self.visit(node.expr, frame)
1606 self.write(')')
1607
Armin Ronachered1e0d42008-05-18 20:25:28 +02001608 def visit_EnvironmentAttribute(self, node, frame):
1609 self.write('environment.' + node.name)
1610
1611 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001612 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001613
1614 def visit_ImportedName(self, node, frame):
1615 self.write(self.import_aliases[node.importname])
1616
1617 def visit_InternalName(self, node, frame):
1618 self.write(node.name)
1619
Armin Ronacher6df604e2008-05-23 22:18:38 +02001620 def visit_ContextReference(self, node, frame):
1621 self.write('context')
1622
Armin Ronachered1e0d42008-05-18 20:25:28 +02001623 def visit_Continue(self, node, frame):
1624 self.writeline('continue', node)
1625
1626 def visit_Break(self, node, frame):
1627 self.writeline('break', node)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001628
1629 def visit_Scope(self, node, frame):
1630 scope_frame = frame.inner()
1631 scope_frame.inspect(node.iter_child_nodes())
1632 aliases = self.push_scope(scope_frame)
1633 self.pull_locals(scope_frame)
1634 self.blockvisit(node.body, scope_frame)
1635 self.pop_scope(aliases, scope_frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001636
1637 def visit_EvalContextModifier(self, node, frame):
1638 for keyword in node.options:
1639 self.writeline('context.eval_ctx.%s = ' % keyword.key)
1640 self.visit(keyword.value, frame)
1641 try:
1642 val = keyword.value.as_const(frame.eval_ctx)
1643 except nodes.Impossible:
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001644 frame.eval_ctx.volatile = True
Armin Ronacher8346bd72010-03-14 19:43:47 +01001645 else:
1646 setattr(frame.eval_ctx, keyword.key, val)
1647
1648 def visit_ScopedEvalContextModifier(self, node, frame):
1649 old_ctx_name = self.temporary_identifier()
1650 safed_ctx = frame.eval_ctx.save()
1651 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1652 self.visit_EvalContextModifier(node, frame)
1653 for child in node.body:
1654 self.visit(child, frame)
1655 frame.eval_ctx.revert(safed_ctx)
1656 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)