blob: 47bd6ec237909b4c97cbf0c70ef66c5e72ae0164 [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
Armin Ronacherd7d663f2013-05-18 11:38:34 +010019from six.moves import cStringIO as StringIO, map
Armin Ronachere791c2a2008-04-07 18:39:54 +020020
Cory Benfieldd5a0edf2013-05-18 11:41:24 +010021# TODO: Move this to the compat module.
22try:
23 range_type = xrange
24except NameError:
25 range_type = range
26
Armin Ronachere791c2a2008-04-07 18:39:54 +020027
28operators = {
29 'eq': '==',
30 'ne': '!=',
31 'gt': '>',
32 'gteq': '>=',
33 'lt': '<',
34 'lteq': '<=',
35 'in': 'in',
36 'notin': 'not in'
37}
38
Armin Ronacher0d242be2010-02-10 01:35:13 +010039# what method to iterate over items do we want to use for dict iteration
40# in generated code? on 2.x let's go with iteritems, on 3.x with items
41if hasattr(dict, 'iteritems'):
42 dict_item_iter = 'iteritems'
43else:
44 dict_item_iter = 'items'
45
46
Armin Ronacher821a4232010-02-17 07:59:38 +010047# does if 0: dummy(x) get us x into the scope?
48def unoptimize_before_dead_code():
49 x = 42
50 def f():
51 if 0: dummy(x)
52 return f
Armin Ronacher9dd7fad2013-05-18 11:36:32 +010053
54# The getattr is necessary for pypy which does not set this attribute if
55# no closure is on the function
56unoptimize_before_dead_code = bool(
57 getattr(unoptimize_before_dead_code(), '__closure__', None))
Armin Ronacher821a4232010-02-17 07:59:38 +010058
59
Armin Ronacher64b08a02010-03-12 03:17:41 +010060def generate(node, environment, name, filename, stream=None,
61 defer_init=False):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020062 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020063 if not isinstance(node, nodes.Template):
64 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher64b08a02010-03-12 03:17:41 +010065 generator = CodeGenerator(environment, name, filename, stream, defer_init)
Armin Ronachere791c2a2008-04-07 18:39:54 +020066 generator.visit(node)
67 if stream is None:
68 return generator.stream.getvalue()
69
70
Armin Ronacher4dfc9752008-04-09 15:03:29 +020071def has_safe_repr(value):
72 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020073 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020074 return True
Thomas Waldmann7d295622013-05-18 00:06:22 +020075 if isinstance(value, (bool, int, float, complex, range_type, Markup) + six.string_types):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020076 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020077 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020078 for item in value:
79 if not has_safe_repr(item):
80 return False
81 return True
82 elif isinstance(value, dict):
Thomas Waldmanne0003552013-05-17 23:52:14 +020083 for key, value in six.iteritems(value):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020084 if not has_safe_repr(key):
85 return False
86 if not has_safe_repr(value):
87 return False
88 return True
89 return False
90
91
Armin Ronacherc9705c22008-04-27 21:28:03 +020092def find_undeclared(nodes, names):
93 """Check if the names passed are accessed undeclared. The return value
94 is a set of all the undeclared names from the sequence of names found.
95 """
96 visitor = UndeclaredNameVisitor(names)
97 try:
98 for node in nodes:
99 visitor.visit(node)
100 except VisitorExit:
101 pass
102 return visitor.undeclared
103
104
Armin Ronachere791c2a2008-04-07 18:39:54 +0200105class Identifiers(object):
106 """Tracks the status of identifiers in frames."""
107
108 def __init__(self):
109 # variables that are known to be declared (probably from outer
110 # frames or because they are special for the frame)
111 self.declared = set()
112
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200113 # undeclared variables from outer scopes
114 self.outer_undeclared = set()
115
Armin Ronachere791c2a2008-04-07 18:39:54 +0200116 # names that are accessed without being explicitly declared by
117 # this one or any of the outer scopes. Names can appear both in
118 # declared and undeclared.
119 self.undeclared = set()
120
121 # names that are declared locally
122 self.declared_locally = set()
123
124 # names that are declared by parameters
125 self.declared_parameter = set()
126
127 def add_special(self, name):
128 """Register a special name like `loop`."""
129 self.undeclared.discard(name)
130 self.declared.add(name)
131
Armin Ronacherda632622011-03-13 14:33:27 -0400132 def is_declared(self, name):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200133 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200134 if name in self.declared_locally or name in self.declared_parameter:
135 return True
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200136 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200137
Armin Ronacher74230e62009-10-25 12:46:31 +0100138 def copy(self):
139 return deepcopy(self)
140
Armin Ronachere791c2a2008-04-07 18:39:54 +0200141
142class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200143 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200144
Armin Ronacher8346bd72010-03-14 19:43:47 +0100145 def __init__(self, eval_ctx, parent=None):
146 self.eval_ctx = eval_ctx
Armin Ronachere791c2a2008-04-07 18:39:54 +0200147 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200148
Armin Ronacher75cfb862008-04-11 13:47:22 +0200149 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200150 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200151
Armin Ronacher75cfb862008-04-11 13:47:22 +0200152 # the root frame is basically just the outermost frame, so no if
153 # conditions. This information is used to optimize inheritance
154 # situations.
155 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200156
Armin Ronacher79668952008-09-23 22:52:46 +0200157 # in some dynamic inheritance situations the compiler needs to add
158 # write tests around output statements.
159 self.require_output_check = parent and parent.require_output_check
Armin Ronacherf40c8842008-09-17 18:51:26 +0200160
Armin Ronacherfed44b52008-04-13 19:42:53 +0200161 # inside some tags we are using a buffer rather than yield statements.
162 # this for example affects {% filter %} or {% macro %}. If a frame
163 # is buffered this variable points to the name of the list used as
164 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200165 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200166
Armin Ronacherfed44b52008-04-13 19:42:53 +0200167 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200168 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200169
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100170 # a set of actually assigned names
171 self.assigned_names = set()
172
Armin Ronacherfed44b52008-04-13 19:42:53 +0200173 # the parent of this frame
174 self.parent = parent
175
Armin Ronachere791c2a2008-04-07 18:39:54 +0200176 if parent is not None:
177 self.identifiers.declared.update(
178 parent.identifiers.declared |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200179 parent.identifiers.declared_parameter |
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100180 parent.assigned_names
Armin Ronachere791c2a2008-04-07 18:39:54 +0200181 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200182 self.identifiers.outer_undeclared.update(
183 parent.identifiers.undeclared -
184 self.identifiers.declared
185 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200186 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200187
Armin Ronacher8efc5222008-04-08 14:47:40 +0200188 def copy(self):
189 """Create a copy of the current one."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200190 rv = object.__new__(self.__class__)
191 rv.__dict__.update(self.__dict__)
192 rv.identifiers = object.__new__(self.identifiers.__class__)
193 rv.identifiers.__dict__.update(self.identifiers.__dict__)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200194 return rv
195
Armin Ronacherda632622011-03-13 14:33:27 -0400196 def inspect(self, nodes):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200197 """Walk the node and check for identifiers. If the scope is hard (eg:
198 enforce on a python level) overrides from outer scopes are tracked
199 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200200 """
Armin Ronacherda632622011-03-13 14:33:27 -0400201 visitor = FrameIdentifierVisitor(self.identifiers)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200202 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200203 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200204
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100205 def find_shadowed(self, extra=()):
206 """Find all the shadowed names. extra is an iterable of variables
207 that may be defined with `add_special` which may occour scoped.
208 """
209 i = self.identifiers
210 return (i.declared | i.outer_undeclared) & \
211 (i.declared_locally | i.declared_parameter) | \
212 set(x for x in extra if i.is_declared(x))
213
Armin Ronachere791c2a2008-04-07 18:39:54 +0200214 def inner(self):
215 """Return an inner frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100216 return Frame(self.eval_ctx, self)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200217
Armin Ronacher75cfb862008-04-11 13:47:22 +0200218 def soft(self):
219 """Return a soft frame. A soft frame may not be modified as
220 standalone thing as it shares the resources with the frame it
221 was created of, but it's not a rootlevel frame any longer.
222 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200223 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200224 rv.rootlevel = False
225 return rv
226
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200227 __copy__ = copy
228
Armin Ronachere791c2a2008-04-07 18:39:54 +0200229
Armin Ronacherc9705c22008-04-27 21:28:03 +0200230class VisitorExit(RuntimeError):
231 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
232
233
234class DependencyFinderVisitor(NodeVisitor):
235 """A visitor that collects filter and test calls."""
236
237 def __init__(self):
238 self.filters = set()
239 self.tests = set()
240
241 def visit_Filter(self, node):
242 self.generic_visit(node)
243 self.filters.add(node.name)
244
245 def visit_Test(self, node):
246 self.generic_visit(node)
247 self.tests.add(node.name)
248
249 def visit_Block(self, node):
250 """Stop visiting at blocks."""
251
252
253class UndeclaredNameVisitor(NodeVisitor):
254 """A visitor that checks if a name is accessed without being
255 declared. This is different from the frame visitor as it will
256 not stop at closure frames.
257 """
258
259 def __init__(self, names):
260 self.names = set(names)
261 self.undeclared = set()
262
263 def visit_Name(self, node):
264 if node.ctx == 'load' and node.name in self.names:
265 self.undeclared.add(node.name)
266 if self.undeclared == self.names:
267 raise VisitorExit()
268 else:
269 self.names.discard(node.name)
270
271 def visit_Block(self, node):
272 """Stop visiting a blocks."""
273
274
Armin Ronachere791c2a2008-04-07 18:39:54 +0200275class FrameIdentifierVisitor(NodeVisitor):
276 """A visitor for `Frame.inspect`."""
277
Armin Ronacherda632622011-03-13 14:33:27 -0400278 def __init__(self, identifiers):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200279 self.identifiers = identifiers
280
Armin Ronacherc9705c22008-04-27 21:28:03 +0200281 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200282 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200283 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200284 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200285 elif node.ctx == 'param':
286 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200287 elif node.ctx == 'load' and not \
Armin Ronacherda632622011-03-13 14:33:27 -0400288 self.identifiers.is_declared(node.name):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200289 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200290
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200291 def visit_If(self, node):
292 self.visit(node.test)
Armin Ronacher74230e62009-10-25 12:46:31 +0100293 real_identifiers = self.identifiers
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200294
Armin Ronacher8a672512010-04-05 18:43:07 +0200295 old_names = real_identifiers.declared_locally | \
Armin Ronacher74230e62009-10-25 12:46:31 +0100296 real_identifiers.declared_parameter
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200297
Armin Ronacher74230e62009-10-25 12:46:31 +0100298 def inner_visit(nodes):
Armin Ronacher1965e312009-10-25 13:03:08 +0100299 if not nodes:
300 return set()
Armin Ronacher74230e62009-10-25 12:46:31 +0100301 self.identifiers = real_identifiers.copy()
302 for subnode in nodes:
303 self.visit(subnode)
304 rv = self.identifiers.declared_locally - old_names
305 # we have to remember the undeclared variables of this branch
306 # because we will have to pull them.
307 real_identifiers.undeclared.update(self.identifiers.undeclared)
308 self.identifiers = real_identifiers
309 return rv
310
311 body = inner_visit(node.body)
312 else_ = inner_visit(node.else_ or ())
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200313
314 # the differences between the two branches are also pulled as
315 # undeclared variables
Armin Ronacher8a672512010-04-05 18:43:07 +0200316 real_identifiers.undeclared.update(body.symmetric_difference(else_) -
317 real_identifiers.declared)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200318
Armin Ronacher74230e62009-10-25 12:46:31 +0100319 # remember those that are declared.
320 real_identifiers.declared_locally.update(body | else_)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200321
Armin Ronacherc9705c22008-04-27 21:28:03 +0200322 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200323 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200324
Armin Ronacherc9705c22008-04-27 21:28:03 +0200325 def visit_Import(self, node):
326 self.generic_visit(node)
327 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200328
Armin Ronacherc9705c22008-04-27 21:28:03 +0200329 def visit_FromImport(self, node):
330 self.generic_visit(node)
331 for name in node.names:
332 if isinstance(name, tuple):
333 self.identifiers.declared_locally.add(name[1])
334 else:
335 self.identifiers.declared_locally.add(name)
336
337 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200338 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200339 self.visit(node.node)
340 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200341
Armin Ronacherc9705c22008-04-27 21:28:03 +0200342 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200343 """Visiting stops at for blocks. However the block sequence
344 is visited as part of the outer scope.
345 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200346 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200347
Armin Ronacherc9705c22008-04-27 21:28:03 +0200348 def visit_CallBlock(self, node):
Armin Ronacheref189442010-01-14 01:26:40 +0100349 self.visit(node.call)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200350
351 def visit_FilterBlock(self, node):
352 self.visit(node.filter)
353
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100354 def visit_Scope(self, node):
355 """Stop visiting at scopes."""
356
Armin Ronacherc9705c22008-04-27 21:28:03 +0200357 def visit_Block(self, node):
358 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200359
360
Armin Ronacher75cfb862008-04-11 13:47:22 +0200361class CompilerExit(Exception):
362 """Raised if the compiler encountered a situation where it just
363 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200364 raises such an exception is not further processed.
365 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200366
367
Armin Ronachere791c2a2008-04-07 18:39:54 +0200368class CodeGenerator(NodeVisitor):
369
Armin Ronacher64b08a02010-03-12 03:17:41 +0100370 def __init__(self, environment, name, filename, stream=None,
371 defer_init=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200372 if stream is None:
373 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200374 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200375 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200376 self.filename = filename
377 self.stream = stream
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100378 self.created_block_context = False
Armin Ronacher64b08a02010-03-12 03:17:41 +0100379 self.defer_init = defer_init
Armin Ronacherfed44b52008-04-13 19:42:53 +0200380
Armin Ronacher023b5e92008-05-08 11:03:10 +0200381 # aliases for imports
382 self.import_aliases = {}
383
Armin Ronacherfed44b52008-04-13 19:42:53 +0200384 # a registry for all blocks. Because blocks are moved out
385 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200386 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200387
388 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200389 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200390
391 # some templates have a rootlevel extends. In this case we
392 # can safely assume that we're a child template and do some
393 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200394 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200395
Armin Ronacherba3757b2008-04-16 19:43:16 +0200396 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200397 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200398
Armin Ronacherb9e78752008-05-10 23:36:28 +0200399 # registry of all filters and tests (global, not block local)
400 self.tests = {}
401 self.filters = {}
402
Armin Ronacherba3757b2008-04-16 19:43:16 +0200403 # the debug information
404 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200405 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200406
Armin Ronacherfed44b52008-04-13 19:42:53 +0200407 # the number of new lines before the next write()
408 self._new_lines = 0
409
410 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200411 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200412
413 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200414 self._first_write = True
415
Armin Ronacherfed44b52008-04-13 19:42:53 +0200416 # used by the `temporary_identifier` method to get new
417 # unique, temporary identifier
418 self._last_identifier = 0
419
420 # the current indentation
421 self._indentation = 0
422
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200423 # -- Various compilation helpers
424
Armin Ronachere2244882008-05-19 09:25:57 +0200425 def fail(self, msg, lineno):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100426 """Fail with a :exc:`TemplateAssertionError`."""
Armin Ronachere2244882008-05-19 09:25:57 +0200427 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
428
Armin Ronachere791c2a2008-04-07 18:39:54 +0200429 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200430 """Get a new unique identifier."""
431 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200432 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200433
Armin Ronachered1e0d42008-05-18 20:25:28 +0200434 def buffer(self, frame):
435 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200436 frame.buffer = self.temporary_identifier()
437 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200438
439 def return_buffer_contents(self, frame):
440 """Return the buffer contents of the frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100441 if frame.eval_ctx.volatile:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100442 self.writeline('if context.eval_ctx.autoescape:')
443 self.indent()
444 self.writeline('return Markup(concat(%s))' % frame.buffer)
445 self.outdent()
446 self.writeline('else:')
447 self.indent()
448 self.writeline('return concat(%s)' % frame.buffer)
449 self.outdent()
Armin Ronacher8346bd72010-03-14 19:43:47 +0100450 elif frame.eval_ctx.autoescape:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100451 self.writeline('return Markup(concat(%s))' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200452 else:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100453 self.writeline('return concat(%s)' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200454
Armin Ronachere791c2a2008-04-07 18:39:54 +0200455 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200456 """Indent by one."""
457 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200458
Armin Ronacher8efc5222008-04-08 14:47:40 +0200459 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200460 """Outdent by step."""
461 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200462
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200463 def start_write(self, frame, node=None):
464 """Yield or write into the frame buffer."""
465 if frame.buffer is None:
466 self.writeline('yield ', node)
467 else:
468 self.writeline('%s.append(' % frame.buffer, node)
469
470 def end_write(self, frame):
471 """End the writing process started by `start_write`."""
472 if frame.buffer is not None:
473 self.write(')')
474
475 def simple_write(self, s, frame, node=None):
476 """Simple shortcut for start_write + write + end_write."""
477 self.start_write(frame, node)
478 self.write(s)
479 self.end_write(frame)
480
Armin Ronacherf40c8842008-09-17 18:51:26 +0200481 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200482 """Visit a list of nodes as block in a frame. If the current frame
483 is no buffer a dummy ``if 0: yield None`` is written automatically
484 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200485 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200486 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200487 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200488 else:
489 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200490 try:
491 for node in nodes:
492 self.visit(node, frame)
493 except CompilerExit:
494 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200495
496 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200497 """Write a string into the output stream."""
498 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200499 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200500 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200501 self.code_lineno += self._new_lines
502 if self._write_debug_info is not None:
503 self.debug_info.append((self._write_debug_info,
504 self.code_lineno))
505 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200506 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200507 self.stream.write(' ' * self._indentation)
508 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200509 self.stream.write(x)
510
511 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200512 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200513 self.newline(node, extra)
514 self.write(x)
515
516 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200517 """Add one or more newlines before the next write."""
518 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200519 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200520 self._write_debug_info = node.lineno
521 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200522
Armin Ronacherfd310492008-05-25 00:16:51 +0200523 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200524 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200525 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200526 arguments may not include python keywords otherwise a syntax
527 error could occour. The extra keyword arguments should be given
528 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200529 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200530 # if any of the given keyword arguments is a python keyword
531 # we have to make sure that no invalid call is created.
532 kwarg_workaround = False
533 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200534 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200535 kwarg_workaround = True
536 break
537
Armin Ronacher8efc5222008-04-08 14:47:40 +0200538 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200539 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200540 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200541
542 if not kwarg_workaround:
543 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200544 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200545 self.visit(kwarg, frame)
546 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200547 for key, value in six.iteritems(extra_kwargs):
Armin Ronacherfd310492008-05-25 00:16:51 +0200548 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200549 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200550 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200551 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200552
553 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200554 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200555 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200556 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200557 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200558 for kwarg in node.kwargs:
559 self.write('%r: ' % kwarg.key)
560 self.visit(kwarg.value, frame)
561 self.write(', ')
562 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200563 for key, value in six.iteritems(extra_kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200564 self.write('%r: %s, ' % (key, value))
565 if node.dyn_kwargs is not None:
566 self.write('}, **')
567 self.visit(node.dyn_kwargs, frame)
568 self.write(')')
569 else:
570 self.write('}')
571
572 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200573 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200574 self.visit(node.dyn_kwargs, frame)
575
Armin Ronacherc9705c22008-04-27 21:28:03 +0200576 def pull_locals(self, frame):
577 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200578 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200579 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200580
581 def pull_dependencies(self, nodes):
582 """Pull all the dependencies."""
583 visitor = DependencyFinderVisitor()
584 for node in nodes:
585 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200586 for dependency in 'filters', 'tests':
587 mapping = getattr(self, dependency)
588 for name in getattr(visitor, dependency):
589 if name not in mapping:
590 mapping[name] = self.temporary_identifier()
591 self.writeline('%s = environment.%s[%r]' %
592 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200593
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100594 def unoptimize_scope(self, frame):
595 """Disable Python optimizations for the frame."""
596 # XXX: this is not that nice but it has no real overhead. It
597 # mainly works because python finds the locals before dead code
598 # is removed. If that breaks we have to add a dummy function
599 # that just accepts the arguments and does nothing.
600 if frame.identifiers.declared:
Armin Ronacher821a4232010-02-17 07:59:38 +0100601 self.writeline('%sdummy(%s)' % (
602 unoptimize_before_dead_code and 'if 0: ' or '',
603 ', '.join('l_' + name for name in frame.identifiers.declared)
604 ))
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100605
Armin Ronacher673aa882008-10-04 18:06:57 +0200606 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200607 """This function returns all the shadowed variables in a dict
608 in the form name: alias and will write the required assignments
609 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200610
Armin Ronacher673aa882008-10-04 18:06:57 +0200611 This also predefines locally declared variables from the loop
612 body because under some circumstances it may be the case that
613
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100614 `extra_vars` is passed to `Frame.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200615 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200616 aliases = {}
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100617 for name in frame.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200618 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200619 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200620 to_declare = set()
621 for name in frame.identifiers.declared_locally:
622 if name not in aliases:
623 to_declare.add('l_' + name)
624 if to_declare:
625 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200626 return aliases
627
Armin Ronacher673aa882008-10-04 18:06:57 +0200628 def pop_scope(self, aliases, frame):
629 """Restore all aliases and delete unused variables."""
Thomas Waldmanne0003552013-05-17 23:52:14 +0200630 for name, alias in six.iteritems(aliases):
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200631 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200632 to_delete = set()
633 for name in frame.identifiers.declared_locally:
634 if name not in aliases:
635 to_delete.add('l_' + name)
636 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100637 # we cannot use the del statement here because enclosed
638 # scopes can trigger a SyntaxError:
639 # a = 42; b = lambda: a; del a
640 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200641
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200642 def function_scoping(self, node, frame, children=None,
643 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200644 """In Jinja a few statements require the help of anonymous
645 functions. Those are currently macros and call blocks and in
646 the future also recursive loops. As there is currently
647 technical limitation that doesn't allow reading and writing a
648 variable in a scope where the initial value is coming from an
649 outer scope, this function tries to fall back with a common
650 error message. Additionally the frame passed is modified so
651 that the argumetns are collected and callers are looked up.
652
653 This will return the modified frame.
654 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200655 # we have to iterate twice over it, make sure that works
656 if children is None:
657 children = node.iter_child_nodes()
658 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200659 func_frame = frame.inner()
Armin Ronacherda632622011-03-13 14:33:27 -0400660 func_frame.inspect(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200661
662 # variables that are undeclared (accessed before declaration) and
663 # declared locally *and* part of an outside scope raise a template
664 # assertion error. Reason: we can't generate reasonable code from
Armin Ronacher02b42a82009-03-18 00:59:32 +0100665 # it without aliasing all the variables.
666 # this could be fixed in Python 3 where we have the nonlocal
667 # keyword or if we switch to bytecode generation
Jonas Nockertbdd09dd2013-02-23 20:34:47 +0100668 overridden_closure_vars = (
Armin Ronacher71082072008-04-12 14:19:36 +0200669 func_frame.identifiers.undeclared &
670 func_frame.identifiers.declared &
671 (func_frame.identifiers.declared_locally |
672 func_frame.identifiers.declared_parameter)
673 )
Jonas Nockertbdd09dd2013-02-23 20:34:47 +0100674 if overridden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200675 self.fail('It\'s not possible to set and access variables '
Armin Ronacherefcc0e52009-09-13 00:22:50 -0700676 'derived from an outer scope! (affects: %s)' %
Jonas Nockertbdd09dd2013-02-23 20:34:47 +0100677 ', '.join(sorted(overridden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200678
679 # remove variables from a closure from the frame's undeclared
680 # identifiers.
681 func_frame.identifiers.undeclared -= (
682 func_frame.identifiers.undeclared &
683 func_frame.identifiers.declared
684 )
685
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200686 # no special variables for this scope, abort early
687 if not find_special:
688 return func_frame
689
Armin Ronacher963f97d2008-04-25 11:44:59 +0200690 func_frame.accesses_kwargs = False
691 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200692 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200693 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200694
Armin Ronacherc9705c22008-04-27 21:28:03 +0200695 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
696
697 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200698 func_frame.accesses_caller = True
699 func_frame.identifiers.add_special('caller')
700 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200701 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200702 func_frame.accesses_kwargs = True
703 func_frame.identifiers.add_special('kwargs')
704 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200705 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200706 func_frame.accesses_varargs = True
707 func_frame.identifiers.add_special('varargs')
708 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200709 return func_frame
710
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200711 def macro_body(self, node, frame, children=None):
712 """Dump the function def of a macro or call block."""
713 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100714 # macros are delayed, they never require output checks
715 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200716 args = frame.arguments
Armin Ronachereabf3dd2009-09-12 23:48:18 -0700717 # XXX: this is an ugly fix for the loop nesting bug
718 # (tests.test_old_bugs.test_loop_call_bug). This works around
719 # a identifier nesting problem we have in general. It's just more
720 # likely to happen in loops which is why we work around it. The
721 # real solution would be "nonlocal" all the identifiers that are
722 # leaking into a new python frame and might be used both unassigned
723 # and assigned.
724 if 'loop' in frame.identifiers.declared:
Armin Ronacherb4044392009-09-13 15:56:58 -0700725 args = args + ['l_loop=l_loop']
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200726 self.writeline('def macro(%s):' % ', '.join(args), node)
727 self.indent()
728 self.buffer(frame)
729 self.pull_locals(frame)
730 self.blockvisit(node.body, frame)
731 self.return_buffer_contents(frame)
732 self.outdent()
733 return frame
734
735 def macro_def(self, node, frame):
736 """Dump the macro definition for the def created by macro_body."""
737 arg_tuple = ', '.join(repr(x.name) for x in node.args)
738 name = getattr(node, 'name', None)
739 if len(node.args) == 1:
740 arg_tuple += ','
741 self.write('Macro(environment, macro, %r, (%s), (' %
742 (name, arg_tuple))
743 for arg in node.defaults:
744 self.visit(arg, frame)
745 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200746 self.write('), %r, %r, %r)' % (
747 bool(frame.accesses_kwargs),
748 bool(frame.accesses_varargs),
749 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200750 ))
751
Armin Ronacher547d0b62008-07-04 16:35:10 +0200752 def position(self, node):
753 """Return a human readable position for the node."""
754 rv = 'line %d' % node.lineno
755 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100756 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200757 return rv
758
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200759 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200760
761 def visit_Template(self, node, frame=None):
762 assert frame is None, 'no root frame allowed'
Armin Ronacher1da23d12010-04-05 18:11:18 +0200763 eval_ctx = EvalContext(self.environment, self.name)
Armin Ronacher8346bd72010-03-14 19:43:47 +0100764
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200765 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200766 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200767 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher821a4232010-02-17 07:59:38 +0100768 if not unoptimize_before_dead_code:
769 self.writeline('dummy = lambda *x: None')
Armin Ronacher8edbe492008-04-10 20:43:43 +0200770
Armin Ronacher64b08a02010-03-12 03:17:41 +0100771 # if we want a deferred initialization we cannot move the
772 # environment into a local name
773 envenv = not self.defer_init and ', environment=environment' or ''
774
Armin Ronacher75cfb862008-04-11 13:47:22 +0200775 # do we have an extends tag at all? If not, we can save some
776 # overhead by just not processing any inheritance code.
777 have_extends = node.find(nodes.Extends) is not None
778
Armin Ronacher8edbe492008-04-10 20:43:43 +0200779 # find all blocks
780 for block in node.find_all(nodes.Block):
781 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200782 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200783 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200784
Armin Ronacher023b5e92008-05-08 11:03:10 +0200785 # find all imports and import them
786 for import_ in node.find_all(nodes.ImportedName):
787 if import_.importname not in self.import_aliases:
788 imp = import_.importname
789 self.import_aliases[imp] = alias = self.temporary_identifier()
790 if '.' in imp:
791 module, obj = imp.rsplit('.', 1)
792 self.writeline('from %s import %s as %s' %
793 (module, obj, alias))
794 else:
795 self.writeline('import %s as %s' % (imp, alias))
796
797 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200798 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200799
Armin Ronacher8efc5222008-04-08 14:47:40 +0200800 # generate the root render function.
Armin Ronacher64b08a02010-03-12 03:17:41 +0100801 self.writeline('def root(context%s):' % envenv, extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200802
803 # process the root
Armin Ronacher8346bd72010-03-14 19:43:47 +0100804 frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200805 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200806 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200807 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200808 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200809 if have_extends:
810 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200811 if 'self' in find_undeclared(node.body, ('self',)):
812 frame.identifiers.add_special('self')
813 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200814 self.pull_locals(frame)
815 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200816 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200817 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200818
Armin Ronacher8efc5222008-04-08 14:47:40 +0200819 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200820 if have_extends:
821 if not self.has_known_extends:
822 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200823 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200824 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200825 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200826 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200827 self.indent()
828 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200829 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200830
831 # at this point we now have the blocks collected and can visit them too.
Thomas Waldmanne0003552013-05-17 23:52:14 +0200832 for name, block in six.iteritems(self.blocks):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100833 block_frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200834 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200835 block_frame.block = name
Armin Ronacher64b08a02010-03-12 03:17:41 +0100836 self.writeline('def block_%s(context%s):' % (name, envenv),
837 block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200838 self.indent()
839 undeclared = find_undeclared(block.body, ('self', 'super'))
840 if 'self' in undeclared:
841 block_frame.identifiers.add_special('self')
842 self.writeline('l_self = TemplateReference(context)')
843 if 'super' in undeclared:
844 block_frame.identifiers.add_special('super')
845 self.writeline('l_super = context.super(%r, '
846 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200847 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200848 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200849 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200850 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200851
Armin Ronacher75cfb862008-04-11 13:47:22 +0200852 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200853 for x in self.blocks),
854 extra=1)
855
856 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200857 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
858 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200859
Armin Ronachere791c2a2008-04-07 18:39:54 +0200860 def visit_Block(self, node, frame):
861 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200862 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200863 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200864 # if we know that we are a child template, there is no need to
865 # check if we are one
866 if self.has_known_extends:
867 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200868 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200869 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200870 self.indent()
871 level += 1
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100872 context = node.scoped and 'context.derived(locals())' or 'context'
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100873 self.writeline('for event in context.blocks[%r][0](%s):' % (
874 node.name, context), node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200875 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200876 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200877 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200878
879 def visit_Extends(self, node, frame):
880 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200881 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200882 self.fail('cannot use extend from a non top-level scope',
883 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200884
Armin Ronacher7fb38972008-04-11 13:54:28 +0200885 # if the number of extends statements in general is zero so
886 # far, we don't have to add a check if something extended
887 # the template before this one.
888 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200889
Armin Ronacher7fb38972008-04-11 13:54:28 +0200890 # if we have a known extends we just add a template runtime
891 # error into the generated code. We could catch that at compile
892 # time too, but i welcome it not to confuse users by throwing the
893 # same error at different times just "because we can".
894 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200895 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200896 self.indent()
897 self.writeline('raise TemplateRuntimeError(%r)' %
898 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200899 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200900
Armin Ronacher7fb38972008-04-11 13:54:28 +0200901 # if we have a known extends already we don't need that code here
902 # as we know that the template execution will end here.
903 if self.has_known_extends:
904 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200905
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200906 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200907 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200908 self.write(', %r)' % self.name)
909 self.writeline('for name, parent_block in parent_template.'
Armin Ronacher0d242be2010-02-10 01:35:13 +0100910 'blocks.%s():' % dict_item_iter)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200911 self.indent()
912 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200913 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200914 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200915
916 # if this extends statement was in the root level we can take
917 # advantage of that information and simplify the generated code
918 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200919 if frame.rootlevel:
920 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200921
Armin Ronacher7fb38972008-04-11 13:54:28 +0200922 # and now we have one more
923 self.extends_so_far += 1
924
Armin Ronacherf059ec12008-04-11 22:21:00 +0200925 def visit_Include(self, node, frame):
926 """Handles includes."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100927 if node.with_context:
928 self.unoptimize_scope(frame)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100929 if node.ignore_missing:
930 self.writeline('try:')
931 self.indent()
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100932
933 func_name = 'get_or_select_template'
934 if isinstance(node.template, nodes.Const):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200935 if isinstance(node.template.value, six.string_types):
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100936 func_name = 'get_template'
937 elif isinstance(node.template.value, (tuple, list)):
938 func_name = 'select_template'
939 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
940 func_name = 'select_template'
941
942 self.writeline('template = environment.%s(' % func_name, node)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100943 self.visit(node.template, frame)
944 self.write(', %r)' % self.name)
945 if node.ignore_missing:
946 self.outdent()
947 self.writeline('except TemplateNotFound:')
948 self.indent()
949 self.writeline('pass')
950 self.outdent()
951 self.writeline('else:')
952 self.indent()
953
Armin Ronacherea847c52008-05-02 20:04:32 +0200954 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200955 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200956 'template.new_context(context.parent, True, '
957 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200958 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100959 self.writeline('for event in template.module._body_stream:')
960
Armin Ronacherf059ec12008-04-11 22:21:00 +0200961 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200962 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200963 self.outdent()
964
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100965 if node.ignore_missing:
966 self.outdent()
967
Armin Ronacher0611e492008-04-25 23:44:14 +0200968 def visit_Import(self, node, frame):
969 """Visit regular imports."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100970 if node.with_context:
971 self.unoptimize_scope(frame)
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200972 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200973 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200974 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200975 self.write('environment.get_template(')
976 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200977 self.write(', %r).' % self.name)
978 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200979 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200980 else:
981 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200982 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200983 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100984 frame.assigned_names.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200985
986 def visit_FromImport(self, node, frame):
987 """Visit named imports."""
988 self.newline(node)
989 self.write('included_template = environment.get_template(')
990 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200991 self.write(', %r).' % self.name)
992 if node.with_context:
993 self.write('make_module(context.parent, True)')
994 else:
995 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200996
997 var_names = []
998 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200999 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +02001000 if isinstance(name, tuple):
1001 name, alias = name
1002 else:
1003 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001004 self.writeline('l_%s = getattr(included_template, '
1005 '%r, missing)' % (alias, name))
1006 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +02001007 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001008 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +02001009 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +02001010 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001011 (alias, 'the template %%r (imported on %s) does '
1012 'not export the requested name %s' % (
1013 self.position(node),
1014 repr(name)
1015 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +02001016 self.outdent()
1017 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +02001018 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +02001019 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +02001020 discarded_names.append(alias)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001021 frame.assigned_names.add(alias)
Armin Ronachera78d2762008-05-15 23:18:07 +02001022
1023 if var_names:
1024 if len(var_names) == 1:
1025 name = var_names[0]
1026 self.writeline('context.vars[%r] = l_%s' % (name, name))
1027 else:
1028 self.writeline('context.vars.update({%s})' % ', '.join(
1029 '%r: l_%s' % (name, name) for name in var_names
1030 ))
1031 if discarded_names:
1032 if len(discarded_names) == 1:
1033 self.writeline('context.exported_vars.discard(%r)' %
1034 discarded_names[0])
1035 else:
1036 self.writeline('context.exported_vars.difference_'
1037 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +02001038
Armin Ronachere791c2a2008-04-07 18:39:54 +02001039 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001040 # when calculating the nodes for the inner frame we have to exclude
1041 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001042 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001043 if node.recursive:
1044 loop_frame = self.function_scoping(node, frame, children,
1045 find_special=False)
1046 else:
1047 loop_frame = frame.inner()
1048 loop_frame.inspect(children)
1049
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001050 # try to figure out if we have an extended loop. An extended loop
1051 # is necessary if the loop is in recursive mode if the special loop
1052 # variable is accessed in the body.
1053 extended_loop = node.recursive or 'loop' in \
1054 find_undeclared(node.iter_child_nodes(
1055 only=('body',)), ('loop',))
1056
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001057 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +02001058 # variables at that point. Because loops can be nested but the loop
1059 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001060 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +02001061 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001062
1063 # otherwise we set up a buffer and add a function def
1064 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001065 self.writeline('def loop(reciter, loop_render_func):', node)
1066 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +02001067 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001068 aliases = {}
1069
Armin Ronacherff53c782008-08-13 18:55:50 +02001070 # make sure the loop variable is a special one and raise a template
1071 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +02001072 if extended_loop:
1073 loop_frame.identifiers.add_special('loop')
Armin Ronacherff53c782008-08-13 18:55:50 +02001074 for name in node.find_all(nodes.Name):
1075 if name.ctx == 'store' and name.name == 'loop':
1076 self.fail('Can\'t assign to special loop variable '
1077 'in for-loop target', name.lineno)
1078
Armin Ronacherc9705c22008-04-27 21:28:03 +02001079 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001080 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001081 iteration_indicator = self.temporary_identifier()
1082 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001083
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001084 # Create a fake parent loop if the else or test section of a
1085 # loop is accessing the special loop variable and no parent loop
1086 # exists.
1087 if 'loop' not in aliases and 'loop' in find_undeclared(
1088 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1089 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001090 ("'loop' is undefined. the filter section of a loop as well "
Armin Ronacherbc56cd22011-01-15 18:35:45 +01001091 "as the else block don't have access to the special 'loop'"
Armin Ronacher547d0b62008-07-04 16:35:10 +02001092 " variable of the current loop. Because there is no parent "
1093 "loop it's undefined. Happened in loop on %s" %
1094 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001095
1096 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001097 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +02001098 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001099
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001100 # if we have an extened loop and a node test, we filter in the
1101 # "outer frame".
1102 if extended_loop and node.test is not None:
1103 self.write('(')
1104 self.visit(node.target, loop_frame)
1105 self.write(' for ')
1106 self.visit(node.target, loop_frame)
1107 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001108 if node.recursive:
1109 self.write('reciter')
1110 else:
1111 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001112 self.write(' if (')
1113 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001114 self.visit(node.test, test_frame)
1115 self.write('))')
1116
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001117 elif node.recursive:
1118 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001119 else:
1120 self.visit(node.iter, loop_frame)
1121
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001122 if node.recursive:
1123 self.write(', recurse=loop_render_func):')
1124 else:
1125 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001126
1127 # tests in not extended loops become a continue
1128 if not extended_loop and node.test is not None:
1129 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +02001130 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +02001131 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001132 self.write(':')
1133 self.indent()
1134 self.writeline('continue')
1135 self.outdent(2)
1136
Armin Ronacherc9705c22008-04-27 21:28:03 +02001137 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001138 self.blockvisit(node.body, loop_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001139 if node.else_:
1140 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001141 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001142
1143 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001144 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001145 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001146 self.blockvisit(node.else_, loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001147 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001148
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001149 # reset the aliases if there are any.
Armin Ronachercebd8382008-12-25 18:33:46 +01001150 if not node.recursive:
1151 self.pop_scope(aliases, loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001152
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001153 # if the node was recursive we have to return the buffer contents
1154 # and start the iteration code
1155 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001156 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001157 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001158 self.start_write(frame, node)
1159 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001160 self.visit(node.iter, frame)
1161 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001162 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001163
Armin Ronachere791c2a2008-04-07 18:39:54 +02001164 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001165 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001166 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001167 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001168 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001169 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001170 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001171 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001172 if node.else_:
1173 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001174 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001175 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001176 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001177
Armin Ronacher8efc5222008-04-08 14:47:40 +02001178 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001179 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001180 self.newline()
1181 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001182 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001183 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001184 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001185 self.write('l_%s = ' % node.name)
1186 self.macro_def(node, macro_frame)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001187 frame.assigned_names.add(node.name)
Armin Ronacher71082072008-04-12 14:19:36 +02001188
1189 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001190 children = node.iter_child_nodes(exclude=('call',))
1191 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001192 self.writeline('caller = ')
1193 self.macro_def(node, call_frame)
1194 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001195 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001196 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001197
1198 def visit_FilterBlock(self, node, frame):
1199 filter_frame = frame.inner()
1200 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacher673aa882008-10-04 18:06:57 +02001201 aliases = self.push_scope(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001202 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001203 self.buffer(filter_frame)
Armin Ronacherf40c8842008-09-17 18:51:26 +02001204 self.blockvisit(node.body, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001205 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001206 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001207 self.end_write(frame)
Armin Ronacher673aa882008-10-04 18:06:57 +02001208 self.pop_scope(aliases, filter_frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001209
Armin Ronachere791c2a2008-04-07 18:39:54 +02001210 def visit_ExprStmt(self, node, frame):
1211 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001212 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001213
1214 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001215 # if we have a known extends statement, we don't output anything
Armin Ronacher79668952008-09-23 22:52:46 +02001216 # if we are in a require_output_check section
1217 if self.has_known_extends and frame.require_output_check:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001218 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001219
Armin Ronacher665bfb82008-07-14 13:41:46 +02001220 if self.environment.finalize:
Thomas Waldmanne0003552013-05-17 23:52:14 +02001221 finalize = lambda x: six.text_type(self.environment.finalize(x))
Armin Ronacher665bfb82008-07-14 13:41:46 +02001222 else:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001223 finalize = six.text_type
Armin Ronacher665bfb82008-07-14 13:41:46 +02001224
Armin Ronacher79668952008-09-23 22:52:46 +02001225 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001226 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001227 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001228 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001229 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001230 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001231
Armin Ronachere791c2a2008-04-07 18:39:54 +02001232 # try to evaluate as many chunks as possible into a static
1233 # string at compile time.
1234 body = []
1235 for child in node.nodes:
1236 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001237 const = child.as_const(frame.eval_ctx)
Armin Ronacher9cf95912008-05-24 19:54:43 +02001238 except nodes.Impossible:
1239 body.append(child)
1240 continue
Armin Ronacher8346bd72010-03-14 19:43:47 +01001241 # the frame can't be volatile here, becaus otherwise the
1242 # as_const() function would raise an Impossible exception
1243 # at that point.
Armin Ronacher9cf95912008-05-24 19:54:43 +02001244 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001245 if frame.eval_ctx.autoescape:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001246 if hasattr(const, '__html__'):
1247 const = const.__html__()
1248 else:
1249 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001250 const = finalize(const)
Ian Lewisab014bd2010-10-31 20:29:28 +09001251 except Exception:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001252 # if something goes wrong here we evaluate the node
1253 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001254 body.append(child)
1255 continue
1256 if body and isinstance(body[-1], list):
1257 body[-1].append(const)
1258 else:
1259 body.append([const])
1260
Armin Ronachered1e0d42008-05-18 20:25:28 +02001261 # if we have less than 3 nodes or a buffer we yield or extend/append
1262 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001263 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001264 # for one item we append, for more we extend
1265 if len(body) == 1:
1266 self.writeline('%s.append(' % frame.buffer)
1267 else:
1268 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001269 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001270 for item in body:
1271 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001272 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001273 if frame.buffer is None:
1274 self.writeline('yield ' + val)
1275 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001276 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001277 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001278 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001279 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001280 else:
1281 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001282 close = 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001283 if frame.eval_ctx.volatile:
1284 self.write('(context.eval_ctx.autoescape and'
1285 ' escape or to_string)(')
1286 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001287 self.write('escape(')
1288 else:
Armin Ronacherbd357722009-08-05 20:25:06 +02001289 self.write('to_string(')
Armin Ronacherd1342312008-04-28 12:20:12 +02001290 if self.environment.finalize is not None:
1291 self.write('environment.finalize(')
1292 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001293 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001294 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001295 if frame.buffer is not None:
1296 self.write(', ')
1297 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001298 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001299 self.outdent()
1300 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001301
1302 # otherwise we create a format string as this is faster in that case
1303 else:
1304 format = []
1305 arguments = []
1306 for item in body:
1307 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001308 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001309 else:
1310 format.append('%s')
1311 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001312 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001313 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001314 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001315 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001316 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001317 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001318 close = 0
Armin Ronacher8346bd72010-03-14 19:43:47 +01001319 if frame.eval_ctx.volatile:
1320 self.write('(context.eval_ctx.autoescape and'
1321 ' escape or to_string)(')
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001322 close += 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001323 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001324 self.write('escape(')
1325 close += 1
1326 if self.environment.finalize is not None:
1327 self.write('environment.finalize(')
1328 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001329 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001330 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001331 self.outdent()
1332 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001333
Armin Ronacher7fb38972008-04-11 13:54:28 +02001334 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001335 self.outdent()
1336
Armin Ronacher8efc5222008-04-08 14:47:40 +02001337 def visit_Assign(self, node, frame):
1338 self.newline(node)
1339 # toplevel assignments however go into the local namespace and
1340 # the current template's context. We create a copy of the frame
1341 # here and add a set so that the Name visitor can add the assigned
1342 # names here.
1343 if frame.toplevel:
1344 assignment_frame = frame.copy()
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001345 assignment_frame.toplevel_assignments = set()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001346 else:
1347 assignment_frame = frame
1348 self.visit(node.target, assignment_frame)
1349 self.write(' = ')
1350 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001351
1352 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001353 if frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001354 public_names = [x for x in assignment_frame.toplevel_assignments
Armin Ronacher903d1682008-05-23 00:51:58 +02001355 if not x.startswith('_')]
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001356 if len(assignment_frame.toplevel_assignments) == 1:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001357 name = six.advance_iterator(iter(assignment_frame.toplevel_assignments))
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001358 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001359 else:
1360 self.writeline('context.vars.update({')
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001361 for idx, name in enumerate(assignment_frame.toplevel_assignments):
Armin Ronacher69e12db2008-05-12 09:00:03 +02001362 if idx:
1363 self.write(', ')
1364 self.write('%r: l_%s' % (name, name))
1365 self.write('})')
1366 if public_names:
1367 if len(public_names) == 1:
1368 self.writeline('context.exported_vars.add(%r)' %
1369 public_names[0])
1370 else:
1371 self.writeline('context.exported_vars.update((%s))' %
1372 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001373
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001374 # -- Expression Visitors
1375
Armin Ronachere791c2a2008-04-07 18:39:54 +02001376 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001377 if node.ctx == 'store' and frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001378 frame.toplevel_assignments.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001379 self.write('l_' + node.name)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001380 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001381
1382 def visit_Const(self, node, frame):
1383 val = node.value
1384 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001385 self.write(str(val))
1386 else:
1387 self.write(repr(val))
1388
Armin Ronacher5411ce72008-05-25 11:36:22 +02001389 def visit_TemplateData(self, node, frame):
Armin Ronacherffaa2e72010-05-29 20:57:16 +02001390 try:
1391 self.write(repr(node.as_const(frame.eval_ctx)))
1392 except nodes.Impossible:
1393 self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)'
1394 % node.data)
Armin Ronacher5411ce72008-05-25 11:36:22 +02001395
Armin Ronacher8efc5222008-04-08 14:47:40 +02001396 def visit_Tuple(self, node, frame):
1397 self.write('(')
1398 idx = -1
1399 for idx, item in enumerate(node.items):
1400 if idx:
1401 self.write(', ')
1402 self.visit(item, frame)
1403 self.write(idx == 0 and ',)' or ')')
1404
Armin Ronacher8edbe492008-04-10 20:43:43 +02001405 def visit_List(self, node, frame):
1406 self.write('[')
1407 for idx, item in enumerate(node.items):
1408 if idx:
1409 self.write(', ')
1410 self.visit(item, frame)
1411 self.write(']')
1412
1413 def visit_Dict(self, node, frame):
1414 self.write('{')
1415 for idx, item in enumerate(node.items):
1416 if idx:
1417 self.write(', ')
1418 self.visit(item.key, frame)
1419 self.write(': ')
1420 self.visit(item.value, frame)
1421 self.write('}')
1422
Armin Ronachera9195382010-11-29 13:21:57 +01001423 def binop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001424 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001425 if self.environment.sandboxed and \
1426 operator in self.environment.intercepted_binops:
1427 self.write('environment.call_binop(context, %r, ' % operator)
1428 self.visit(node.left, frame)
1429 self.write(', ')
1430 self.visit(node.right, frame)
1431 else:
1432 self.write('(')
1433 self.visit(node.left, frame)
1434 self.write(' %s ' % operator)
1435 self.visit(node.right, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001436 self.write(')')
1437 return visitor
1438
Armin Ronachera9195382010-11-29 13:21:57 +01001439 def uaop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001440 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001441 if self.environment.sandboxed and \
1442 operator in self.environment.intercepted_unops:
1443 self.write('environment.call_unop(context, %r, ' % operator)
1444 self.visit(node.node, frame)
1445 else:
1446 self.write('(' + operator)
1447 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001448 self.write(')')
1449 return visitor
1450
1451 visit_Add = binop('+')
1452 visit_Sub = binop('-')
1453 visit_Mul = binop('*')
1454 visit_Div = binop('/')
1455 visit_FloorDiv = binop('//')
1456 visit_Pow = binop('**')
1457 visit_Mod = binop('%')
Armin Ronachera9195382010-11-29 13:21:57 +01001458 visit_And = binop('and', interceptable=False)
1459 visit_Or = binop('or', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001460 visit_Pos = uaop('+')
1461 visit_Neg = uaop('-')
Armin Ronachera9195382010-11-29 13:21:57 +01001462 visit_Not = uaop('not ', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001463 del binop, uaop
1464
Armin Ronacherd1342312008-04-28 12:20:12 +02001465 def visit_Concat(self, node, frame):
Armin Ronacher8346bd72010-03-14 19:43:47 +01001466 if frame.eval_ctx.volatile:
1467 func_name = '(context.eval_ctx.volatile and' \
1468 ' markup_join or unicode_join)'
1469 elif frame.eval_ctx.autoescape:
1470 func_name = 'markup_join'
1471 else:
1472 func_name = 'unicode_join'
1473 self.write('%s((' % func_name)
Armin Ronacherd1342312008-04-28 12:20:12 +02001474 for arg in node.nodes:
1475 self.visit(arg, frame)
1476 self.write(', ')
1477 self.write('))')
1478
Armin Ronachere791c2a2008-04-07 18:39:54 +02001479 def visit_Compare(self, node, frame):
1480 self.visit(node.expr, frame)
1481 for op in node.ops:
1482 self.visit(op, frame)
1483
1484 def visit_Operand(self, node, frame):
1485 self.write(' %s ' % operators[node.op])
1486 self.visit(node.expr, frame)
1487
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001488 def visit_Getattr(self, node, frame):
1489 self.write('environment.getattr(')
1490 self.visit(node.node, frame)
1491 self.write(', %r)' % node.attr)
1492
1493 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001494 # slices bypass the environment getitem method.
1495 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001496 self.visit(node.node, frame)
1497 self.write('[')
1498 self.visit(node.arg, frame)
1499 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001500 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001501 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001502 self.visit(node.node, frame)
1503 self.write(', ')
1504 self.visit(node.arg, frame)
1505 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001506
1507 def visit_Slice(self, node, frame):
1508 if node.start is not None:
1509 self.visit(node.start, frame)
1510 self.write(':')
1511 if node.stop is not None:
1512 self.visit(node.stop, frame)
1513 if node.step is not None:
1514 self.write(':')
1515 self.visit(node.step, frame)
1516
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001517 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001518 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001519 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001520 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001521 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001522 if getattr(func, 'contextfilter', False):
1523 self.write('context, ')
Armin Ronacher8346bd72010-03-14 19:43:47 +01001524 elif getattr(func, 'evalcontextfilter', False):
1525 self.write('context.eval_ctx, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001526 elif getattr(func, 'environmentfilter', False):
1527 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001528
1529 # if the filter node is None we are inside a filter block
1530 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001531 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001532 self.visit(node.node, frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001533 elif frame.eval_ctx.volatile:
1534 self.write('(context.eval_ctx.autoescape and'
1535 ' Markup(concat(%s)) or concat(%s))' %
1536 (frame.buffer, frame.buffer))
1537 elif frame.eval_ctx.autoescape:
Armin Ronacher3da90312008-05-23 16:37:28 +02001538 self.write('Markup(concat(%s))' % frame.buffer)
1539 else:
1540 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001541 self.signature(node, frame)
1542 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001543
1544 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001545 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001546 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001547 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001548 self.visit(node.node, frame)
1549 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001550 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001551
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001552 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001553 def write_expr2():
1554 if node.expr2 is not None:
1555 return self.visit(node.expr2, frame)
1556 self.write('environment.undefined(%r)' % ('the inline if-'
1557 'expression on %s evaluated to false and '
1558 'no else section was defined.' % self.position(node)))
1559
Cory Benfielde8acd5b2013-05-18 11:58:57 +01001560 self.write('(')
1561 self.visit(node.expr1, frame)
1562 self.write(' if ')
1563 self.visit(node.test, frame)
1564 self.write(' else ')
1565 write_expr2()
1566 self.write(')')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001567
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001568 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001569 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001570 self.write('environment.call(context, ')
1571 else:
1572 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001573 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001574 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001575 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001576 self.write(')')
1577
1578 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001579 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001580 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001581
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001582 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001583
1584 def visit_MarkSafe(self, node, frame):
1585 self.write('Markup(')
1586 self.visit(node.expr, frame)
1587 self.write(')')
1588
Armin Ronacher4da90342010-05-29 17:35:10 +02001589 def visit_MarkSafeIfAutoescape(self, node, frame):
1590 self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1591 self.visit(node.expr, frame)
1592 self.write(')')
1593
Armin Ronachered1e0d42008-05-18 20:25:28 +02001594 def visit_EnvironmentAttribute(self, node, frame):
1595 self.write('environment.' + node.name)
1596
1597 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001598 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001599
1600 def visit_ImportedName(self, node, frame):
1601 self.write(self.import_aliases[node.importname])
1602
1603 def visit_InternalName(self, node, frame):
1604 self.write(node.name)
1605
Armin Ronacher6df604e2008-05-23 22:18:38 +02001606 def visit_ContextReference(self, node, frame):
1607 self.write('context')
1608
Armin Ronachered1e0d42008-05-18 20:25:28 +02001609 def visit_Continue(self, node, frame):
1610 self.writeline('continue', node)
1611
1612 def visit_Break(self, node, frame):
1613 self.writeline('break', node)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001614
1615 def visit_Scope(self, node, frame):
1616 scope_frame = frame.inner()
1617 scope_frame.inspect(node.iter_child_nodes())
1618 aliases = self.push_scope(scope_frame)
1619 self.pull_locals(scope_frame)
1620 self.blockvisit(node.body, scope_frame)
1621 self.pop_scope(aliases, scope_frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001622
1623 def visit_EvalContextModifier(self, node, frame):
1624 for keyword in node.options:
1625 self.writeline('context.eval_ctx.%s = ' % keyword.key)
1626 self.visit(keyword.value, frame)
1627 try:
1628 val = keyword.value.as_const(frame.eval_ctx)
1629 except nodes.Impossible:
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001630 frame.eval_ctx.volatile = True
Armin Ronacher8346bd72010-03-14 19:43:47 +01001631 else:
1632 setattr(frame.eval_ctx, keyword.key, val)
1633
1634 def visit_ScopedEvalContextModifier(self, node, frame):
1635 old_ctx_name = self.temporary_identifier()
1636 safed_ctx = frame.eval_ctx.save()
1637 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1638 self.visit_EvalContextModifier(node, frame)
1639 for child in node.body:
1640 self.visit(child, frame)
1641 frame.eval_ctx.revert(safed_ctx)
1642 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)