blob: c3d84d1089030693f4ffd396287e5f12276f30b6 [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
22
23operators = {
24 'eq': '==',
25 'ne': '!=',
26 'gt': '>',
27 'gteq': '>=',
28 'lt': '<',
29 'lteq': '<=',
30 'in': 'in',
31 'notin': 'not in'
32}
33
Armin Ronacher3d8b7842008-04-13 13:16:50 +020034try:
Thomas Waldmanne0003552013-05-17 23:52:14 +020035 exec('(0 if 0 else 0)')
Armin Ronacher3d8b7842008-04-13 13:16:50 +020036except SyntaxError:
37 have_condexpr = False
38else:
39 have_condexpr = True
40
41
Armin Ronacher0d242be2010-02-10 01:35:13 +010042# what method to iterate over items do we want to use for dict iteration
43# in generated code? on 2.x let's go with iteritems, on 3.x with items
44if hasattr(dict, 'iteritems'):
45 dict_item_iter = 'iteritems'
46else:
47 dict_item_iter = 'items'
48
49
Armin Ronacher821a4232010-02-17 07:59:38 +010050# does if 0: dummy(x) get us x into the scope?
51def unoptimize_before_dead_code():
52 x = 42
53 def f():
54 if 0: dummy(x)
55 return f
Armin Ronacher9dd7fad2013-05-18 11:36:32 +010056
57# The getattr is necessary for pypy which does not set this attribute if
58# no closure is on the function
59unoptimize_before_dead_code = bool(
60 getattr(unoptimize_before_dead_code(), '__closure__', None))
Armin Ronacher821a4232010-02-17 07:59:38 +010061
62
Armin Ronacher64b08a02010-03-12 03:17:41 +010063def generate(node, environment, name, filename, stream=None,
64 defer_init=False):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020065 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020066 if not isinstance(node, nodes.Template):
67 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher64b08a02010-03-12 03:17:41 +010068 generator = CodeGenerator(environment, name, filename, stream, defer_init)
Armin Ronachere791c2a2008-04-07 18:39:54 +020069 generator.visit(node)
70 if stream is None:
71 return generator.stream.getvalue()
72
73
Armin Ronacher4dfc9752008-04-09 15:03:29 +020074def has_safe_repr(value):
75 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020076 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020077 return True
Thomas Waldmann7d295622013-05-18 00:06:22 +020078 try:
79 range_type = xrange
80 except NameError:
81 range_type = range
82 if isinstance(value, (bool, int, float, complex, range_type, Markup) + six.string_types):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020083 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020084 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020085 for item in value:
86 if not has_safe_repr(item):
87 return False
88 return True
89 elif isinstance(value, dict):
Thomas Waldmanne0003552013-05-17 23:52:14 +020090 for key, value in six.iteritems(value):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020091 if not has_safe_repr(key):
92 return False
93 if not has_safe_repr(value):
94 return False
95 return True
96 return False
97
98
Armin Ronacherc9705c22008-04-27 21:28:03 +020099def find_undeclared(nodes, names):
100 """Check if the names passed are accessed undeclared. The return value
101 is a set of all the undeclared names from the sequence of names found.
102 """
103 visitor = UndeclaredNameVisitor(names)
104 try:
105 for node in nodes:
106 visitor.visit(node)
107 except VisitorExit:
108 pass
109 return visitor.undeclared
110
111
Armin Ronachere791c2a2008-04-07 18:39:54 +0200112class Identifiers(object):
113 """Tracks the status of identifiers in frames."""
114
115 def __init__(self):
116 # variables that are known to be declared (probably from outer
117 # frames or because they are special for the frame)
118 self.declared = set()
119
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200120 # undeclared variables from outer scopes
121 self.outer_undeclared = set()
122
Armin Ronachere791c2a2008-04-07 18:39:54 +0200123 # names that are accessed without being explicitly declared by
124 # this one or any of the outer scopes. Names can appear both in
125 # declared and undeclared.
126 self.undeclared = set()
127
128 # names that are declared locally
129 self.declared_locally = set()
130
131 # names that are declared by parameters
132 self.declared_parameter = set()
133
134 def add_special(self, name):
135 """Register a special name like `loop`."""
136 self.undeclared.discard(name)
137 self.declared.add(name)
138
Armin Ronacherda632622011-03-13 14:33:27 -0400139 def is_declared(self, name):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200140 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200141 if name in self.declared_locally or name in self.declared_parameter:
142 return True
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200143 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200144
Armin Ronacher74230e62009-10-25 12:46:31 +0100145 def copy(self):
146 return deepcopy(self)
147
Armin Ronachere791c2a2008-04-07 18:39:54 +0200148
149class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200150 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200151
Armin Ronacher8346bd72010-03-14 19:43:47 +0100152 def __init__(self, eval_ctx, parent=None):
153 self.eval_ctx = eval_ctx
Armin Ronachere791c2a2008-04-07 18:39:54 +0200154 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200155
Armin Ronacher75cfb862008-04-11 13:47:22 +0200156 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200157 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200158
Armin Ronacher75cfb862008-04-11 13:47:22 +0200159 # the root frame is basically just the outermost frame, so no if
160 # conditions. This information is used to optimize inheritance
161 # situations.
162 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200163
Armin Ronacher79668952008-09-23 22:52:46 +0200164 # in some dynamic inheritance situations the compiler needs to add
165 # write tests around output statements.
166 self.require_output_check = parent and parent.require_output_check
Armin Ronacherf40c8842008-09-17 18:51:26 +0200167
Armin Ronacherfed44b52008-04-13 19:42:53 +0200168 # inside some tags we are using a buffer rather than yield statements.
169 # this for example affects {% filter %} or {% macro %}. If a frame
170 # is buffered this variable points to the name of the list used as
171 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200172 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200173
Armin Ronacherfed44b52008-04-13 19:42:53 +0200174 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200175 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200176
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100177 # a set of actually assigned names
178 self.assigned_names = set()
179
Armin Ronacherfed44b52008-04-13 19:42:53 +0200180 # the parent of this frame
181 self.parent = parent
182
Armin Ronachere791c2a2008-04-07 18:39:54 +0200183 if parent is not None:
184 self.identifiers.declared.update(
185 parent.identifiers.declared |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200186 parent.identifiers.declared_parameter |
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100187 parent.assigned_names
Armin Ronachere791c2a2008-04-07 18:39:54 +0200188 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200189 self.identifiers.outer_undeclared.update(
190 parent.identifiers.undeclared -
191 self.identifiers.declared
192 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200193 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200194
Armin Ronacher8efc5222008-04-08 14:47:40 +0200195 def copy(self):
196 """Create a copy of the current one."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200197 rv = object.__new__(self.__class__)
198 rv.__dict__.update(self.__dict__)
199 rv.identifiers = object.__new__(self.identifiers.__class__)
200 rv.identifiers.__dict__.update(self.identifiers.__dict__)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200201 return rv
202
Armin Ronacherda632622011-03-13 14:33:27 -0400203 def inspect(self, nodes):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200204 """Walk the node and check for identifiers. If the scope is hard (eg:
205 enforce on a python level) overrides from outer scopes are tracked
206 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200207 """
Armin Ronacherda632622011-03-13 14:33:27 -0400208 visitor = FrameIdentifierVisitor(self.identifiers)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200209 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200210 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200211
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100212 def find_shadowed(self, extra=()):
213 """Find all the shadowed names. extra is an iterable of variables
214 that may be defined with `add_special` which may occour scoped.
215 """
216 i = self.identifiers
217 return (i.declared | i.outer_undeclared) & \
218 (i.declared_locally | i.declared_parameter) | \
219 set(x for x in extra if i.is_declared(x))
220
Armin Ronachere791c2a2008-04-07 18:39:54 +0200221 def inner(self):
222 """Return an inner frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100223 return Frame(self.eval_ctx, self)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200224
Armin Ronacher75cfb862008-04-11 13:47:22 +0200225 def soft(self):
226 """Return a soft frame. A soft frame may not be modified as
227 standalone thing as it shares the resources with the frame it
228 was created of, but it's not a rootlevel frame any longer.
229 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200230 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200231 rv.rootlevel = False
232 return rv
233
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200234 __copy__ = copy
235
Armin Ronachere791c2a2008-04-07 18:39:54 +0200236
Armin Ronacherc9705c22008-04-27 21:28:03 +0200237class VisitorExit(RuntimeError):
238 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
239
240
241class DependencyFinderVisitor(NodeVisitor):
242 """A visitor that collects filter and test calls."""
243
244 def __init__(self):
245 self.filters = set()
246 self.tests = set()
247
248 def visit_Filter(self, node):
249 self.generic_visit(node)
250 self.filters.add(node.name)
251
252 def visit_Test(self, node):
253 self.generic_visit(node)
254 self.tests.add(node.name)
255
256 def visit_Block(self, node):
257 """Stop visiting at blocks."""
258
259
260class UndeclaredNameVisitor(NodeVisitor):
261 """A visitor that checks if a name is accessed without being
262 declared. This is different from the frame visitor as it will
263 not stop at closure frames.
264 """
265
266 def __init__(self, names):
267 self.names = set(names)
268 self.undeclared = set()
269
270 def visit_Name(self, node):
271 if node.ctx == 'load' and node.name in self.names:
272 self.undeclared.add(node.name)
273 if self.undeclared == self.names:
274 raise VisitorExit()
275 else:
276 self.names.discard(node.name)
277
278 def visit_Block(self, node):
279 """Stop visiting a blocks."""
280
281
Armin Ronachere791c2a2008-04-07 18:39:54 +0200282class FrameIdentifierVisitor(NodeVisitor):
283 """A visitor for `Frame.inspect`."""
284
Armin Ronacherda632622011-03-13 14:33:27 -0400285 def __init__(self, identifiers):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200286 self.identifiers = identifiers
287
Armin Ronacherc9705c22008-04-27 21:28:03 +0200288 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200289 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200290 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200291 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200292 elif node.ctx == 'param':
293 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200294 elif node.ctx == 'load' and not \
Armin Ronacherda632622011-03-13 14:33:27 -0400295 self.identifiers.is_declared(node.name):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200296 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200297
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200298 def visit_If(self, node):
299 self.visit(node.test)
Armin Ronacher74230e62009-10-25 12:46:31 +0100300 real_identifiers = self.identifiers
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200301
Armin Ronacher8a672512010-04-05 18:43:07 +0200302 old_names = real_identifiers.declared_locally | \
Armin Ronacher74230e62009-10-25 12:46:31 +0100303 real_identifiers.declared_parameter
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200304
Armin Ronacher74230e62009-10-25 12:46:31 +0100305 def inner_visit(nodes):
Armin Ronacher1965e312009-10-25 13:03:08 +0100306 if not nodes:
307 return set()
Armin Ronacher74230e62009-10-25 12:46:31 +0100308 self.identifiers = real_identifiers.copy()
309 for subnode in nodes:
310 self.visit(subnode)
311 rv = self.identifiers.declared_locally - old_names
312 # we have to remember the undeclared variables of this branch
313 # because we will have to pull them.
314 real_identifiers.undeclared.update(self.identifiers.undeclared)
315 self.identifiers = real_identifiers
316 return rv
317
318 body = inner_visit(node.body)
319 else_ = inner_visit(node.else_ or ())
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200320
321 # the differences between the two branches are also pulled as
322 # undeclared variables
Armin Ronacher8a672512010-04-05 18:43:07 +0200323 real_identifiers.undeclared.update(body.symmetric_difference(else_) -
324 real_identifiers.declared)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200325
Armin Ronacher74230e62009-10-25 12:46:31 +0100326 # remember those that are declared.
327 real_identifiers.declared_locally.update(body | else_)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200328
Armin Ronacherc9705c22008-04-27 21:28:03 +0200329 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200330 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200331
Armin Ronacherc9705c22008-04-27 21:28:03 +0200332 def visit_Import(self, node):
333 self.generic_visit(node)
334 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200335
Armin Ronacherc9705c22008-04-27 21:28:03 +0200336 def visit_FromImport(self, node):
337 self.generic_visit(node)
338 for name in node.names:
339 if isinstance(name, tuple):
340 self.identifiers.declared_locally.add(name[1])
341 else:
342 self.identifiers.declared_locally.add(name)
343
344 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200345 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200346 self.visit(node.node)
347 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200348
Armin Ronacherc9705c22008-04-27 21:28:03 +0200349 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200350 """Visiting stops at for blocks. However the block sequence
351 is visited as part of the outer scope.
352 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200353 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200354
Armin Ronacherc9705c22008-04-27 21:28:03 +0200355 def visit_CallBlock(self, node):
Armin Ronacheref189442010-01-14 01:26:40 +0100356 self.visit(node.call)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200357
358 def visit_FilterBlock(self, node):
359 self.visit(node.filter)
360
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100361 def visit_Scope(self, node):
362 """Stop visiting at scopes."""
363
Armin Ronacherc9705c22008-04-27 21:28:03 +0200364 def visit_Block(self, node):
365 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200366
367
Armin Ronacher75cfb862008-04-11 13:47:22 +0200368class CompilerExit(Exception):
369 """Raised if the compiler encountered a situation where it just
370 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200371 raises such an exception is not further processed.
372 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200373
374
Armin Ronachere791c2a2008-04-07 18:39:54 +0200375class CodeGenerator(NodeVisitor):
376
Armin Ronacher64b08a02010-03-12 03:17:41 +0100377 def __init__(self, environment, name, filename, stream=None,
378 defer_init=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200379 if stream is None:
380 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200381 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200382 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200383 self.filename = filename
384 self.stream = stream
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100385 self.created_block_context = False
Armin Ronacher64b08a02010-03-12 03:17:41 +0100386 self.defer_init = defer_init
Armin Ronacherfed44b52008-04-13 19:42:53 +0200387
Armin Ronacher023b5e92008-05-08 11:03:10 +0200388 # aliases for imports
389 self.import_aliases = {}
390
Armin Ronacherfed44b52008-04-13 19:42:53 +0200391 # a registry for all blocks. Because blocks are moved out
392 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200393 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200394
395 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200396 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200397
398 # some templates have a rootlevel extends. In this case we
399 # can safely assume that we're a child template and do some
400 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200401 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200402
Armin Ronacherba3757b2008-04-16 19:43:16 +0200403 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200404 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200405
Armin Ronacherb9e78752008-05-10 23:36:28 +0200406 # registry of all filters and tests (global, not block local)
407 self.tests = {}
408 self.filters = {}
409
Armin Ronacherba3757b2008-04-16 19:43:16 +0200410 # the debug information
411 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200412 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200413
Armin Ronacherfed44b52008-04-13 19:42:53 +0200414 # the number of new lines before the next write()
415 self._new_lines = 0
416
417 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200418 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200419
420 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200421 self._first_write = True
422
Armin Ronacherfed44b52008-04-13 19:42:53 +0200423 # used by the `temporary_identifier` method to get new
424 # unique, temporary identifier
425 self._last_identifier = 0
426
427 # the current indentation
428 self._indentation = 0
429
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200430 # -- Various compilation helpers
431
Armin Ronachere2244882008-05-19 09:25:57 +0200432 def fail(self, msg, lineno):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100433 """Fail with a :exc:`TemplateAssertionError`."""
Armin Ronachere2244882008-05-19 09:25:57 +0200434 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
435
Armin Ronachere791c2a2008-04-07 18:39:54 +0200436 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200437 """Get a new unique identifier."""
438 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200439 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200440
Armin Ronachered1e0d42008-05-18 20:25:28 +0200441 def buffer(self, frame):
442 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200443 frame.buffer = self.temporary_identifier()
444 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200445
446 def return_buffer_contents(self, frame):
447 """Return the buffer contents of the frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100448 if frame.eval_ctx.volatile:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100449 self.writeline('if context.eval_ctx.autoescape:')
450 self.indent()
451 self.writeline('return Markup(concat(%s))' % frame.buffer)
452 self.outdent()
453 self.writeline('else:')
454 self.indent()
455 self.writeline('return concat(%s)' % frame.buffer)
456 self.outdent()
Armin Ronacher8346bd72010-03-14 19:43:47 +0100457 elif frame.eval_ctx.autoescape:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100458 self.writeline('return Markup(concat(%s))' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200459 else:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100460 self.writeline('return concat(%s)' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200461
Armin Ronachere791c2a2008-04-07 18:39:54 +0200462 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200463 """Indent by one."""
464 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200465
Armin Ronacher8efc5222008-04-08 14:47:40 +0200466 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200467 """Outdent by step."""
468 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200469
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200470 def start_write(self, frame, node=None):
471 """Yield or write into the frame buffer."""
472 if frame.buffer is None:
473 self.writeline('yield ', node)
474 else:
475 self.writeline('%s.append(' % frame.buffer, node)
476
477 def end_write(self, frame):
478 """End the writing process started by `start_write`."""
479 if frame.buffer is not None:
480 self.write(')')
481
482 def simple_write(self, s, frame, node=None):
483 """Simple shortcut for start_write + write + end_write."""
484 self.start_write(frame, node)
485 self.write(s)
486 self.end_write(frame)
487
Armin Ronacherf40c8842008-09-17 18:51:26 +0200488 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200489 """Visit a list of nodes as block in a frame. If the current frame
490 is no buffer a dummy ``if 0: yield None`` is written automatically
491 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200492 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200493 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200494 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200495 else:
496 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200497 try:
498 for node in nodes:
499 self.visit(node, frame)
500 except CompilerExit:
501 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200502
503 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200504 """Write a string into the output stream."""
505 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200506 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200507 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200508 self.code_lineno += self._new_lines
509 if self._write_debug_info is not None:
510 self.debug_info.append((self._write_debug_info,
511 self.code_lineno))
512 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200513 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200514 self.stream.write(' ' * self._indentation)
515 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200516 self.stream.write(x)
517
518 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200519 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200520 self.newline(node, extra)
521 self.write(x)
522
523 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200524 """Add one or more newlines before the next write."""
525 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200526 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200527 self._write_debug_info = node.lineno
528 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200529
Armin Ronacherfd310492008-05-25 00:16:51 +0200530 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200531 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200532 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200533 arguments may not include python keywords otherwise a syntax
534 error could occour. The extra keyword arguments should be given
535 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200536 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200537 # if any of the given keyword arguments is a python keyword
538 # we have to make sure that no invalid call is created.
539 kwarg_workaround = False
540 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200541 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200542 kwarg_workaround = True
543 break
544
Armin Ronacher8efc5222008-04-08 14:47:40 +0200545 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200546 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200547 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200548
549 if not kwarg_workaround:
550 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200551 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200552 self.visit(kwarg, frame)
553 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200554 for key, value in six.iteritems(extra_kwargs):
Armin Ronacherfd310492008-05-25 00:16:51 +0200555 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200556 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200557 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200558 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200559
560 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200561 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200562 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200563 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200564 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200565 for kwarg in node.kwargs:
566 self.write('%r: ' % kwarg.key)
567 self.visit(kwarg.value, frame)
568 self.write(', ')
569 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200570 for key, value in six.iteritems(extra_kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200571 self.write('%r: %s, ' % (key, value))
572 if node.dyn_kwargs is not None:
573 self.write('}, **')
574 self.visit(node.dyn_kwargs, frame)
575 self.write(')')
576 else:
577 self.write('}')
578
579 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200580 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200581 self.visit(node.dyn_kwargs, frame)
582
Armin Ronacherc9705c22008-04-27 21:28:03 +0200583 def pull_locals(self, frame):
584 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200585 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200586 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200587
588 def pull_dependencies(self, nodes):
589 """Pull all the dependencies."""
590 visitor = DependencyFinderVisitor()
591 for node in nodes:
592 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200593 for dependency in 'filters', 'tests':
594 mapping = getattr(self, dependency)
595 for name in getattr(visitor, dependency):
596 if name not in mapping:
597 mapping[name] = self.temporary_identifier()
598 self.writeline('%s = environment.%s[%r]' %
599 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200600
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100601 def unoptimize_scope(self, frame):
602 """Disable Python optimizations for the frame."""
603 # XXX: this is not that nice but it has no real overhead. It
604 # mainly works because python finds the locals before dead code
605 # is removed. If that breaks we have to add a dummy function
606 # that just accepts the arguments and does nothing.
607 if frame.identifiers.declared:
Armin Ronacher821a4232010-02-17 07:59:38 +0100608 self.writeline('%sdummy(%s)' % (
609 unoptimize_before_dead_code and 'if 0: ' or '',
610 ', '.join('l_' + name for name in frame.identifiers.declared)
611 ))
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100612
Armin Ronacher673aa882008-10-04 18:06:57 +0200613 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200614 """This function returns all the shadowed variables in a dict
615 in the form name: alias and will write the required assignments
616 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200617
Armin Ronacher673aa882008-10-04 18:06:57 +0200618 This also predefines locally declared variables from the loop
619 body because under some circumstances it may be the case that
620
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100621 `extra_vars` is passed to `Frame.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200622 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200623 aliases = {}
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100624 for name in frame.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200625 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200626 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200627 to_declare = set()
628 for name in frame.identifiers.declared_locally:
629 if name not in aliases:
630 to_declare.add('l_' + name)
631 if to_declare:
632 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200633 return aliases
634
Armin Ronacher673aa882008-10-04 18:06:57 +0200635 def pop_scope(self, aliases, frame):
636 """Restore all aliases and delete unused variables."""
Thomas Waldmanne0003552013-05-17 23:52:14 +0200637 for name, alias in six.iteritems(aliases):
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200638 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200639 to_delete = set()
640 for name in frame.identifiers.declared_locally:
641 if name not in aliases:
642 to_delete.add('l_' + name)
643 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100644 # we cannot use the del statement here because enclosed
645 # scopes can trigger a SyntaxError:
646 # a = 42; b = lambda: a; del a
647 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200648
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200649 def function_scoping(self, node, frame, children=None,
650 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200651 """In Jinja a few statements require the help of anonymous
652 functions. Those are currently macros and call blocks and in
653 the future also recursive loops. As there is currently
654 technical limitation that doesn't allow reading and writing a
655 variable in a scope where the initial value is coming from an
656 outer scope, this function tries to fall back with a common
657 error message. Additionally the frame passed is modified so
658 that the argumetns are collected and callers are looked up.
659
660 This will return the modified frame.
661 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200662 # we have to iterate twice over it, make sure that works
663 if children is None:
664 children = node.iter_child_nodes()
665 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200666 func_frame = frame.inner()
Armin Ronacherda632622011-03-13 14:33:27 -0400667 func_frame.inspect(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200668
669 # variables that are undeclared (accessed before declaration) and
670 # declared locally *and* part of an outside scope raise a template
671 # assertion error. Reason: we can't generate reasonable code from
Armin Ronacher02b42a82009-03-18 00:59:32 +0100672 # it without aliasing all the variables.
673 # this could be fixed in Python 3 where we have the nonlocal
674 # keyword or if we switch to bytecode generation
Armin Ronacher71082072008-04-12 14:19:36 +0200675 overriden_closure_vars = (
676 func_frame.identifiers.undeclared &
677 func_frame.identifiers.declared &
678 (func_frame.identifiers.declared_locally |
679 func_frame.identifiers.declared_parameter)
680 )
681 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200682 self.fail('It\'s not possible to set and access variables '
Armin Ronacherefcc0e52009-09-13 00:22:50 -0700683 'derived from an outer scope! (affects: %s)' %
Armin Ronachere2244882008-05-19 09:25:57 +0200684 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200685
686 # remove variables from a closure from the frame's undeclared
687 # identifiers.
688 func_frame.identifiers.undeclared -= (
689 func_frame.identifiers.undeclared &
690 func_frame.identifiers.declared
691 )
692
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200693 # no special variables for this scope, abort early
694 if not find_special:
695 return func_frame
696
Armin Ronacher963f97d2008-04-25 11:44:59 +0200697 func_frame.accesses_kwargs = False
698 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200699 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200700 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200701
Armin Ronacherc9705c22008-04-27 21:28:03 +0200702 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
703
704 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200705 func_frame.accesses_caller = True
706 func_frame.identifiers.add_special('caller')
707 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200708 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200709 func_frame.accesses_kwargs = True
710 func_frame.identifiers.add_special('kwargs')
711 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200712 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200713 func_frame.accesses_varargs = True
714 func_frame.identifiers.add_special('varargs')
715 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200716 return func_frame
717
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200718 def macro_body(self, node, frame, children=None):
719 """Dump the function def of a macro or call block."""
720 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100721 # macros are delayed, they never require output checks
722 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200723 args = frame.arguments
Armin Ronachereabf3dd2009-09-12 23:48:18 -0700724 # XXX: this is an ugly fix for the loop nesting bug
725 # (tests.test_old_bugs.test_loop_call_bug). This works around
726 # a identifier nesting problem we have in general. It's just more
727 # likely to happen in loops which is why we work around it. The
728 # real solution would be "nonlocal" all the identifiers that are
729 # leaking into a new python frame and might be used both unassigned
730 # and assigned.
731 if 'loop' in frame.identifiers.declared:
Armin Ronacherb4044392009-09-13 15:56:58 -0700732 args = args + ['l_loop=l_loop']
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200733 self.writeline('def macro(%s):' % ', '.join(args), node)
734 self.indent()
735 self.buffer(frame)
736 self.pull_locals(frame)
737 self.blockvisit(node.body, frame)
738 self.return_buffer_contents(frame)
739 self.outdent()
740 return frame
741
742 def macro_def(self, node, frame):
743 """Dump the macro definition for the def created by macro_body."""
744 arg_tuple = ', '.join(repr(x.name) for x in node.args)
745 name = getattr(node, 'name', None)
746 if len(node.args) == 1:
747 arg_tuple += ','
748 self.write('Macro(environment, macro, %r, (%s), (' %
749 (name, arg_tuple))
750 for arg in node.defaults:
751 self.visit(arg, frame)
752 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200753 self.write('), %r, %r, %r)' % (
754 bool(frame.accesses_kwargs),
755 bool(frame.accesses_varargs),
756 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200757 ))
758
Armin Ronacher547d0b62008-07-04 16:35:10 +0200759 def position(self, node):
760 """Return a human readable position for the node."""
761 rv = 'line %d' % node.lineno
762 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100763 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200764 return rv
765
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200766 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200767
768 def visit_Template(self, node, frame=None):
769 assert frame is None, 'no root frame allowed'
Armin Ronacher1da23d12010-04-05 18:11:18 +0200770 eval_ctx = EvalContext(self.environment, self.name)
Armin Ronacher8346bd72010-03-14 19:43:47 +0100771
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200772 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200773 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200774 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher821a4232010-02-17 07:59:38 +0100775 if not unoptimize_before_dead_code:
776 self.writeline('dummy = lambda *x: None')
Armin Ronacher8edbe492008-04-10 20:43:43 +0200777
Armin Ronacher64b08a02010-03-12 03:17:41 +0100778 # if we want a deferred initialization we cannot move the
779 # environment into a local name
780 envenv = not self.defer_init and ', environment=environment' or ''
781
Armin Ronacher75cfb862008-04-11 13:47:22 +0200782 # do we have an extends tag at all? If not, we can save some
783 # overhead by just not processing any inheritance code.
784 have_extends = node.find(nodes.Extends) is not None
785
Armin Ronacher8edbe492008-04-10 20:43:43 +0200786 # find all blocks
787 for block in node.find_all(nodes.Block):
788 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200789 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200790 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200791
Armin Ronacher023b5e92008-05-08 11:03:10 +0200792 # find all imports and import them
793 for import_ in node.find_all(nodes.ImportedName):
794 if import_.importname not in self.import_aliases:
795 imp = import_.importname
796 self.import_aliases[imp] = alias = self.temporary_identifier()
797 if '.' in imp:
798 module, obj = imp.rsplit('.', 1)
799 self.writeline('from %s import %s as %s' %
800 (module, obj, alias))
801 else:
802 self.writeline('import %s as %s' % (imp, alias))
803
804 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200805 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200806
Armin Ronacher8efc5222008-04-08 14:47:40 +0200807 # generate the root render function.
Armin Ronacher64b08a02010-03-12 03:17:41 +0100808 self.writeline('def root(context%s):' % envenv, extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200809
810 # process the root
Armin Ronacher8346bd72010-03-14 19:43:47 +0100811 frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200812 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200813 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200814 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200815 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200816 if have_extends:
817 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200818 if 'self' in find_undeclared(node.body, ('self',)):
819 frame.identifiers.add_special('self')
820 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200821 self.pull_locals(frame)
822 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200823 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200824 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200825
Armin Ronacher8efc5222008-04-08 14:47:40 +0200826 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200827 if have_extends:
828 if not self.has_known_extends:
829 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200830 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200831 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200832 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200833 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200834 self.indent()
835 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200836 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200837
838 # at this point we now have the blocks collected and can visit them too.
Thomas Waldmanne0003552013-05-17 23:52:14 +0200839 for name, block in six.iteritems(self.blocks):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100840 block_frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200841 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200842 block_frame.block = name
Armin Ronacher64b08a02010-03-12 03:17:41 +0100843 self.writeline('def block_%s(context%s):' % (name, envenv),
844 block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200845 self.indent()
846 undeclared = find_undeclared(block.body, ('self', 'super'))
847 if 'self' in undeclared:
848 block_frame.identifiers.add_special('self')
849 self.writeline('l_self = TemplateReference(context)')
850 if 'super' in undeclared:
851 block_frame.identifiers.add_special('super')
852 self.writeline('l_super = context.super(%r, '
853 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200854 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200855 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200856 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200857 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200858
Armin Ronacher75cfb862008-04-11 13:47:22 +0200859 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200860 for x in self.blocks),
861 extra=1)
862
863 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200864 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
865 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200866
Armin Ronachere791c2a2008-04-07 18:39:54 +0200867 def visit_Block(self, node, frame):
868 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200869 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200870 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200871 # if we know that we are a child template, there is no need to
872 # check if we are one
873 if self.has_known_extends:
874 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200875 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200876 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200877 self.indent()
878 level += 1
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100879 context = node.scoped and 'context.derived(locals())' or 'context'
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100880 self.writeline('for event in context.blocks[%r][0](%s):' % (
881 node.name, context), node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200882 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200883 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200884 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200885
886 def visit_Extends(self, node, frame):
887 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200888 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200889 self.fail('cannot use extend from a non top-level scope',
890 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200891
Armin Ronacher7fb38972008-04-11 13:54:28 +0200892 # if the number of extends statements in general is zero so
893 # far, we don't have to add a check if something extended
894 # the template before this one.
895 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200896
Armin Ronacher7fb38972008-04-11 13:54:28 +0200897 # if we have a known extends we just add a template runtime
898 # error into the generated code. We could catch that at compile
899 # time too, but i welcome it not to confuse users by throwing the
900 # same error at different times just "because we can".
901 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200902 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200903 self.indent()
904 self.writeline('raise TemplateRuntimeError(%r)' %
905 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200906 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200907
Armin Ronacher7fb38972008-04-11 13:54:28 +0200908 # if we have a known extends already we don't need that code here
909 # as we know that the template execution will end here.
910 if self.has_known_extends:
911 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200912
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200913 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200914 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200915 self.write(', %r)' % self.name)
916 self.writeline('for name, parent_block in parent_template.'
Armin Ronacher0d242be2010-02-10 01:35:13 +0100917 'blocks.%s():' % dict_item_iter)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200918 self.indent()
919 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200920 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200921 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200922
923 # if this extends statement was in the root level we can take
924 # advantage of that information and simplify the generated code
925 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200926 if frame.rootlevel:
927 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200928
Armin Ronacher7fb38972008-04-11 13:54:28 +0200929 # and now we have one more
930 self.extends_so_far += 1
931
Armin Ronacherf059ec12008-04-11 22:21:00 +0200932 def visit_Include(self, node, frame):
933 """Handles includes."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100934 if node.with_context:
935 self.unoptimize_scope(frame)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100936 if node.ignore_missing:
937 self.writeline('try:')
938 self.indent()
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100939
940 func_name = 'get_or_select_template'
941 if isinstance(node.template, nodes.Const):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200942 if isinstance(node.template.value, six.string_types):
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100943 func_name = 'get_template'
944 elif isinstance(node.template.value, (tuple, list)):
945 func_name = 'select_template'
946 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
947 func_name = 'select_template'
948
949 self.writeline('template = environment.%s(' % func_name, node)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100950 self.visit(node.template, frame)
951 self.write(', %r)' % self.name)
952 if node.ignore_missing:
953 self.outdent()
954 self.writeline('except TemplateNotFound:')
955 self.indent()
956 self.writeline('pass')
957 self.outdent()
958 self.writeline('else:')
959 self.indent()
960
Armin Ronacherea847c52008-05-02 20:04:32 +0200961 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200962 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200963 'template.new_context(context.parent, True, '
964 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200965 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100966 self.writeline('for event in template.module._body_stream:')
967
Armin Ronacherf059ec12008-04-11 22:21:00 +0200968 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200969 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200970 self.outdent()
971
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100972 if node.ignore_missing:
973 self.outdent()
974
Armin Ronacher0611e492008-04-25 23:44:14 +0200975 def visit_Import(self, node, frame):
976 """Visit regular imports."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100977 if node.with_context:
978 self.unoptimize_scope(frame)
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200979 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200980 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200981 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200982 self.write('environment.get_template(')
983 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200984 self.write(', %r).' % self.name)
985 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200986 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200987 else:
988 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200989 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200990 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100991 frame.assigned_names.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200992
993 def visit_FromImport(self, node, frame):
994 """Visit named imports."""
995 self.newline(node)
996 self.write('included_template = environment.get_template(')
997 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200998 self.write(', %r).' % self.name)
999 if node.with_context:
1000 self.write('make_module(context.parent, True)')
1001 else:
1002 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +02001003
1004 var_names = []
1005 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +02001006 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +02001007 if isinstance(name, tuple):
1008 name, alias = name
1009 else:
1010 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001011 self.writeline('l_%s = getattr(included_template, '
1012 '%r, missing)' % (alias, name))
1013 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +02001014 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001015 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +02001016 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +02001017 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001018 (alias, 'the template %%r (imported on %s) does '
1019 'not export the requested name %s' % (
1020 self.position(node),
1021 repr(name)
1022 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +02001023 self.outdent()
1024 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +02001025 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +02001026 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +02001027 discarded_names.append(alias)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001028 frame.assigned_names.add(alias)
Armin Ronachera78d2762008-05-15 23:18:07 +02001029
1030 if var_names:
1031 if len(var_names) == 1:
1032 name = var_names[0]
1033 self.writeline('context.vars[%r] = l_%s' % (name, name))
1034 else:
1035 self.writeline('context.vars.update({%s})' % ', '.join(
1036 '%r: l_%s' % (name, name) for name in var_names
1037 ))
1038 if discarded_names:
1039 if len(discarded_names) == 1:
1040 self.writeline('context.exported_vars.discard(%r)' %
1041 discarded_names[0])
1042 else:
1043 self.writeline('context.exported_vars.difference_'
1044 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +02001045
Armin Ronachere791c2a2008-04-07 18:39:54 +02001046 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001047 # when calculating the nodes for the inner frame we have to exclude
1048 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001049 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001050 if node.recursive:
1051 loop_frame = self.function_scoping(node, frame, children,
1052 find_special=False)
1053 else:
1054 loop_frame = frame.inner()
1055 loop_frame.inspect(children)
1056
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001057 # try to figure out if we have an extended loop. An extended loop
1058 # is necessary if the loop is in recursive mode if the special loop
1059 # variable is accessed in the body.
1060 extended_loop = node.recursive or 'loop' in \
1061 find_undeclared(node.iter_child_nodes(
1062 only=('body',)), ('loop',))
1063
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001064 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +02001065 # variables at that point. Because loops can be nested but the loop
1066 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001067 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +02001068 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001069
1070 # otherwise we set up a buffer and add a function def
1071 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001072 self.writeline('def loop(reciter, loop_render_func):', node)
1073 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +02001074 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001075 aliases = {}
1076
Armin Ronacherff53c782008-08-13 18:55:50 +02001077 # make sure the loop variable is a special one and raise a template
1078 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +02001079 if extended_loop:
1080 loop_frame.identifiers.add_special('loop')
Armin Ronacherff53c782008-08-13 18:55:50 +02001081 for name in node.find_all(nodes.Name):
1082 if name.ctx == 'store' and name.name == 'loop':
1083 self.fail('Can\'t assign to special loop variable '
1084 'in for-loop target', name.lineno)
1085
Armin Ronacherc9705c22008-04-27 21:28:03 +02001086 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001087 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001088 iteration_indicator = self.temporary_identifier()
1089 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001090
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001091 # Create a fake parent loop if the else or test section of a
1092 # loop is accessing the special loop variable and no parent loop
1093 # exists.
1094 if 'loop' not in aliases and 'loop' in find_undeclared(
1095 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1096 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001097 ("'loop' is undefined. the filter section of a loop as well "
Armin Ronacherbc56cd22011-01-15 18:35:45 +01001098 "as the else block don't have access to the special 'loop'"
Armin Ronacher547d0b62008-07-04 16:35:10 +02001099 " variable of the current loop. Because there is no parent "
1100 "loop it's undefined. Happened in loop on %s" %
1101 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001102
1103 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001104 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +02001105 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001106
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001107 # if we have an extened loop and a node test, we filter in the
1108 # "outer frame".
1109 if extended_loop and node.test is not None:
1110 self.write('(')
1111 self.visit(node.target, loop_frame)
1112 self.write(' for ')
1113 self.visit(node.target, loop_frame)
1114 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001115 if node.recursive:
1116 self.write('reciter')
1117 else:
1118 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001119 self.write(' if (')
1120 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001121 self.visit(node.test, test_frame)
1122 self.write('))')
1123
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001124 elif node.recursive:
1125 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001126 else:
1127 self.visit(node.iter, loop_frame)
1128
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001129 if node.recursive:
1130 self.write(', recurse=loop_render_func):')
1131 else:
1132 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001133
1134 # tests in not extended loops become a continue
1135 if not extended_loop and node.test is not None:
1136 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +02001137 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +02001138 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001139 self.write(':')
1140 self.indent()
1141 self.writeline('continue')
1142 self.outdent(2)
1143
Armin Ronacherc9705c22008-04-27 21:28:03 +02001144 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001145 self.blockvisit(node.body, loop_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001146 if node.else_:
1147 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001148 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001149
1150 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001151 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001152 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001153 self.blockvisit(node.else_, loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001154 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001155
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001156 # reset the aliases if there are any.
Armin Ronachercebd8382008-12-25 18:33:46 +01001157 if not node.recursive:
1158 self.pop_scope(aliases, loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001159
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001160 # if the node was recursive we have to return the buffer contents
1161 # and start the iteration code
1162 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001163 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001164 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001165 self.start_write(frame, node)
1166 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001167 self.visit(node.iter, frame)
1168 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001169 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001170
Armin Ronachere791c2a2008-04-07 18:39:54 +02001171 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001172 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001173 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001174 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001175 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001176 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001177 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001178 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001179 if node.else_:
1180 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001181 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001182 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001183 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001184
Armin Ronacher8efc5222008-04-08 14:47:40 +02001185 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001186 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001187 self.newline()
1188 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001189 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001190 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001191 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001192 self.write('l_%s = ' % node.name)
1193 self.macro_def(node, macro_frame)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001194 frame.assigned_names.add(node.name)
Armin Ronacher71082072008-04-12 14:19:36 +02001195
1196 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001197 children = node.iter_child_nodes(exclude=('call',))
1198 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001199 self.writeline('caller = ')
1200 self.macro_def(node, call_frame)
1201 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001202 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001203 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001204
1205 def visit_FilterBlock(self, node, frame):
1206 filter_frame = frame.inner()
1207 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacher673aa882008-10-04 18:06:57 +02001208 aliases = self.push_scope(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001209 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001210 self.buffer(filter_frame)
Armin Ronacherf40c8842008-09-17 18:51:26 +02001211 self.blockvisit(node.body, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001212 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001213 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001214 self.end_write(frame)
Armin Ronacher673aa882008-10-04 18:06:57 +02001215 self.pop_scope(aliases, filter_frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001216
Armin Ronachere791c2a2008-04-07 18:39:54 +02001217 def visit_ExprStmt(self, node, frame):
1218 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001219 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001220
1221 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001222 # if we have a known extends statement, we don't output anything
Armin Ronacher79668952008-09-23 22:52:46 +02001223 # if we are in a require_output_check section
1224 if self.has_known_extends and frame.require_output_check:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001225 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001226
Armin Ronacher665bfb82008-07-14 13:41:46 +02001227 if self.environment.finalize:
Thomas Waldmanne0003552013-05-17 23:52:14 +02001228 finalize = lambda x: six.text_type(self.environment.finalize(x))
Armin Ronacher665bfb82008-07-14 13:41:46 +02001229 else:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001230 finalize = six.text_type
Armin Ronacher665bfb82008-07-14 13:41:46 +02001231
Armin Ronacher79668952008-09-23 22:52:46 +02001232 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001233 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001234 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001235 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001236 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001237 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001238
Armin Ronachere791c2a2008-04-07 18:39:54 +02001239 # try to evaluate as many chunks as possible into a static
1240 # string at compile time.
1241 body = []
1242 for child in node.nodes:
1243 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001244 const = child.as_const(frame.eval_ctx)
Armin Ronacher9cf95912008-05-24 19:54:43 +02001245 except nodes.Impossible:
1246 body.append(child)
1247 continue
Armin Ronacher8346bd72010-03-14 19:43:47 +01001248 # the frame can't be volatile here, becaus otherwise the
1249 # as_const() function would raise an Impossible exception
1250 # at that point.
Armin Ronacher9cf95912008-05-24 19:54:43 +02001251 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001252 if frame.eval_ctx.autoescape:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001253 if hasattr(const, '__html__'):
1254 const = const.__html__()
1255 else:
1256 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001257 const = finalize(const)
Ian Lewisab014bd2010-10-31 20:29:28 +09001258 except Exception:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001259 # if something goes wrong here we evaluate the node
1260 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001261 body.append(child)
1262 continue
1263 if body and isinstance(body[-1], list):
1264 body[-1].append(const)
1265 else:
1266 body.append([const])
1267
Armin Ronachered1e0d42008-05-18 20:25:28 +02001268 # if we have less than 3 nodes or a buffer we yield or extend/append
1269 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001270 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001271 # for one item we append, for more we extend
1272 if len(body) == 1:
1273 self.writeline('%s.append(' % frame.buffer)
1274 else:
1275 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001276 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001277 for item in body:
1278 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001279 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001280 if frame.buffer is None:
1281 self.writeline('yield ' + val)
1282 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001283 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001284 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001285 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001286 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001287 else:
1288 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001289 close = 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001290 if frame.eval_ctx.volatile:
1291 self.write('(context.eval_ctx.autoescape and'
1292 ' escape or to_string)(')
1293 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001294 self.write('escape(')
1295 else:
Armin Ronacherbd357722009-08-05 20:25:06 +02001296 self.write('to_string(')
Armin Ronacherd1342312008-04-28 12:20:12 +02001297 if self.environment.finalize is not None:
1298 self.write('environment.finalize(')
1299 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001300 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001301 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001302 if frame.buffer is not None:
1303 self.write(', ')
1304 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001305 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001306 self.outdent()
1307 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001308
1309 # otherwise we create a format string as this is faster in that case
1310 else:
1311 format = []
1312 arguments = []
1313 for item in body:
1314 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001315 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001316 else:
1317 format.append('%s')
1318 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001319 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001320 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001321 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001322 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001323 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001324 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001325 close = 0
Armin Ronacher8346bd72010-03-14 19:43:47 +01001326 if frame.eval_ctx.volatile:
1327 self.write('(context.eval_ctx.autoescape and'
1328 ' escape or to_string)(')
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001329 close += 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001330 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001331 self.write('escape(')
1332 close += 1
1333 if self.environment.finalize is not None:
1334 self.write('environment.finalize(')
1335 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001336 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001337 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001338 self.outdent()
1339 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001340
Armin Ronacher7fb38972008-04-11 13:54:28 +02001341 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001342 self.outdent()
1343
Armin Ronacher8efc5222008-04-08 14:47:40 +02001344 def visit_Assign(self, node, frame):
1345 self.newline(node)
1346 # toplevel assignments however go into the local namespace and
1347 # the current template's context. We create a copy of the frame
1348 # here and add a set so that the Name visitor can add the assigned
1349 # names here.
1350 if frame.toplevel:
1351 assignment_frame = frame.copy()
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001352 assignment_frame.toplevel_assignments = set()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001353 else:
1354 assignment_frame = frame
1355 self.visit(node.target, assignment_frame)
1356 self.write(' = ')
1357 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001358
1359 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001360 if frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001361 public_names = [x for x in assignment_frame.toplevel_assignments
Armin Ronacher903d1682008-05-23 00:51:58 +02001362 if not x.startswith('_')]
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001363 if len(assignment_frame.toplevel_assignments) == 1:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001364 name = six.advance_iterator(iter(assignment_frame.toplevel_assignments))
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001365 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001366 else:
1367 self.writeline('context.vars.update({')
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001368 for idx, name in enumerate(assignment_frame.toplevel_assignments):
Armin Ronacher69e12db2008-05-12 09:00:03 +02001369 if idx:
1370 self.write(', ')
1371 self.write('%r: l_%s' % (name, name))
1372 self.write('})')
1373 if public_names:
1374 if len(public_names) == 1:
1375 self.writeline('context.exported_vars.add(%r)' %
1376 public_names[0])
1377 else:
1378 self.writeline('context.exported_vars.update((%s))' %
1379 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001380
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001381 # -- Expression Visitors
1382
Armin Ronachere791c2a2008-04-07 18:39:54 +02001383 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001384 if node.ctx == 'store' and frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001385 frame.toplevel_assignments.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001386 self.write('l_' + node.name)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001387 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001388
1389 def visit_Const(self, node, frame):
1390 val = node.value
1391 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001392 self.write(str(val))
1393 else:
1394 self.write(repr(val))
1395
Armin Ronacher5411ce72008-05-25 11:36:22 +02001396 def visit_TemplateData(self, node, frame):
Armin Ronacherffaa2e72010-05-29 20:57:16 +02001397 try:
1398 self.write(repr(node.as_const(frame.eval_ctx)))
1399 except nodes.Impossible:
1400 self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)'
1401 % node.data)
Armin Ronacher5411ce72008-05-25 11:36:22 +02001402
Armin Ronacher8efc5222008-04-08 14:47:40 +02001403 def visit_Tuple(self, node, frame):
1404 self.write('(')
1405 idx = -1
1406 for idx, item in enumerate(node.items):
1407 if idx:
1408 self.write(', ')
1409 self.visit(item, frame)
1410 self.write(idx == 0 and ',)' or ')')
1411
Armin Ronacher8edbe492008-04-10 20:43:43 +02001412 def visit_List(self, node, frame):
1413 self.write('[')
1414 for idx, item in enumerate(node.items):
1415 if idx:
1416 self.write(', ')
1417 self.visit(item, frame)
1418 self.write(']')
1419
1420 def visit_Dict(self, node, frame):
1421 self.write('{')
1422 for idx, item in enumerate(node.items):
1423 if idx:
1424 self.write(', ')
1425 self.visit(item.key, frame)
1426 self.write(': ')
1427 self.visit(item.value, frame)
1428 self.write('}')
1429
Armin Ronachera9195382010-11-29 13:21:57 +01001430 def binop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001431 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001432 if self.environment.sandboxed and \
1433 operator in self.environment.intercepted_binops:
1434 self.write('environment.call_binop(context, %r, ' % operator)
1435 self.visit(node.left, frame)
1436 self.write(', ')
1437 self.visit(node.right, frame)
1438 else:
1439 self.write('(')
1440 self.visit(node.left, frame)
1441 self.write(' %s ' % operator)
1442 self.visit(node.right, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001443 self.write(')')
1444 return visitor
1445
Armin Ronachera9195382010-11-29 13:21:57 +01001446 def uaop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001447 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001448 if self.environment.sandboxed and \
1449 operator in self.environment.intercepted_unops:
1450 self.write('environment.call_unop(context, %r, ' % operator)
1451 self.visit(node.node, frame)
1452 else:
1453 self.write('(' + operator)
1454 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001455 self.write(')')
1456 return visitor
1457
1458 visit_Add = binop('+')
1459 visit_Sub = binop('-')
1460 visit_Mul = binop('*')
1461 visit_Div = binop('/')
1462 visit_FloorDiv = binop('//')
1463 visit_Pow = binop('**')
1464 visit_Mod = binop('%')
Armin Ronachera9195382010-11-29 13:21:57 +01001465 visit_And = binop('and', interceptable=False)
1466 visit_Or = binop('or', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001467 visit_Pos = uaop('+')
1468 visit_Neg = uaop('-')
Armin Ronachera9195382010-11-29 13:21:57 +01001469 visit_Not = uaop('not ', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001470 del binop, uaop
1471
Armin Ronacherd1342312008-04-28 12:20:12 +02001472 def visit_Concat(self, node, frame):
Armin Ronacher8346bd72010-03-14 19:43:47 +01001473 if frame.eval_ctx.volatile:
1474 func_name = '(context.eval_ctx.volatile and' \
1475 ' markup_join or unicode_join)'
1476 elif frame.eval_ctx.autoescape:
1477 func_name = 'markup_join'
1478 else:
1479 func_name = 'unicode_join'
1480 self.write('%s((' % func_name)
Armin Ronacherd1342312008-04-28 12:20:12 +02001481 for arg in node.nodes:
1482 self.visit(arg, frame)
1483 self.write(', ')
1484 self.write('))')
1485
Armin Ronachere791c2a2008-04-07 18:39:54 +02001486 def visit_Compare(self, node, frame):
1487 self.visit(node.expr, frame)
1488 for op in node.ops:
1489 self.visit(op, frame)
1490
1491 def visit_Operand(self, node, frame):
1492 self.write(' %s ' % operators[node.op])
1493 self.visit(node.expr, frame)
1494
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001495 def visit_Getattr(self, node, frame):
1496 self.write('environment.getattr(')
1497 self.visit(node.node, frame)
1498 self.write(', %r)' % node.attr)
1499
1500 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001501 # slices bypass the environment getitem method.
1502 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001503 self.visit(node.node, frame)
1504 self.write('[')
1505 self.visit(node.arg, frame)
1506 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001507 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001508 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001509 self.visit(node.node, frame)
1510 self.write(', ')
1511 self.visit(node.arg, frame)
1512 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001513
1514 def visit_Slice(self, node, frame):
1515 if node.start is not None:
1516 self.visit(node.start, frame)
1517 self.write(':')
1518 if node.stop is not None:
1519 self.visit(node.stop, frame)
1520 if node.step is not None:
1521 self.write(':')
1522 self.visit(node.step, frame)
1523
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001524 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001525 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001526 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001527 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001528 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001529 if getattr(func, 'contextfilter', False):
1530 self.write('context, ')
Armin Ronacher8346bd72010-03-14 19:43:47 +01001531 elif getattr(func, 'evalcontextfilter', False):
1532 self.write('context.eval_ctx, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001533 elif getattr(func, 'environmentfilter', False):
1534 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001535
1536 # if the filter node is None we are inside a filter block
1537 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001538 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001539 self.visit(node.node, frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001540 elif frame.eval_ctx.volatile:
1541 self.write('(context.eval_ctx.autoescape and'
1542 ' Markup(concat(%s)) or concat(%s))' %
1543 (frame.buffer, frame.buffer))
1544 elif frame.eval_ctx.autoescape:
Armin Ronacher3da90312008-05-23 16:37:28 +02001545 self.write('Markup(concat(%s))' % frame.buffer)
1546 else:
1547 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001548 self.signature(node, frame)
1549 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001550
1551 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001552 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001553 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001554 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001555 self.visit(node.node, frame)
1556 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001557 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001558
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001559 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001560 def write_expr2():
1561 if node.expr2 is not None:
1562 return self.visit(node.expr2, frame)
1563 self.write('environment.undefined(%r)' % ('the inline if-'
1564 'expression on %s evaluated to false and '
1565 'no else section was defined.' % self.position(node)))
1566
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001567 if not have_condexpr:
1568 self.write('((')
1569 self.visit(node.test, frame)
1570 self.write(') and (')
1571 self.visit(node.expr1, frame)
1572 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001573 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001574 self.write(',))[0]')
1575 else:
1576 self.write('(')
1577 self.visit(node.expr1, frame)
1578 self.write(' if ')
1579 self.visit(node.test, frame)
1580 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001581 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001582 self.write(')')
1583
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001584 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001585 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001586 self.write('environment.call(context, ')
1587 else:
1588 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001589 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001590 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001591 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001592 self.write(')')
1593
1594 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001595 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001596 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001597
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001598 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001599
1600 def visit_MarkSafe(self, node, frame):
1601 self.write('Markup(')
1602 self.visit(node.expr, frame)
1603 self.write(')')
1604
Armin Ronacher4da90342010-05-29 17:35:10 +02001605 def visit_MarkSafeIfAutoescape(self, node, frame):
1606 self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1607 self.visit(node.expr, frame)
1608 self.write(')')
1609
Armin Ronachered1e0d42008-05-18 20:25:28 +02001610 def visit_EnvironmentAttribute(self, node, frame):
1611 self.write('environment.' + node.name)
1612
1613 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001614 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001615
1616 def visit_ImportedName(self, node, frame):
1617 self.write(self.import_aliases[node.importname])
1618
1619 def visit_InternalName(self, node, frame):
1620 self.write(node.name)
1621
Armin Ronacher6df604e2008-05-23 22:18:38 +02001622 def visit_ContextReference(self, node, frame):
1623 self.write('context')
1624
Armin Ronachered1e0d42008-05-18 20:25:28 +02001625 def visit_Continue(self, node, frame):
1626 self.writeline('continue', node)
1627
1628 def visit_Break(self, node, frame):
1629 self.writeline('break', node)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001630
1631 def visit_Scope(self, node, frame):
1632 scope_frame = frame.inner()
1633 scope_frame.inspect(node.iter_child_nodes())
1634 aliases = self.push_scope(scope_frame)
1635 self.pull_locals(scope_frame)
1636 self.blockvisit(node.body, scope_frame)
1637 self.pop_scope(aliases, scope_frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001638
1639 def visit_EvalContextModifier(self, node, frame):
1640 for keyword in node.options:
1641 self.writeline('context.eval_ctx.%s = ' % keyword.key)
1642 self.visit(keyword.value, frame)
1643 try:
1644 val = keyword.value.as_const(frame.eval_ctx)
1645 except nodes.Impossible:
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001646 frame.eval_ctx.volatile = True
Armin Ronacher8346bd72010-03-14 19:43:47 +01001647 else:
1648 setattr(frame.eval_ctx, keyword.key, val)
1649
1650 def visit_ScopedEvalContextModifier(self, node, frame):
1651 old_ctx_name = self.temporary_identifier()
1652 safed_ctx = frame.eval_ctx.save()
1653 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1654 self.visit_EvalContextModifier(node, frame)
1655 for child in node.body:
1656 self.visit(child, frame)
1657 frame.eval_ctx.revert(safed_ctx)
1658 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)