blob: 1b1b5a7514fe4164dc94d687e0ee77bb9fe670b8 [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
Thomas Waldmann05ace8b2013-05-18 13:14:14 +020021from six.moves import xrange
Armin Ronachere791c2a2008-04-07 18:39:54 +020022
23
24operators = {
25 'eq': '==',
26 'ne': '!=',
27 'gt': '>',
28 'gteq': '>=',
29 'lt': '<',
30 'lteq': '<=',
31 'in': 'in',
32 'notin': 'not in'
33}
34
Armin Ronacher3d8b7842008-04-13 13:16:50 +020035try:
Thomas Waldmanne0003552013-05-17 23:52:14 +020036 exec('(0 if 0 else 0)')
Armin Ronacher3d8b7842008-04-13 13:16:50 +020037except SyntaxError:
38 have_condexpr = False
39else:
40 have_condexpr = True
41
42
Armin Ronacher0d242be2010-02-10 01:35:13 +010043# what method to iterate over items do we want to use for dict iteration
44# in generated code? on 2.x let's go with iteritems, on 3.x with items
45if hasattr(dict, 'iteritems'):
46 dict_item_iter = 'iteritems'
47else:
48 dict_item_iter = 'items'
49
50
Armin Ronacher821a4232010-02-17 07:59:38 +010051# does if 0: dummy(x) get us x into the scope?
52def unoptimize_before_dead_code():
53 x = 42
54 def f():
55 if 0: dummy(x)
56 return f
Armin Ronacher9dd7fad2013-05-18 11:36:32 +010057
58# The getattr is necessary for pypy which does not set this attribute if
59# no closure is on the function
60unoptimize_before_dead_code = bool(
61 getattr(unoptimize_before_dead_code(), '__closure__', None))
Armin Ronacher821a4232010-02-17 07:59:38 +010062
63
Armin Ronacher64b08a02010-03-12 03:17:41 +010064def generate(node, environment, name, filename, stream=None,
65 defer_init=False):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020066 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020067 if not isinstance(node, nodes.Template):
68 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher64b08a02010-03-12 03:17:41 +010069 generator = CodeGenerator(environment, name, filename, stream, defer_init)
Armin Ronachere791c2a2008-04-07 18:39:54 +020070 generator.visit(node)
71 if stream is None:
72 return generator.stream.getvalue()
73
74
Armin Ronacher4dfc9752008-04-09 15:03:29 +020075def has_safe_repr(value):
76 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020077 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020078 return True
Thomas Waldmann05ace8b2013-05-18 13:14:14 +020079 if isinstance(value, (bool, int, float, complex, xrange, Markup) + six.string_types):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020080 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020081 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020082 for item in value:
83 if not has_safe_repr(item):
84 return False
85 return True
86 elif isinstance(value, dict):
Thomas Waldmanne0003552013-05-17 23:52:14 +020087 for key, value in six.iteritems(value):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020088 if not has_safe_repr(key):
89 return False
90 if not has_safe_repr(value):
91 return False
92 return True
93 return False
94
95
Armin Ronacherc9705c22008-04-27 21:28:03 +020096def find_undeclared(nodes, names):
97 """Check if the names passed are accessed undeclared. The return value
98 is a set of all the undeclared names from the sequence of names found.
99 """
100 visitor = UndeclaredNameVisitor(names)
101 try:
102 for node in nodes:
103 visitor.visit(node)
104 except VisitorExit:
105 pass
106 return visitor.undeclared
107
108
Armin Ronachere791c2a2008-04-07 18:39:54 +0200109class Identifiers(object):
110 """Tracks the status of identifiers in frames."""
111
112 def __init__(self):
113 # variables that are known to be declared (probably from outer
114 # frames or because they are special for the frame)
115 self.declared = set()
116
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200117 # undeclared variables from outer scopes
118 self.outer_undeclared = set()
119
Armin Ronachere791c2a2008-04-07 18:39:54 +0200120 # names that are accessed without being explicitly declared by
121 # this one or any of the outer scopes. Names can appear both in
122 # declared and undeclared.
123 self.undeclared = set()
124
125 # names that are declared locally
126 self.declared_locally = set()
127
128 # names that are declared by parameters
129 self.declared_parameter = set()
130
131 def add_special(self, name):
132 """Register a special name like `loop`."""
133 self.undeclared.discard(name)
134 self.declared.add(name)
135
Armin Ronacherda632622011-03-13 14:33:27 -0400136 def is_declared(self, name):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200137 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200138 if name in self.declared_locally or name in self.declared_parameter:
139 return True
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200140 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200141
Armin Ronacher74230e62009-10-25 12:46:31 +0100142 def copy(self):
143 return deepcopy(self)
144
Armin Ronachere791c2a2008-04-07 18:39:54 +0200145
146class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200147 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200148
Armin Ronacher8346bd72010-03-14 19:43:47 +0100149 def __init__(self, eval_ctx, parent=None):
150 self.eval_ctx = eval_ctx
Armin Ronachere791c2a2008-04-07 18:39:54 +0200151 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200152
Armin Ronacher75cfb862008-04-11 13:47:22 +0200153 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200154 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200155
Armin Ronacher75cfb862008-04-11 13:47:22 +0200156 # the root frame is basically just the outermost frame, so no if
157 # conditions. This information is used to optimize inheritance
158 # situations.
159 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200160
Armin Ronacher79668952008-09-23 22:52:46 +0200161 # in some dynamic inheritance situations the compiler needs to add
162 # write tests around output statements.
163 self.require_output_check = parent and parent.require_output_check
Armin Ronacherf40c8842008-09-17 18:51:26 +0200164
Armin Ronacherfed44b52008-04-13 19:42:53 +0200165 # inside some tags we are using a buffer rather than yield statements.
166 # this for example affects {% filter %} or {% macro %}. If a frame
167 # is buffered this variable points to the name of the list used as
168 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200169 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200170
Armin Ronacherfed44b52008-04-13 19:42:53 +0200171 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200172 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200173
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100174 # a set of actually assigned names
175 self.assigned_names = set()
176
Armin Ronacherfed44b52008-04-13 19:42:53 +0200177 # the parent of this frame
178 self.parent = parent
179
Armin Ronachere791c2a2008-04-07 18:39:54 +0200180 if parent is not None:
181 self.identifiers.declared.update(
182 parent.identifiers.declared |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200183 parent.identifiers.declared_parameter |
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100184 parent.assigned_names
Armin Ronachere791c2a2008-04-07 18:39:54 +0200185 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200186 self.identifiers.outer_undeclared.update(
187 parent.identifiers.undeclared -
188 self.identifiers.declared
189 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200190 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200191
Armin Ronacher8efc5222008-04-08 14:47:40 +0200192 def copy(self):
193 """Create a copy of the current one."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200194 rv = object.__new__(self.__class__)
195 rv.__dict__.update(self.__dict__)
196 rv.identifiers = object.__new__(self.identifiers.__class__)
197 rv.identifiers.__dict__.update(self.identifiers.__dict__)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200198 return rv
199
Armin Ronacherda632622011-03-13 14:33:27 -0400200 def inspect(self, nodes):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200201 """Walk the node and check for identifiers. If the scope is hard (eg:
202 enforce on a python level) overrides from outer scopes are tracked
203 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200204 """
Armin Ronacherda632622011-03-13 14:33:27 -0400205 visitor = FrameIdentifierVisitor(self.identifiers)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200206 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200207 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200208
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100209 def find_shadowed(self, extra=()):
210 """Find all the shadowed names. extra is an iterable of variables
211 that may be defined with `add_special` which may occour scoped.
212 """
213 i = self.identifiers
214 return (i.declared | i.outer_undeclared) & \
215 (i.declared_locally | i.declared_parameter) | \
216 set(x for x in extra if i.is_declared(x))
217
Armin Ronachere791c2a2008-04-07 18:39:54 +0200218 def inner(self):
219 """Return an inner frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100220 return Frame(self.eval_ctx, self)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200221
Armin Ronacher75cfb862008-04-11 13:47:22 +0200222 def soft(self):
223 """Return a soft frame. A soft frame may not be modified as
224 standalone thing as it shares the resources with the frame it
225 was created of, but it's not a rootlevel frame any longer.
226 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200227 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200228 rv.rootlevel = False
229 return rv
230
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200231 __copy__ = copy
232
Armin Ronachere791c2a2008-04-07 18:39:54 +0200233
Armin Ronacherc9705c22008-04-27 21:28:03 +0200234class VisitorExit(RuntimeError):
235 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
236
237
238class DependencyFinderVisitor(NodeVisitor):
239 """A visitor that collects filter and test calls."""
240
241 def __init__(self):
242 self.filters = set()
243 self.tests = set()
244
245 def visit_Filter(self, node):
246 self.generic_visit(node)
247 self.filters.add(node.name)
248
249 def visit_Test(self, node):
250 self.generic_visit(node)
251 self.tests.add(node.name)
252
253 def visit_Block(self, node):
254 """Stop visiting at blocks."""
255
256
257class UndeclaredNameVisitor(NodeVisitor):
258 """A visitor that checks if a name is accessed without being
259 declared. This is different from the frame visitor as it will
260 not stop at closure frames.
261 """
262
263 def __init__(self, names):
264 self.names = set(names)
265 self.undeclared = set()
266
267 def visit_Name(self, node):
268 if node.ctx == 'load' and node.name in self.names:
269 self.undeclared.add(node.name)
270 if self.undeclared == self.names:
271 raise VisitorExit()
272 else:
273 self.names.discard(node.name)
274
275 def visit_Block(self, node):
276 """Stop visiting a blocks."""
277
278
Armin Ronachere791c2a2008-04-07 18:39:54 +0200279class FrameIdentifierVisitor(NodeVisitor):
280 """A visitor for `Frame.inspect`."""
281
Armin Ronacherda632622011-03-13 14:33:27 -0400282 def __init__(self, identifiers):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200283 self.identifiers = identifiers
284
Armin Ronacherc9705c22008-04-27 21:28:03 +0200285 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200286 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200287 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200288 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200289 elif node.ctx == 'param':
290 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200291 elif node.ctx == 'load' and not \
Armin Ronacherda632622011-03-13 14:33:27 -0400292 self.identifiers.is_declared(node.name):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200293 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200294
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200295 def visit_If(self, node):
296 self.visit(node.test)
Armin Ronacher74230e62009-10-25 12:46:31 +0100297 real_identifiers = self.identifiers
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200298
Armin Ronacher8a672512010-04-05 18:43:07 +0200299 old_names = real_identifiers.declared_locally | \
Armin Ronacher74230e62009-10-25 12:46:31 +0100300 real_identifiers.declared_parameter
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200301
Armin Ronacher74230e62009-10-25 12:46:31 +0100302 def inner_visit(nodes):
Armin Ronacher1965e312009-10-25 13:03:08 +0100303 if not nodes:
304 return set()
Armin Ronacher74230e62009-10-25 12:46:31 +0100305 self.identifiers = real_identifiers.copy()
306 for subnode in nodes:
307 self.visit(subnode)
308 rv = self.identifiers.declared_locally - old_names
309 # we have to remember the undeclared variables of this branch
310 # because we will have to pull them.
311 real_identifiers.undeclared.update(self.identifiers.undeclared)
312 self.identifiers = real_identifiers
313 return rv
314
315 body = inner_visit(node.body)
316 else_ = inner_visit(node.else_ or ())
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200317
318 # the differences between the two branches are also pulled as
319 # undeclared variables
Armin Ronacher8a672512010-04-05 18:43:07 +0200320 real_identifiers.undeclared.update(body.symmetric_difference(else_) -
321 real_identifiers.declared)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200322
Armin Ronacher74230e62009-10-25 12:46:31 +0100323 # remember those that are declared.
324 real_identifiers.declared_locally.update(body | else_)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200325
Armin Ronacherc9705c22008-04-27 21:28:03 +0200326 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200327 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200328
Armin Ronacherc9705c22008-04-27 21:28:03 +0200329 def visit_Import(self, node):
330 self.generic_visit(node)
331 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200332
Armin Ronacherc9705c22008-04-27 21:28:03 +0200333 def visit_FromImport(self, node):
334 self.generic_visit(node)
335 for name in node.names:
336 if isinstance(name, tuple):
337 self.identifiers.declared_locally.add(name[1])
338 else:
339 self.identifiers.declared_locally.add(name)
340
341 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200342 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200343 self.visit(node.node)
344 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200345
Armin Ronacherc9705c22008-04-27 21:28:03 +0200346 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200347 """Visiting stops at for blocks. However the block sequence
348 is visited as part of the outer scope.
349 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200350 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200351
Armin Ronacherc9705c22008-04-27 21:28:03 +0200352 def visit_CallBlock(self, node):
Armin Ronacheref189442010-01-14 01:26:40 +0100353 self.visit(node.call)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200354
355 def visit_FilterBlock(self, node):
356 self.visit(node.filter)
357
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100358 def visit_Scope(self, node):
359 """Stop visiting at scopes."""
360
Armin Ronacherc9705c22008-04-27 21:28:03 +0200361 def visit_Block(self, node):
362 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200363
364
Armin Ronacher75cfb862008-04-11 13:47:22 +0200365class CompilerExit(Exception):
366 """Raised if the compiler encountered a situation where it just
367 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200368 raises such an exception is not further processed.
369 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200370
371
Armin Ronachere791c2a2008-04-07 18:39:54 +0200372class CodeGenerator(NodeVisitor):
373
Armin Ronacher64b08a02010-03-12 03:17:41 +0100374 def __init__(self, environment, name, filename, stream=None,
375 defer_init=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200376 if stream is None:
377 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200378 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200379 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200380 self.filename = filename
381 self.stream = stream
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100382 self.created_block_context = False
Armin Ronacher64b08a02010-03-12 03:17:41 +0100383 self.defer_init = defer_init
Armin Ronacherfed44b52008-04-13 19:42:53 +0200384
Armin Ronacher023b5e92008-05-08 11:03:10 +0200385 # aliases for imports
386 self.import_aliases = {}
387
Armin Ronacherfed44b52008-04-13 19:42:53 +0200388 # a registry for all blocks. Because blocks are moved out
389 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200390 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200391
392 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200393 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200394
395 # some templates have a rootlevel extends. In this case we
396 # can safely assume that we're a child template and do some
397 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200398 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200399
Armin Ronacherba3757b2008-04-16 19:43:16 +0200400 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200401 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200402
Armin Ronacherb9e78752008-05-10 23:36:28 +0200403 # registry of all filters and tests (global, not block local)
404 self.tests = {}
405 self.filters = {}
406
Armin Ronacherba3757b2008-04-16 19:43:16 +0200407 # the debug information
408 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200409 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200410
Armin Ronacherfed44b52008-04-13 19:42:53 +0200411 # the number of new lines before the next write()
412 self._new_lines = 0
413
414 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200415 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200416
417 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200418 self._first_write = True
419
Armin Ronacherfed44b52008-04-13 19:42:53 +0200420 # used by the `temporary_identifier` method to get new
421 # unique, temporary identifier
422 self._last_identifier = 0
423
424 # the current indentation
425 self._indentation = 0
426
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200427 # -- Various compilation helpers
428
Armin Ronachere2244882008-05-19 09:25:57 +0200429 def fail(self, msg, lineno):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100430 """Fail with a :exc:`TemplateAssertionError`."""
Armin Ronachere2244882008-05-19 09:25:57 +0200431 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
432
Armin Ronachere791c2a2008-04-07 18:39:54 +0200433 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200434 """Get a new unique identifier."""
435 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200436 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200437
Armin Ronachered1e0d42008-05-18 20:25:28 +0200438 def buffer(self, frame):
439 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200440 frame.buffer = self.temporary_identifier()
441 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200442
443 def return_buffer_contents(self, frame):
444 """Return the buffer contents of the frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100445 if frame.eval_ctx.volatile:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100446 self.writeline('if context.eval_ctx.autoescape:')
447 self.indent()
448 self.writeline('return Markup(concat(%s))' % frame.buffer)
449 self.outdent()
450 self.writeline('else:')
451 self.indent()
452 self.writeline('return concat(%s)' % frame.buffer)
453 self.outdent()
Armin Ronacher8346bd72010-03-14 19:43:47 +0100454 elif frame.eval_ctx.autoescape:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100455 self.writeline('return Markup(concat(%s))' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200456 else:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100457 self.writeline('return concat(%s)' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200458
Armin Ronachere791c2a2008-04-07 18:39:54 +0200459 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200460 """Indent by one."""
461 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200462
Armin Ronacher8efc5222008-04-08 14:47:40 +0200463 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200464 """Outdent by step."""
465 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200466
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200467 def start_write(self, frame, node=None):
468 """Yield or write into the frame buffer."""
469 if frame.buffer is None:
470 self.writeline('yield ', node)
471 else:
472 self.writeline('%s.append(' % frame.buffer, node)
473
474 def end_write(self, frame):
475 """End the writing process started by `start_write`."""
476 if frame.buffer is not None:
477 self.write(')')
478
479 def simple_write(self, s, frame, node=None):
480 """Simple shortcut for start_write + write + end_write."""
481 self.start_write(frame, node)
482 self.write(s)
483 self.end_write(frame)
484
Armin Ronacherf40c8842008-09-17 18:51:26 +0200485 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200486 """Visit a list of nodes as block in a frame. If the current frame
487 is no buffer a dummy ``if 0: yield None`` is written automatically
488 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200489 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200490 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200491 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200492 else:
493 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200494 try:
495 for node in nodes:
496 self.visit(node, frame)
497 except CompilerExit:
498 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200499
500 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200501 """Write a string into the output stream."""
502 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200503 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200504 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200505 self.code_lineno += self._new_lines
506 if self._write_debug_info is not None:
507 self.debug_info.append((self._write_debug_info,
508 self.code_lineno))
509 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200510 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200511 self.stream.write(' ' * self._indentation)
512 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200513 self.stream.write(x)
514
515 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200516 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200517 self.newline(node, extra)
518 self.write(x)
519
520 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200521 """Add one or more newlines before the next write."""
522 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200523 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200524 self._write_debug_info = node.lineno
525 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200526
Armin Ronacherfd310492008-05-25 00:16:51 +0200527 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200528 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200529 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200530 arguments may not include python keywords otherwise a syntax
531 error could occour. The extra keyword arguments should be given
532 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200533 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200534 # if any of the given keyword arguments is a python keyword
535 # we have to make sure that no invalid call is created.
536 kwarg_workaround = False
537 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200538 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200539 kwarg_workaround = True
540 break
541
Armin Ronacher8efc5222008-04-08 14:47:40 +0200542 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200543 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200544 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200545
546 if not kwarg_workaround:
547 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200548 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200549 self.visit(kwarg, frame)
550 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200551 for key, value in six.iteritems(extra_kwargs):
Armin Ronacherfd310492008-05-25 00:16:51 +0200552 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200553 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200554 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200555 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200556
557 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200558 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200559 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200560 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200561 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200562 for kwarg in node.kwargs:
563 self.write('%r: ' % kwarg.key)
564 self.visit(kwarg.value, frame)
565 self.write(', ')
566 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200567 for key, value in six.iteritems(extra_kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200568 self.write('%r: %s, ' % (key, value))
569 if node.dyn_kwargs is not None:
570 self.write('}, **')
571 self.visit(node.dyn_kwargs, frame)
572 self.write(')')
573 else:
574 self.write('}')
575
576 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200577 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200578 self.visit(node.dyn_kwargs, frame)
579
Armin Ronacherc9705c22008-04-27 21:28:03 +0200580 def pull_locals(self, frame):
581 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200582 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200583 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200584
585 def pull_dependencies(self, nodes):
586 """Pull all the dependencies."""
587 visitor = DependencyFinderVisitor()
588 for node in nodes:
589 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200590 for dependency in 'filters', 'tests':
591 mapping = getattr(self, dependency)
592 for name in getattr(visitor, dependency):
593 if name not in mapping:
594 mapping[name] = self.temporary_identifier()
595 self.writeline('%s = environment.%s[%r]' %
596 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200597
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100598 def unoptimize_scope(self, frame):
599 """Disable Python optimizations for the frame."""
600 # XXX: this is not that nice but it has no real overhead. It
601 # mainly works because python finds the locals before dead code
602 # is removed. If that breaks we have to add a dummy function
603 # that just accepts the arguments and does nothing.
604 if frame.identifiers.declared:
Armin Ronacher821a4232010-02-17 07:59:38 +0100605 self.writeline('%sdummy(%s)' % (
606 unoptimize_before_dead_code and 'if 0: ' or '',
607 ', '.join('l_' + name for name in frame.identifiers.declared)
608 ))
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100609
Armin Ronacher673aa882008-10-04 18:06:57 +0200610 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200611 """This function returns all the shadowed variables in a dict
612 in the form name: alias and will write the required assignments
613 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200614
Armin Ronacher673aa882008-10-04 18:06:57 +0200615 This also predefines locally declared variables from the loop
616 body because under some circumstances it may be the case that
617
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100618 `extra_vars` is passed to `Frame.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200619 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200620 aliases = {}
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100621 for name in frame.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200622 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200623 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200624 to_declare = set()
625 for name in frame.identifiers.declared_locally:
626 if name not in aliases:
627 to_declare.add('l_' + name)
628 if to_declare:
629 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200630 return aliases
631
Armin Ronacher673aa882008-10-04 18:06:57 +0200632 def pop_scope(self, aliases, frame):
633 """Restore all aliases and delete unused variables."""
Thomas Waldmanne0003552013-05-17 23:52:14 +0200634 for name, alias in six.iteritems(aliases):
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200635 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200636 to_delete = set()
637 for name in frame.identifiers.declared_locally:
638 if name not in aliases:
639 to_delete.add('l_' + name)
640 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100641 # we cannot use the del statement here because enclosed
642 # scopes can trigger a SyntaxError:
643 # a = 42; b = lambda: a; del a
644 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200645
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200646 def function_scoping(self, node, frame, children=None,
647 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200648 """In Jinja a few statements require the help of anonymous
649 functions. Those are currently macros and call blocks and in
650 the future also recursive loops. As there is currently
651 technical limitation that doesn't allow reading and writing a
652 variable in a scope where the initial value is coming from an
653 outer scope, this function tries to fall back with a common
654 error message. Additionally the frame passed is modified so
655 that the argumetns are collected and callers are looked up.
656
657 This will return the modified frame.
658 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200659 # we have to iterate twice over it, make sure that works
660 if children is None:
661 children = node.iter_child_nodes()
662 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200663 func_frame = frame.inner()
Armin Ronacherda632622011-03-13 14:33:27 -0400664 func_frame.inspect(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200665
666 # variables that are undeclared (accessed before declaration) and
667 # declared locally *and* part of an outside scope raise a template
668 # assertion error. Reason: we can't generate reasonable code from
Armin Ronacher02b42a82009-03-18 00:59:32 +0100669 # it without aliasing all the variables.
670 # this could be fixed in Python 3 where we have the nonlocal
671 # keyword or if we switch to bytecode generation
Armin Ronacher71082072008-04-12 14:19:36 +0200672 overriden_closure_vars = (
673 func_frame.identifiers.undeclared &
674 func_frame.identifiers.declared &
675 (func_frame.identifiers.declared_locally |
676 func_frame.identifiers.declared_parameter)
677 )
678 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200679 self.fail('It\'s not possible to set and access variables '
Armin Ronacherefcc0e52009-09-13 00:22:50 -0700680 'derived from an outer scope! (affects: %s)' %
Armin Ronachere2244882008-05-19 09:25:57 +0200681 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200682
683 # remove variables from a closure from the frame's undeclared
684 # identifiers.
685 func_frame.identifiers.undeclared -= (
686 func_frame.identifiers.undeclared &
687 func_frame.identifiers.declared
688 )
689
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200690 # no special variables for this scope, abort early
691 if not find_special:
692 return func_frame
693
Armin Ronacher963f97d2008-04-25 11:44:59 +0200694 func_frame.accesses_kwargs = False
695 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200696 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200697 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200698
Armin Ronacherc9705c22008-04-27 21:28:03 +0200699 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
700
701 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200702 func_frame.accesses_caller = True
703 func_frame.identifiers.add_special('caller')
704 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200705 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200706 func_frame.accesses_kwargs = True
707 func_frame.identifiers.add_special('kwargs')
708 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200709 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200710 func_frame.accesses_varargs = True
711 func_frame.identifiers.add_special('varargs')
712 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200713 return func_frame
714
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200715 def macro_body(self, node, frame, children=None):
716 """Dump the function def of a macro or call block."""
717 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100718 # macros are delayed, they never require output checks
719 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200720 args = frame.arguments
Armin Ronachereabf3dd2009-09-12 23:48:18 -0700721 # XXX: this is an ugly fix for the loop nesting bug
722 # (tests.test_old_bugs.test_loop_call_bug). This works around
723 # a identifier nesting problem we have in general. It's just more
724 # likely to happen in loops which is why we work around it. The
725 # real solution would be "nonlocal" all the identifiers that are
726 # leaking into a new python frame and might be used both unassigned
727 # and assigned.
728 if 'loop' in frame.identifiers.declared:
Armin Ronacherb4044392009-09-13 15:56:58 -0700729 args = args + ['l_loop=l_loop']
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200730 self.writeline('def macro(%s):' % ', '.join(args), node)
731 self.indent()
732 self.buffer(frame)
733 self.pull_locals(frame)
734 self.blockvisit(node.body, frame)
735 self.return_buffer_contents(frame)
736 self.outdent()
737 return frame
738
739 def macro_def(self, node, frame):
740 """Dump the macro definition for the def created by macro_body."""
741 arg_tuple = ', '.join(repr(x.name) for x in node.args)
742 name = getattr(node, 'name', None)
743 if len(node.args) == 1:
744 arg_tuple += ','
745 self.write('Macro(environment, macro, %r, (%s), (' %
746 (name, arg_tuple))
747 for arg in node.defaults:
748 self.visit(arg, frame)
749 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200750 self.write('), %r, %r, %r)' % (
751 bool(frame.accesses_kwargs),
752 bool(frame.accesses_varargs),
753 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200754 ))
755
Armin Ronacher547d0b62008-07-04 16:35:10 +0200756 def position(self, node):
757 """Return a human readable position for the node."""
758 rv = 'line %d' % node.lineno
759 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100760 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200761 return rv
762
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200763 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200764
765 def visit_Template(self, node, frame=None):
766 assert frame is None, 'no root frame allowed'
Armin Ronacher1da23d12010-04-05 18:11:18 +0200767 eval_ctx = EvalContext(self.environment, self.name)
Armin Ronacher8346bd72010-03-14 19:43:47 +0100768
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200769 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200770 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200771 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher821a4232010-02-17 07:59:38 +0100772 if not unoptimize_before_dead_code:
773 self.writeline('dummy = lambda *x: None')
Armin Ronacher8edbe492008-04-10 20:43:43 +0200774
Armin Ronacher64b08a02010-03-12 03:17:41 +0100775 # if we want a deferred initialization we cannot move the
776 # environment into a local name
777 envenv = not self.defer_init and ', environment=environment' or ''
778
Armin Ronacher75cfb862008-04-11 13:47:22 +0200779 # do we have an extends tag at all? If not, we can save some
780 # overhead by just not processing any inheritance code.
781 have_extends = node.find(nodes.Extends) is not None
782
Armin Ronacher8edbe492008-04-10 20:43:43 +0200783 # find all blocks
784 for block in node.find_all(nodes.Block):
785 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200786 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200787 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200788
Armin Ronacher023b5e92008-05-08 11:03:10 +0200789 # find all imports and import them
790 for import_ in node.find_all(nodes.ImportedName):
791 if import_.importname not in self.import_aliases:
792 imp = import_.importname
793 self.import_aliases[imp] = alias = self.temporary_identifier()
794 if '.' in imp:
795 module, obj = imp.rsplit('.', 1)
796 self.writeline('from %s import %s as %s' %
797 (module, obj, alias))
798 else:
799 self.writeline('import %s as %s' % (imp, alias))
800
801 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200802 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200803
Armin Ronacher8efc5222008-04-08 14:47:40 +0200804 # generate the root render function.
Armin Ronacher64b08a02010-03-12 03:17:41 +0100805 self.writeline('def root(context%s):' % envenv, extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200806
807 # process the root
Armin Ronacher8346bd72010-03-14 19:43:47 +0100808 frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200809 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200810 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200811 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200812 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200813 if have_extends:
814 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200815 if 'self' in find_undeclared(node.body, ('self',)):
816 frame.identifiers.add_special('self')
817 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200818 self.pull_locals(frame)
819 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200820 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200821 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200822
Armin Ronacher8efc5222008-04-08 14:47:40 +0200823 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200824 if have_extends:
825 if not self.has_known_extends:
826 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200827 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200828 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200829 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200830 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200831 self.indent()
832 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200833 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200834
835 # at this point we now have the blocks collected and can visit them too.
Thomas Waldmanne0003552013-05-17 23:52:14 +0200836 for name, block in six.iteritems(self.blocks):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100837 block_frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200838 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200839 block_frame.block = name
Armin Ronacher64b08a02010-03-12 03:17:41 +0100840 self.writeline('def block_%s(context%s):' % (name, envenv),
841 block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200842 self.indent()
843 undeclared = find_undeclared(block.body, ('self', 'super'))
844 if 'self' in undeclared:
845 block_frame.identifiers.add_special('self')
846 self.writeline('l_self = TemplateReference(context)')
847 if 'super' in undeclared:
848 block_frame.identifiers.add_special('super')
849 self.writeline('l_super = context.super(%r, '
850 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200851 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200852 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200853 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200854 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200855
Armin Ronacher75cfb862008-04-11 13:47:22 +0200856 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200857 for x in self.blocks),
858 extra=1)
859
860 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200861 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
862 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200863
Armin Ronachere791c2a2008-04-07 18:39:54 +0200864 def visit_Block(self, node, frame):
865 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200866 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200867 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200868 # if we know that we are a child template, there is no need to
869 # check if we are one
870 if self.has_known_extends:
871 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200872 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200873 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200874 self.indent()
875 level += 1
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100876 context = node.scoped and 'context.derived(locals())' or 'context'
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100877 self.writeline('for event in context.blocks[%r][0](%s):' % (
878 node.name, context), node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200879 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200880 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200881 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200882
883 def visit_Extends(self, node, frame):
884 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200885 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200886 self.fail('cannot use extend from a non top-level scope',
887 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200888
Armin Ronacher7fb38972008-04-11 13:54:28 +0200889 # if the number of extends statements in general is zero so
890 # far, we don't have to add a check if something extended
891 # the template before this one.
892 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200893
Armin Ronacher7fb38972008-04-11 13:54:28 +0200894 # if we have a known extends we just add a template runtime
895 # error into the generated code. We could catch that at compile
896 # time too, but i welcome it not to confuse users by throwing the
897 # same error at different times just "because we can".
898 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200899 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200900 self.indent()
901 self.writeline('raise TemplateRuntimeError(%r)' %
902 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200903 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200904
Armin Ronacher7fb38972008-04-11 13:54:28 +0200905 # if we have a known extends already we don't need that code here
906 # as we know that the template execution will end here.
907 if self.has_known_extends:
908 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200909
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200910 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200911 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200912 self.write(', %r)' % self.name)
913 self.writeline('for name, parent_block in parent_template.'
Armin Ronacher0d242be2010-02-10 01:35:13 +0100914 'blocks.%s():' % dict_item_iter)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200915 self.indent()
916 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200917 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200918 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200919
920 # if this extends statement was in the root level we can take
921 # advantage of that information and simplify the generated code
922 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200923 if frame.rootlevel:
924 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200925
Armin Ronacher7fb38972008-04-11 13:54:28 +0200926 # and now we have one more
927 self.extends_so_far += 1
928
Armin Ronacherf059ec12008-04-11 22:21:00 +0200929 def visit_Include(self, node, frame):
930 """Handles includes."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100931 if node.with_context:
932 self.unoptimize_scope(frame)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100933 if node.ignore_missing:
934 self.writeline('try:')
935 self.indent()
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100936
937 func_name = 'get_or_select_template'
938 if isinstance(node.template, nodes.Const):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200939 if isinstance(node.template.value, six.string_types):
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100940 func_name = 'get_template'
941 elif isinstance(node.template.value, (tuple, list)):
942 func_name = 'select_template'
943 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
944 func_name = 'select_template'
945
946 self.writeline('template = environment.%s(' % func_name, node)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100947 self.visit(node.template, frame)
948 self.write(', %r)' % self.name)
949 if node.ignore_missing:
950 self.outdent()
951 self.writeline('except TemplateNotFound:')
952 self.indent()
953 self.writeline('pass')
954 self.outdent()
955 self.writeline('else:')
956 self.indent()
957
Armin Ronacherea847c52008-05-02 20:04:32 +0200958 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200959 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200960 'template.new_context(context.parent, True, '
961 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200962 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100963 self.writeline('for event in template.module._body_stream:')
964
Armin Ronacherf059ec12008-04-11 22:21:00 +0200965 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200966 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200967 self.outdent()
968
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100969 if node.ignore_missing:
970 self.outdent()
971
Armin Ronacher0611e492008-04-25 23:44:14 +0200972 def visit_Import(self, node, frame):
973 """Visit regular imports."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100974 if node.with_context:
975 self.unoptimize_scope(frame)
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200976 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200977 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200978 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200979 self.write('environment.get_template(')
980 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200981 self.write(', %r).' % self.name)
982 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200983 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200984 else:
985 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200986 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200987 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100988 frame.assigned_names.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200989
990 def visit_FromImport(self, node, frame):
991 """Visit named imports."""
992 self.newline(node)
993 self.write('included_template = environment.get_template(')
994 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200995 self.write(', %r).' % self.name)
996 if node.with_context:
997 self.write('make_module(context.parent, True)')
998 else:
999 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +02001000
1001 var_names = []
1002 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +02001003 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +02001004 if isinstance(name, tuple):
1005 name, alias = name
1006 else:
1007 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001008 self.writeline('l_%s = getattr(included_template, '
1009 '%r, missing)' % (alias, name))
1010 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +02001011 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001012 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +02001013 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +02001014 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001015 (alias, 'the template %%r (imported on %s) does '
1016 'not export the requested name %s' % (
1017 self.position(node),
1018 repr(name)
1019 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +02001020 self.outdent()
1021 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +02001022 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +02001023 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +02001024 discarded_names.append(alias)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001025 frame.assigned_names.add(alias)
Armin Ronachera78d2762008-05-15 23:18:07 +02001026
1027 if var_names:
1028 if len(var_names) == 1:
1029 name = var_names[0]
1030 self.writeline('context.vars[%r] = l_%s' % (name, name))
1031 else:
1032 self.writeline('context.vars.update({%s})' % ', '.join(
1033 '%r: l_%s' % (name, name) for name in var_names
1034 ))
1035 if discarded_names:
1036 if len(discarded_names) == 1:
1037 self.writeline('context.exported_vars.discard(%r)' %
1038 discarded_names[0])
1039 else:
1040 self.writeline('context.exported_vars.difference_'
1041 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +02001042
Armin Ronachere791c2a2008-04-07 18:39:54 +02001043 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001044 # when calculating the nodes for the inner frame we have to exclude
1045 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001046 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001047 if node.recursive:
1048 loop_frame = self.function_scoping(node, frame, children,
1049 find_special=False)
1050 else:
1051 loop_frame = frame.inner()
1052 loop_frame.inspect(children)
1053
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001054 # try to figure out if we have an extended loop. An extended loop
1055 # is necessary if the loop is in recursive mode if the special loop
1056 # variable is accessed in the body.
1057 extended_loop = node.recursive or 'loop' in \
1058 find_undeclared(node.iter_child_nodes(
1059 only=('body',)), ('loop',))
1060
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001061 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +02001062 # variables at that point. Because loops can be nested but the loop
1063 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001064 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +02001065 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001066
1067 # otherwise we set up a buffer and add a function def
1068 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001069 self.writeline('def loop(reciter, loop_render_func):', node)
1070 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +02001071 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001072 aliases = {}
1073
Armin Ronacherff53c782008-08-13 18:55:50 +02001074 # make sure the loop variable is a special one and raise a template
1075 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +02001076 if extended_loop:
1077 loop_frame.identifiers.add_special('loop')
Armin Ronacherff53c782008-08-13 18:55:50 +02001078 for name in node.find_all(nodes.Name):
1079 if name.ctx == 'store' and name.name == 'loop':
1080 self.fail('Can\'t assign to special loop variable '
1081 'in for-loop target', name.lineno)
1082
Armin Ronacherc9705c22008-04-27 21:28:03 +02001083 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001084 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001085 iteration_indicator = self.temporary_identifier()
1086 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001087
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001088 # Create a fake parent loop if the else or test section of a
1089 # loop is accessing the special loop variable and no parent loop
1090 # exists.
1091 if 'loop' not in aliases and 'loop' in find_undeclared(
1092 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1093 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001094 ("'loop' is undefined. the filter section of a loop as well "
Armin Ronacherbc56cd22011-01-15 18:35:45 +01001095 "as the else block don't have access to the special 'loop'"
Armin Ronacher547d0b62008-07-04 16:35:10 +02001096 " variable of the current loop. Because there is no parent "
1097 "loop it's undefined. Happened in loop on %s" %
1098 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001099
1100 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001101 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +02001102 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001103
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001104 # if we have an extened loop and a node test, we filter in the
1105 # "outer frame".
1106 if extended_loop and node.test is not None:
1107 self.write('(')
1108 self.visit(node.target, loop_frame)
1109 self.write(' for ')
1110 self.visit(node.target, loop_frame)
1111 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001112 if node.recursive:
1113 self.write('reciter')
1114 else:
1115 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001116 self.write(' if (')
1117 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001118 self.visit(node.test, test_frame)
1119 self.write('))')
1120
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001121 elif node.recursive:
1122 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001123 else:
1124 self.visit(node.iter, loop_frame)
1125
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001126 if node.recursive:
1127 self.write(', recurse=loop_render_func):')
1128 else:
1129 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001130
1131 # tests in not extended loops become a continue
1132 if not extended_loop and node.test is not None:
1133 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +02001134 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +02001135 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001136 self.write(':')
1137 self.indent()
1138 self.writeline('continue')
1139 self.outdent(2)
1140
Armin Ronacherc9705c22008-04-27 21:28:03 +02001141 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001142 self.blockvisit(node.body, loop_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001143 if node.else_:
1144 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001145 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001146
1147 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001148 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001149 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001150 self.blockvisit(node.else_, loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001151 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001152
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001153 # reset the aliases if there are any.
Armin Ronachercebd8382008-12-25 18:33:46 +01001154 if not node.recursive:
1155 self.pop_scope(aliases, loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001156
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001157 # if the node was recursive we have to return the buffer contents
1158 # and start the iteration code
1159 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001160 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001161 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001162 self.start_write(frame, node)
1163 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001164 self.visit(node.iter, frame)
1165 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001166 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001167
Armin Ronachere791c2a2008-04-07 18:39:54 +02001168 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001169 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001170 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001171 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001172 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001173 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001174 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001175 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001176 if node.else_:
1177 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001178 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001179 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001180 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001181
Armin Ronacher8efc5222008-04-08 14:47:40 +02001182 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001183 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001184 self.newline()
1185 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001186 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001187 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001188 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001189 self.write('l_%s = ' % node.name)
1190 self.macro_def(node, macro_frame)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001191 frame.assigned_names.add(node.name)
Armin Ronacher71082072008-04-12 14:19:36 +02001192
1193 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001194 children = node.iter_child_nodes(exclude=('call',))
1195 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001196 self.writeline('caller = ')
1197 self.macro_def(node, call_frame)
1198 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001199 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001200 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001201
1202 def visit_FilterBlock(self, node, frame):
1203 filter_frame = frame.inner()
1204 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacher673aa882008-10-04 18:06:57 +02001205 aliases = self.push_scope(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001206 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001207 self.buffer(filter_frame)
Armin Ronacherf40c8842008-09-17 18:51:26 +02001208 self.blockvisit(node.body, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001209 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001210 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001211 self.end_write(frame)
Armin Ronacher673aa882008-10-04 18:06:57 +02001212 self.pop_scope(aliases, filter_frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001213
Armin Ronachere791c2a2008-04-07 18:39:54 +02001214 def visit_ExprStmt(self, node, frame):
1215 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001216 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001217
1218 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001219 # if we have a known extends statement, we don't output anything
Armin Ronacher79668952008-09-23 22:52:46 +02001220 # if we are in a require_output_check section
1221 if self.has_known_extends and frame.require_output_check:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001222 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001223
Armin Ronacher665bfb82008-07-14 13:41:46 +02001224 if self.environment.finalize:
Thomas Waldmanne0003552013-05-17 23:52:14 +02001225 finalize = lambda x: six.text_type(self.environment.finalize(x))
Armin Ronacher665bfb82008-07-14 13:41:46 +02001226 else:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001227 finalize = six.text_type
Armin Ronacher665bfb82008-07-14 13:41:46 +02001228
Armin Ronacher79668952008-09-23 22:52:46 +02001229 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001230 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001231 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001232 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001233 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001234 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001235
Armin Ronachere791c2a2008-04-07 18:39:54 +02001236 # try to evaluate as many chunks as possible into a static
1237 # string at compile time.
1238 body = []
1239 for child in node.nodes:
1240 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001241 const = child.as_const(frame.eval_ctx)
Armin Ronacher9cf95912008-05-24 19:54:43 +02001242 except nodes.Impossible:
1243 body.append(child)
1244 continue
Armin Ronacher8346bd72010-03-14 19:43:47 +01001245 # the frame can't be volatile here, becaus otherwise the
1246 # as_const() function would raise an Impossible exception
1247 # at that point.
Armin Ronacher9cf95912008-05-24 19:54:43 +02001248 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001249 if frame.eval_ctx.autoescape:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001250 if hasattr(const, '__html__'):
1251 const = const.__html__()
1252 else:
1253 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001254 const = finalize(const)
Ian Lewisab014bd2010-10-31 20:29:28 +09001255 except Exception:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001256 # if something goes wrong here we evaluate the node
1257 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001258 body.append(child)
1259 continue
1260 if body and isinstance(body[-1], list):
1261 body[-1].append(const)
1262 else:
1263 body.append([const])
1264
Armin Ronachered1e0d42008-05-18 20:25:28 +02001265 # if we have less than 3 nodes or a buffer we yield or extend/append
1266 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001267 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001268 # for one item we append, for more we extend
1269 if len(body) == 1:
1270 self.writeline('%s.append(' % frame.buffer)
1271 else:
1272 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001273 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001274 for item in body:
1275 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001276 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001277 if frame.buffer is None:
1278 self.writeline('yield ' + val)
1279 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001280 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001281 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001282 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001283 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001284 else:
1285 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001286 close = 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001287 if frame.eval_ctx.volatile:
1288 self.write('(context.eval_ctx.autoescape and'
1289 ' escape or to_string)(')
1290 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001291 self.write('escape(')
1292 else:
Armin Ronacherbd357722009-08-05 20:25:06 +02001293 self.write('to_string(')
Armin Ronacherd1342312008-04-28 12:20:12 +02001294 if self.environment.finalize is not None:
1295 self.write('environment.finalize(')
1296 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001297 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001298 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001299 if frame.buffer is not None:
1300 self.write(', ')
1301 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001302 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001303 self.outdent()
1304 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001305
1306 # otherwise we create a format string as this is faster in that case
1307 else:
1308 format = []
1309 arguments = []
1310 for item in body:
1311 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001312 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001313 else:
1314 format.append('%s')
1315 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001316 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001317 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001318 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001319 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001320 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001321 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001322 close = 0
Armin Ronacher8346bd72010-03-14 19:43:47 +01001323 if frame.eval_ctx.volatile:
1324 self.write('(context.eval_ctx.autoescape and'
1325 ' escape or to_string)(')
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001326 close += 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001327 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001328 self.write('escape(')
1329 close += 1
1330 if self.environment.finalize is not None:
1331 self.write('environment.finalize(')
1332 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001333 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001334 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001335 self.outdent()
1336 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001337
Armin Ronacher7fb38972008-04-11 13:54:28 +02001338 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001339 self.outdent()
1340
Armin Ronacher8efc5222008-04-08 14:47:40 +02001341 def visit_Assign(self, node, frame):
1342 self.newline(node)
1343 # toplevel assignments however go into the local namespace and
1344 # the current template's context. We create a copy of the frame
1345 # here and add a set so that the Name visitor can add the assigned
1346 # names here.
1347 if frame.toplevel:
1348 assignment_frame = frame.copy()
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001349 assignment_frame.toplevel_assignments = set()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001350 else:
1351 assignment_frame = frame
1352 self.visit(node.target, assignment_frame)
1353 self.write(' = ')
1354 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001355
1356 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001357 if frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001358 public_names = [x for x in assignment_frame.toplevel_assignments
Armin Ronacher903d1682008-05-23 00:51:58 +02001359 if not x.startswith('_')]
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001360 if len(assignment_frame.toplevel_assignments) == 1:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001361 name = six.advance_iterator(iter(assignment_frame.toplevel_assignments))
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001362 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001363 else:
1364 self.writeline('context.vars.update({')
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001365 for idx, name in enumerate(assignment_frame.toplevel_assignments):
Armin Ronacher69e12db2008-05-12 09:00:03 +02001366 if idx:
1367 self.write(', ')
1368 self.write('%r: l_%s' % (name, name))
1369 self.write('})')
1370 if public_names:
1371 if len(public_names) == 1:
1372 self.writeline('context.exported_vars.add(%r)' %
1373 public_names[0])
1374 else:
1375 self.writeline('context.exported_vars.update((%s))' %
1376 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001377
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001378 # -- Expression Visitors
1379
Armin Ronachere791c2a2008-04-07 18:39:54 +02001380 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001381 if node.ctx == 'store' and frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001382 frame.toplevel_assignments.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001383 self.write('l_' + node.name)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001384 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001385
1386 def visit_Const(self, node, frame):
1387 val = node.value
1388 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001389 self.write(str(val))
1390 else:
1391 self.write(repr(val))
1392
Armin Ronacher5411ce72008-05-25 11:36:22 +02001393 def visit_TemplateData(self, node, frame):
Armin Ronacherffaa2e72010-05-29 20:57:16 +02001394 try:
1395 self.write(repr(node.as_const(frame.eval_ctx)))
1396 except nodes.Impossible:
1397 self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)'
1398 % node.data)
Armin Ronacher5411ce72008-05-25 11:36:22 +02001399
Armin Ronacher8efc5222008-04-08 14:47:40 +02001400 def visit_Tuple(self, node, frame):
1401 self.write('(')
1402 idx = -1
1403 for idx, item in enumerate(node.items):
1404 if idx:
1405 self.write(', ')
1406 self.visit(item, frame)
1407 self.write(idx == 0 and ',)' or ')')
1408
Armin Ronacher8edbe492008-04-10 20:43:43 +02001409 def visit_List(self, node, frame):
1410 self.write('[')
1411 for idx, item in enumerate(node.items):
1412 if idx:
1413 self.write(', ')
1414 self.visit(item, frame)
1415 self.write(']')
1416
1417 def visit_Dict(self, node, frame):
1418 self.write('{')
1419 for idx, item in enumerate(node.items):
1420 if idx:
1421 self.write(', ')
1422 self.visit(item.key, frame)
1423 self.write(': ')
1424 self.visit(item.value, frame)
1425 self.write('}')
1426
Armin Ronachera9195382010-11-29 13:21:57 +01001427 def binop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001428 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001429 if self.environment.sandboxed and \
1430 operator in self.environment.intercepted_binops:
1431 self.write('environment.call_binop(context, %r, ' % operator)
1432 self.visit(node.left, frame)
1433 self.write(', ')
1434 self.visit(node.right, frame)
1435 else:
1436 self.write('(')
1437 self.visit(node.left, frame)
1438 self.write(' %s ' % operator)
1439 self.visit(node.right, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001440 self.write(')')
1441 return visitor
1442
Armin Ronachera9195382010-11-29 13:21:57 +01001443 def uaop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001444 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001445 if self.environment.sandboxed and \
1446 operator in self.environment.intercepted_unops:
1447 self.write('environment.call_unop(context, %r, ' % operator)
1448 self.visit(node.node, frame)
1449 else:
1450 self.write('(' + operator)
1451 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001452 self.write(')')
1453 return visitor
1454
1455 visit_Add = binop('+')
1456 visit_Sub = binop('-')
1457 visit_Mul = binop('*')
1458 visit_Div = binop('/')
1459 visit_FloorDiv = binop('//')
1460 visit_Pow = binop('**')
1461 visit_Mod = binop('%')
Armin Ronachera9195382010-11-29 13:21:57 +01001462 visit_And = binop('and', interceptable=False)
1463 visit_Or = binop('or', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001464 visit_Pos = uaop('+')
1465 visit_Neg = uaop('-')
Armin Ronachera9195382010-11-29 13:21:57 +01001466 visit_Not = uaop('not ', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001467 del binop, uaop
1468
Armin Ronacherd1342312008-04-28 12:20:12 +02001469 def visit_Concat(self, node, frame):
Armin Ronacher8346bd72010-03-14 19:43:47 +01001470 if frame.eval_ctx.volatile:
1471 func_name = '(context.eval_ctx.volatile and' \
1472 ' markup_join or unicode_join)'
1473 elif frame.eval_ctx.autoescape:
1474 func_name = 'markup_join'
1475 else:
1476 func_name = 'unicode_join'
1477 self.write('%s((' % func_name)
Armin Ronacherd1342312008-04-28 12:20:12 +02001478 for arg in node.nodes:
1479 self.visit(arg, frame)
1480 self.write(', ')
1481 self.write('))')
1482
Armin Ronachere791c2a2008-04-07 18:39:54 +02001483 def visit_Compare(self, node, frame):
1484 self.visit(node.expr, frame)
1485 for op in node.ops:
1486 self.visit(op, frame)
1487
1488 def visit_Operand(self, node, frame):
1489 self.write(' %s ' % operators[node.op])
1490 self.visit(node.expr, frame)
1491
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001492 def visit_Getattr(self, node, frame):
1493 self.write('environment.getattr(')
1494 self.visit(node.node, frame)
1495 self.write(', %r)' % node.attr)
1496
1497 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001498 # slices bypass the environment getitem method.
1499 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001500 self.visit(node.node, frame)
1501 self.write('[')
1502 self.visit(node.arg, frame)
1503 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001504 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001505 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001506 self.visit(node.node, frame)
1507 self.write(', ')
1508 self.visit(node.arg, frame)
1509 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001510
1511 def visit_Slice(self, node, frame):
1512 if node.start is not None:
1513 self.visit(node.start, frame)
1514 self.write(':')
1515 if node.stop is not None:
1516 self.visit(node.stop, frame)
1517 if node.step is not None:
1518 self.write(':')
1519 self.visit(node.step, frame)
1520
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001521 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001522 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001523 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001524 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001525 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001526 if getattr(func, 'contextfilter', False):
1527 self.write('context, ')
Armin Ronacher8346bd72010-03-14 19:43:47 +01001528 elif getattr(func, 'evalcontextfilter', False):
1529 self.write('context.eval_ctx, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001530 elif getattr(func, 'environmentfilter', False):
1531 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001532
1533 # if the filter node is None we are inside a filter block
1534 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001535 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001536 self.visit(node.node, frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001537 elif frame.eval_ctx.volatile:
1538 self.write('(context.eval_ctx.autoescape and'
1539 ' Markup(concat(%s)) or concat(%s))' %
1540 (frame.buffer, frame.buffer))
1541 elif frame.eval_ctx.autoescape:
Armin Ronacher3da90312008-05-23 16:37:28 +02001542 self.write('Markup(concat(%s))' % frame.buffer)
1543 else:
1544 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001545 self.signature(node, frame)
1546 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001547
1548 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001549 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001550 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001551 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001552 self.visit(node.node, frame)
1553 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001554 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001555
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001556 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001557 def write_expr2():
1558 if node.expr2 is not None:
1559 return self.visit(node.expr2, frame)
1560 self.write('environment.undefined(%r)' % ('the inline if-'
1561 'expression on %s evaluated to false and '
1562 'no else section was defined.' % self.position(node)))
1563
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001564 if not have_condexpr:
1565 self.write('((')
1566 self.visit(node.test, frame)
1567 self.write(') and (')
1568 self.visit(node.expr1, frame)
1569 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001570 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001571 self.write(',))[0]')
1572 else:
1573 self.write('(')
1574 self.visit(node.expr1, frame)
1575 self.write(' if ')
1576 self.visit(node.test, frame)
1577 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001578 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001579 self.write(')')
1580
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001581 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001582 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001583 self.write('environment.call(context, ')
1584 else:
1585 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001586 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001587 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001588 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001589 self.write(')')
1590
1591 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001592 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001593 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001594
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001595 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001596
1597 def visit_MarkSafe(self, node, frame):
1598 self.write('Markup(')
1599 self.visit(node.expr, frame)
1600 self.write(')')
1601
Armin Ronacher4da90342010-05-29 17:35:10 +02001602 def visit_MarkSafeIfAutoescape(self, node, frame):
1603 self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1604 self.visit(node.expr, frame)
1605 self.write(')')
1606
Armin Ronachered1e0d42008-05-18 20:25:28 +02001607 def visit_EnvironmentAttribute(self, node, frame):
1608 self.write('environment.' + node.name)
1609
1610 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001611 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001612
1613 def visit_ImportedName(self, node, frame):
1614 self.write(self.import_aliases[node.importname])
1615
1616 def visit_InternalName(self, node, frame):
1617 self.write(node.name)
1618
Armin Ronacher6df604e2008-05-23 22:18:38 +02001619 def visit_ContextReference(self, node, frame):
1620 self.write('context')
1621
Armin Ronachered1e0d42008-05-18 20:25:28 +02001622 def visit_Continue(self, node, frame):
1623 self.writeline('continue', node)
1624
1625 def visit_Break(self, node, frame):
1626 self.writeline('break', node)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001627
1628 def visit_Scope(self, node, frame):
1629 scope_frame = frame.inner()
1630 scope_frame.inspect(node.iter_child_nodes())
1631 aliases = self.push_scope(scope_frame)
1632 self.pull_locals(scope_frame)
1633 self.blockvisit(node.body, scope_frame)
1634 self.pop_scope(aliases, scope_frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001635
1636 def visit_EvalContextModifier(self, node, frame):
1637 for keyword in node.options:
1638 self.writeline('context.eval_ctx.%s = ' % keyword.key)
1639 self.visit(keyword.value, frame)
1640 try:
1641 val = keyword.value.as_const(frame.eval_ctx)
1642 except nodes.Impossible:
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001643 frame.eval_ctx.volatile = True
Armin Ronacher8346bd72010-03-14 19:43:47 +01001644 else:
1645 setattr(frame.eval_ctx, keyword.key, val)
1646
1647 def visit_ScopedEvalContextModifier(self, node, frame):
1648 old_ctx_name = self.temporary_identifier()
1649 safed_ctx = frame.eval_ctx.save()
1650 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1651 self.visit_EvalContextModifier(node, frame)
1652 for child in node.body:
1653 self.visit(child, frame)
1654 frame.eval_ctx.revert(safed_ctx)
1655 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)