blob: 6ea124cf1c1b3012252effddc6d9a83fc4326bab [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
21
22operators = {
23 'eq': '==',
24 'ne': '!=',
25 'gt': '>',
26 'gteq': '>=',
27 'lt': '<',
28 'lteq': '<=',
29 'in': 'in',
30 'notin': 'not in'
31}
32
Armin Ronacher3d8b7842008-04-13 13:16:50 +020033try:
Thomas Waldmanne0003552013-05-17 23:52:14 +020034 exec('(0 if 0 else 0)')
Armin Ronacher3d8b7842008-04-13 13:16:50 +020035except SyntaxError:
36 have_condexpr = False
37else:
38 have_condexpr = True
39
40
Armin Ronacher0d242be2010-02-10 01:35:13 +010041# what method to iterate over items do we want to use for dict iteration
42# in generated code? on 2.x let's go with iteritems, on 3.x with items
43if hasattr(dict, 'iteritems'):
44 dict_item_iter = 'iteritems'
45else:
46 dict_item_iter = 'items'
47
48
Armin Ronacher821a4232010-02-17 07:59:38 +010049# does if 0: dummy(x) get us x into the scope?
50def unoptimize_before_dead_code():
51 x = 42
52 def f():
53 if 0: dummy(x)
54 return f
Armin Ronacher9dd7fad2013-05-18 11:36:32 +010055
56# The getattr is necessary for pypy which does not set this attribute if
57# no closure is on the function
58unoptimize_before_dead_code = bool(
59 getattr(unoptimize_before_dead_code(), '__closure__', None))
Armin Ronacher821a4232010-02-17 07:59:38 +010060
61
Armin Ronacher64b08a02010-03-12 03:17:41 +010062def generate(node, environment, name, filename, stream=None,
63 defer_init=False):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020064 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020065 if not isinstance(node, nodes.Template):
66 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher64b08a02010-03-12 03:17:41 +010067 generator = CodeGenerator(environment, name, filename, stream, defer_init)
Armin Ronachere791c2a2008-04-07 18:39:54 +020068 generator.visit(node)
69 if stream is None:
70 return generator.stream.getvalue()
71
72
Armin Ronacher4dfc9752008-04-09 15:03:29 +020073def has_safe_repr(value):
74 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020075 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020076 return True
Thomas Waldmann7d295622013-05-18 00:06:22 +020077 try:
78 range_type = xrange
79 except NameError:
80 range_type = range
81 if isinstance(value, (bool, int, float, complex, range_type, Markup) + six.string_types):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020082 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020083 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020084 for item in value:
85 if not has_safe_repr(item):
86 return False
87 return True
88 elif isinstance(value, dict):
Thomas Waldmanne0003552013-05-17 23:52:14 +020089 for key, value in six.iteritems(value):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020090 if not has_safe_repr(key):
91 return False
92 if not has_safe_repr(value):
93 return False
94 return True
95 return False
96
97
Armin Ronacherc9705c22008-04-27 21:28:03 +020098def find_undeclared(nodes, names):
99 """Check if the names passed are accessed undeclared. The return value
100 is a set of all the undeclared names from the sequence of names found.
101 """
102 visitor = UndeclaredNameVisitor(names)
103 try:
104 for node in nodes:
105 visitor.visit(node)
106 except VisitorExit:
107 pass
108 return visitor.undeclared
109
110
Armin Ronachere791c2a2008-04-07 18:39:54 +0200111class Identifiers(object):
112 """Tracks the status of identifiers in frames."""
113
114 def __init__(self):
115 # variables that are known to be declared (probably from outer
116 # frames or because they are special for the frame)
117 self.declared = set()
118
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200119 # undeclared variables from outer scopes
120 self.outer_undeclared = set()
121
Armin Ronachere791c2a2008-04-07 18:39:54 +0200122 # names that are accessed without being explicitly declared by
123 # this one or any of the outer scopes. Names can appear both in
124 # declared and undeclared.
125 self.undeclared = set()
126
127 # names that are declared locally
128 self.declared_locally = set()
129
130 # names that are declared by parameters
131 self.declared_parameter = set()
132
133 def add_special(self, name):
134 """Register a special name like `loop`."""
135 self.undeclared.discard(name)
136 self.declared.add(name)
137
Armin Ronacherda632622011-03-13 14:33:27 -0400138 def is_declared(self, name):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200139 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200140 if name in self.declared_locally or name in self.declared_parameter:
141 return True
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200142 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200143
Armin Ronacher74230e62009-10-25 12:46:31 +0100144 def copy(self):
145 return deepcopy(self)
146
Armin Ronachere791c2a2008-04-07 18:39:54 +0200147
148class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200149 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200150
Armin Ronacher8346bd72010-03-14 19:43:47 +0100151 def __init__(self, eval_ctx, parent=None):
152 self.eval_ctx = eval_ctx
Armin Ronachere791c2a2008-04-07 18:39:54 +0200153 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200154
Armin Ronacher75cfb862008-04-11 13:47:22 +0200155 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200156 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200157
Armin Ronacher75cfb862008-04-11 13:47:22 +0200158 # the root frame is basically just the outermost frame, so no if
159 # conditions. This information is used to optimize inheritance
160 # situations.
161 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200162
Armin Ronacher79668952008-09-23 22:52:46 +0200163 # in some dynamic inheritance situations the compiler needs to add
164 # write tests around output statements.
165 self.require_output_check = parent and parent.require_output_check
Armin Ronacherf40c8842008-09-17 18:51:26 +0200166
Armin Ronacherfed44b52008-04-13 19:42:53 +0200167 # inside some tags we are using a buffer rather than yield statements.
168 # this for example affects {% filter %} or {% macro %}. If a frame
169 # is buffered this variable points to the name of the list used as
170 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200171 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200172
Armin Ronacherfed44b52008-04-13 19:42:53 +0200173 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200174 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200175
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100176 # a set of actually assigned names
177 self.assigned_names = set()
178
Armin Ronacherfed44b52008-04-13 19:42:53 +0200179 # the parent of this frame
180 self.parent = parent
181
Armin Ronachere791c2a2008-04-07 18:39:54 +0200182 if parent is not None:
183 self.identifiers.declared.update(
184 parent.identifiers.declared |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200185 parent.identifiers.declared_parameter |
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100186 parent.assigned_names
Armin Ronachere791c2a2008-04-07 18:39:54 +0200187 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200188 self.identifiers.outer_undeclared.update(
189 parent.identifiers.undeclared -
190 self.identifiers.declared
191 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200192 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200193
Armin Ronacher8efc5222008-04-08 14:47:40 +0200194 def copy(self):
195 """Create a copy of the current one."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200196 rv = object.__new__(self.__class__)
197 rv.__dict__.update(self.__dict__)
198 rv.identifiers = object.__new__(self.identifiers.__class__)
199 rv.identifiers.__dict__.update(self.identifiers.__dict__)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200200 return rv
201
Armin Ronacherda632622011-03-13 14:33:27 -0400202 def inspect(self, nodes):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200203 """Walk the node and check for identifiers. If the scope is hard (eg:
204 enforce on a python level) overrides from outer scopes are tracked
205 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200206 """
Armin Ronacherda632622011-03-13 14:33:27 -0400207 visitor = FrameIdentifierVisitor(self.identifiers)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200208 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200209 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200210
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100211 def find_shadowed(self, extra=()):
212 """Find all the shadowed names. extra is an iterable of variables
213 that may be defined with `add_special` which may occour scoped.
214 """
215 i = self.identifiers
216 return (i.declared | i.outer_undeclared) & \
217 (i.declared_locally | i.declared_parameter) | \
218 set(x for x in extra if i.is_declared(x))
219
Armin Ronachere791c2a2008-04-07 18:39:54 +0200220 def inner(self):
221 """Return an inner frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100222 return Frame(self.eval_ctx, self)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200223
Armin Ronacher75cfb862008-04-11 13:47:22 +0200224 def soft(self):
225 """Return a soft frame. A soft frame may not be modified as
226 standalone thing as it shares the resources with the frame it
227 was created of, but it's not a rootlevel frame any longer.
228 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200229 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200230 rv.rootlevel = False
231 return rv
232
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200233 __copy__ = copy
234
Armin Ronachere791c2a2008-04-07 18:39:54 +0200235
Armin Ronacherc9705c22008-04-27 21:28:03 +0200236class VisitorExit(RuntimeError):
237 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
238
239
240class DependencyFinderVisitor(NodeVisitor):
241 """A visitor that collects filter and test calls."""
242
243 def __init__(self):
244 self.filters = set()
245 self.tests = set()
246
247 def visit_Filter(self, node):
248 self.generic_visit(node)
249 self.filters.add(node.name)
250
251 def visit_Test(self, node):
252 self.generic_visit(node)
253 self.tests.add(node.name)
254
255 def visit_Block(self, node):
256 """Stop visiting at blocks."""
257
258
259class UndeclaredNameVisitor(NodeVisitor):
260 """A visitor that checks if a name is accessed without being
261 declared. This is different from the frame visitor as it will
262 not stop at closure frames.
263 """
264
265 def __init__(self, names):
266 self.names = set(names)
267 self.undeclared = set()
268
269 def visit_Name(self, node):
270 if node.ctx == 'load' and node.name in self.names:
271 self.undeclared.add(node.name)
272 if self.undeclared == self.names:
273 raise VisitorExit()
274 else:
275 self.names.discard(node.name)
276
277 def visit_Block(self, node):
278 """Stop visiting a blocks."""
279
280
Armin Ronachere791c2a2008-04-07 18:39:54 +0200281class FrameIdentifierVisitor(NodeVisitor):
282 """A visitor for `Frame.inspect`."""
283
Armin Ronacherda632622011-03-13 14:33:27 -0400284 def __init__(self, identifiers):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200285 self.identifiers = identifiers
286
Armin Ronacherc9705c22008-04-27 21:28:03 +0200287 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200288 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200289 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200290 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200291 elif node.ctx == 'param':
292 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200293 elif node.ctx == 'load' and not \
Armin Ronacherda632622011-03-13 14:33:27 -0400294 self.identifiers.is_declared(node.name):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200295 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200296
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200297 def visit_If(self, node):
298 self.visit(node.test)
Armin Ronacher74230e62009-10-25 12:46:31 +0100299 real_identifiers = self.identifiers
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200300
Armin Ronacher8a672512010-04-05 18:43:07 +0200301 old_names = real_identifiers.declared_locally | \
Armin Ronacher74230e62009-10-25 12:46:31 +0100302 real_identifiers.declared_parameter
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200303
Armin Ronacher74230e62009-10-25 12:46:31 +0100304 def inner_visit(nodes):
Armin Ronacher1965e312009-10-25 13:03:08 +0100305 if not nodes:
306 return set()
Armin Ronacher74230e62009-10-25 12:46:31 +0100307 self.identifiers = real_identifiers.copy()
308 for subnode in nodes:
309 self.visit(subnode)
310 rv = self.identifiers.declared_locally - old_names
311 # we have to remember the undeclared variables of this branch
312 # because we will have to pull them.
313 real_identifiers.undeclared.update(self.identifiers.undeclared)
314 self.identifiers = real_identifiers
315 return rv
316
317 body = inner_visit(node.body)
318 else_ = inner_visit(node.else_ or ())
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200319
320 # the differences between the two branches are also pulled as
321 # undeclared variables
Armin Ronacher8a672512010-04-05 18:43:07 +0200322 real_identifiers.undeclared.update(body.symmetric_difference(else_) -
323 real_identifiers.declared)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200324
Armin Ronacher74230e62009-10-25 12:46:31 +0100325 # remember those that are declared.
326 real_identifiers.declared_locally.update(body | else_)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200327
Armin Ronacherc9705c22008-04-27 21:28:03 +0200328 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200329 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200330
Armin Ronacherc9705c22008-04-27 21:28:03 +0200331 def visit_Import(self, node):
332 self.generic_visit(node)
333 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200334
Armin Ronacherc9705c22008-04-27 21:28:03 +0200335 def visit_FromImport(self, node):
336 self.generic_visit(node)
337 for name in node.names:
338 if isinstance(name, tuple):
339 self.identifiers.declared_locally.add(name[1])
340 else:
341 self.identifiers.declared_locally.add(name)
342
343 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200344 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200345 self.visit(node.node)
346 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200347
Armin Ronacherc9705c22008-04-27 21:28:03 +0200348 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200349 """Visiting stops at for blocks. However the block sequence
350 is visited as part of the outer scope.
351 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200352 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200353
Armin Ronacherc9705c22008-04-27 21:28:03 +0200354 def visit_CallBlock(self, node):
Armin Ronacheref189442010-01-14 01:26:40 +0100355 self.visit(node.call)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200356
357 def visit_FilterBlock(self, node):
358 self.visit(node.filter)
359
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100360 def visit_Scope(self, node):
361 """Stop visiting at scopes."""
362
Armin Ronacherc9705c22008-04-27 21:28:03 +0200363 def visit_Block(self, node):
364 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200365
366
Armin Ronacher75cfb862008-04-11 13:47:22 +0200367class CompilerExit(Exception):
368 """Raised if the compiler encountered a situation where it just
369 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200370 raises such an exception is not further processed.
371 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200372
373
Armin Ronachere791c2a2008-04-07 18:39:54 +0200374class CodeGenerator(NodeVisitor):
375
Armin Ronacher64b08a02010-03-12 03:17:41 +0100376 def __init__(self, environment, name, filename, stream=None,
377 defer_init=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200378 if stream is None:
379 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200380 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200381 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200382 self.filename = filename
383 self.stream = stream
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100384 self.created_block_context = False
Armin Ronacher64b08a02010-03-12 03:17:41 +0100385 self.defer_init = defer_init
Armin Ronacherfed44b52008-04-13 19:42:53 +0200386
Armin Ronacher023b5e92008-05-08 11:03:10 +0200387 # aliases for imports
388 self.import_aliases = {}
389
Armin Ronacherfed44b52008-04-13 19:42:53 +0200390 # a registry for all blocks. Because blocks are moved out
391 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200392 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200393
394 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200395 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200396
397 # some templates have a rootlevel extends. In this case we
398 # can safely assume that we're a child template and do some
399 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200400 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200401
Armin Ronacherba3757b2008-04-16 19:43:16 +0200402 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200403 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200404
Armin Ronacherb9e78752008-05-10 23:36:28 +0200405 # registry of all filters and tests (global, not block local)
406 self.tests = {}
407 self.filters = {}
408
Armin Ronacherba3757b2008-04-16 19:43:16 +0200409 # the debug information
410 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200411 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200412
Armin Ronacherfed44b52008-04-13 19:42:53 +0200413 # the number of new lines before the next write()
414 self._new_lines = 0
415
416 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200417 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200418
419 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200420 self._first_write = True
421
Armin Ronacherfed44b52008-04-13 19:42:53 +0200422 # used by the `temporary_identifier` method to get new
423 # unique, temporary identifier
424 self._last_identifier = 0
425
426 # the current indentation
427 self._indentation = 0
428
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200429 # -- Various compilation helpers
430
Armin Ronachere2244882008-05-19 09:25:57 +0200431 def fail(self, msg, lineno):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100432 """Fail with a :exc:`TemplateAssertionError`."""
Armin Ronachere2244882008-05-19 09:25:57 +0200433 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
434
Armin Ronachere791c2a2008-04-07 18:39:54 +0200435 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200436 """Get a new unique identifier."""
437 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200438 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200439
Armin Ronachered1e0d42008-05-18 20:25:28 +0200440 def buffer(self, frame):
441 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200442 frame.buffer = self.temporary_identifier()
443 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200444
445 def return_buffer_contents(self, frame):
446 """Return the buffer contents of the frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100447 if frame.eval_ctx.volatile:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100448 self.writeline('if context.eval_ctx.autoescape:')
449 self.indent()
450 self.writeline('return Markup(concat(%s))' % frame.buffer)
451 self.outdent()
452 self.writeline('else:')
453 self.indent()
454 self.writeline('return concat(%s)' % frame.buffer)
455 self.outdent()
Armin Ronacher8346bd72010-03-14 19:43:47 +0100456 elif frame.eval_ctx.autoescape:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100457 self.writeline('return Markup(concat(%s))' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200458 else:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100459 self.writeline('return concat(%s)' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200460
Armin Ronachere791c2a2008-04-07 18:39:54 +0200461 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200462 """Indent by one."""
463 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200464
Armin Ronacher8efc5222008-04-08 14:47:40 +0200465 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200466 """Outdent by step."""
467 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200468
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200469 def start_write(self, frame, node=None):
470 """Yield or write into the frame buffer."""
471 if frame.buffer is None:
472 self.writeline('yield ', node)
473 else:
474 self.writeline('%s.append(' % frame.buffer, node)
475
476 def end_write(self, frame):
477 """End the writing process started by `start_write`."""
478 if frame.buffer is not None:
479 self.write(')')
480
481 def simple_write(self, s, frame, node=None):
482 """Simple shortcut for start_write + write + end_write."""
483 self.start_write(frame, node)
484 self.write(s)
485 self.end_write(frame)
486
Armin Ronacherf40c8842008-09-17 18:51:26 +0200487 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200488 """Visit a list of nodes as block in a frame. If the current frame
489 is no buffer a dummy ``if 0: yield None`` is written automatically
490 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200491 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200492 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200493 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200494 else:
495 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200496 try:
497 for node in nodes:
498 self.visit(node, frame)
499 except CompilerExit:
500 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200501
502 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200503 """Write a string into the output stream."""
504 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200505 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200506 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200507 self.code_lineno += self._new_lines
508 if self._write_debug_info is not None:
509 self.debug_info.append((self._write_debug_info,
510 self.code_lineno))
511 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200512 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200513 self.stream.write(' ' * self._indentation)
514 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200515 self.stream.write(x)
516
517 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200518 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200519 self.newline(node, extra)
520 self.write(x)
521
522 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200523 """Add one or more newlines before the next write."""
524 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200525 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200526 self._write_debug_info = node.lineno
527 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200528
Armin Ronacherfd310492008-05-25 00:16:51 +0200529 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200530 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200531 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200532 arguments may not include python keywords otherwise a syntax
533 error could occour. The extra keyword arguments should be given
534 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200535 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200536 # if any of the given keyword arguments is a python keyword
537 # we have to make sure that no invalid call is created.
538 kwarg_workaround = False
539 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200540 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200541 kwarg_workaround = True
542 break
543
Armin Ronacher8efc5222008-04-08 14:47:40 +0200544 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200545 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200546 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200547
548 if not kwarg_workaround:
549 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200550 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200551 self.visit(kwarg, frame)
552 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200553 for key, value in six.iteritems(extra_kwargs):
Armin Ronacherfd310492008-05-25 00:16:51 +0200554 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200555 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200556 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200557 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200558
559 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200560 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200561 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200562 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200563 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200564 for kwarg in node.kwargs:
565 self.write('%r: ' % kwarg.key)
566 self.visit(kwarg.value, frame)
567 self.write(', ')
568 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200569 for key, value in six.iteritems(extra_kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200570 self.write('%r: %s, ' % (key, value))
571 if node.dyn_kwargs is not None:
572 self.write('}, **')
573 self.visit(node.dyn_kwargs, frame)
574 self.write(')')
575 else:
576 self.write('}')
577
578 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200579 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200580 self.visit(node.dyn_kwargs, frame)
581
Armin Ronacherc9705c22008-04-27 21:28:03 +0200582 def pull_locals(self, frame):
583 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200584 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200585 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200586
587 def pull_dependencies(self, nodes):
588 """Pull all the dependencies."""
589 visitor = DependencyFinderVisitor()
590 for node in nodes:
591 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200592 for dependency in 'filters', 'tests':
593 mapping = getattr(self, dependency)
594 for name in getattr(visitor, dependency):
595 if name not in mapping:
596 mapping[name] = self.temporary_identifier()
597 self.writeline('%s = environment.%s[%r]' %
598 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200599
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100600 def unoptimize_scope(self, frame):
601 """Disable Python optimizations for the frame."""
602 # XXX: this is not that nice but it has no real overhead. It
603 # mainly works because python finds the locals before dead code
604 # is removed. If that breaks we have to add a dummy function
605 # that just accepts the arguments and does nothing.
606 if frame.identifiers.declared:
Armin Ronacher821a4232010-02-17 07:59:38 +0100607 self.writeline('%sdummy(%s)' % (
608 unoptimize_before_dead_code and 'if 0: ' or '',
609 ', '.join('l_' + name for name in frame.identifiers.declared)
610 ))
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100611
Armin Ronacher673aa882008-10-04 18:06:57 +0200612 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200613 """This function returns all the shadowed variables in a dict
614 in the form name: alias and will write the required assignments
615 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200616
Armin Ronacher673aa882008-10-04 18:06:57 +0200617 This also predefines locally declared variables from the loop
618 body because under some circumstances it may be the case that
619
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100620 `extra_vars` is passed to `Frame.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200621 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200622 aliases = {}
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100623 for name in frame.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200624 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200625 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200626 to_declare = set()
627 for name in frame.identifiers.declared_locally:
628 if name not in aliases:
629 to_declare.add('l_' + name)
630 if to_declare:
631 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200632 return aliases
633
Armin Ronacher673aa882008-10-04 18:06:57 +0200634 def pop_scope(self, aliases, frame):
635 """Restore all aliases and delete unused variables."""
Thomas Waldmanne0003552013-05-17 23:52:14 +0200636 for name, alias in six.iteritems(aliases):
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200637 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200638 to_delete = set()
639 for name in frame.identifiers.declared_locally:
640 if name not in aliases:
641 to_delete.add('l_' + name)
642 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100643 # we cannot use the del statement here because enclosed
644 # scopes can trigger a SyntaxError:
645 # a = 42; b = lambda: a; del a
646 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200647
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200648 def function_scoping(self, node, frame, children=None,
649 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200650 """In Jinja a few statements require the help of anonymous
651 functions. Those are currently macros and call blocks and in
652 the future also recursive loops. As there is currently
653 technical limitation that doesn't allow reading and writing a
654 variable in a scope where the initial value is coming from an
655 outer scope, this function tries to fall back with a common
656 error message. Additionally the frame passed is modified so
657 that the argumetns are collected and callers are looked up.
658
659 This will return the modified frame.
660 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200661 # we have to iterate twice over it, make sure that works
662 if children is None:
663 children = node.iter_child_nodes()
664 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200665 func_frame = frame.inner()
Armin Ronacherda632622011-03-13 14:33:27 -0400666 func_frame.inspect(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200667
668 # variables that are undeclared (accessed before declaration) and
669 # declared locally *and* part of an outside scope raise a template
670 # assertion error. Reason: we can't generate reasonable code from
Armin Ronacher02b42a82009-03-18 00:59:32 +0100671 # it without aliasing all the variables.
672 # this could be fixed in Python 3 where we have the nonlocal
673 # keyword or if we switch to bytecode generation
Armin Ronacher71082072008-04-12 14:19:36 +0200674 overriden_closure_vars = (
675 func_frame.identifiers.undeclared &
676 func_frame.identifiers.declared &
677 (func_frame.identifiers.declared_locally |
678 func_frame.identifiers.declared_parameter)
679 )
680 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200681 self.fail('It\'s not possible to set and access variables '
Armin Ronacherefcc0e52009-09-13 00:22:50 -0700682 'derived from an outer scope! (affects: %s)' %
Armin Ronachere2244882008-05-19 09:25:57 +0200683 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200684
685 # remove variables from a closure from the frame's undeclared
686 # identifiers.
687 func_frame.identifiers.undeclared -= (
688 func_frame.identifiers.undeclared &
689 func_frame.identifiers.declared
690 )
691
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200692 # no special variables for this scope, abort early
693 if not find_special:
694 return func_frame
695
Armin Ronacher963f97d2008-04-25 11:44:59 +0200696 func_frame.accesses_kwargs = False
697 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200698 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200699 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200700
Armin Ronacherc9705c22008-04-27 21:28:03 +0200701 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
702
703 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200704 func_frame.accesses_caller = True
705 func_frame.identifiers.add_special('caller')
706 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200707 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200708 func_frame.accesses_kwargs = True
709 func_frame.identifiers.add_special('kwargs')
710 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200711 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200712 func_frame.accesses_varargs = True
713 func_frame.identifiers.add_special('varargs')
714 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200715 return func_frame
716
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200717 def macro_body(self, node, frame, children=None):
718 """Dump the function def of a macro or call block."""
719 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100720 # macros are delayed, they never require output checks
721 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200722 args = frame.arguments
Armin Ronachereabf3dd2009-09-12 23:48:18 -0700723 # XXX: this is an ugly fix for the loop nesting bug
724 # (tests.test_old_bugs.test_loop_call_bug). This works around
725 # a identifier nesting problem we have in general. It's just more
726 # likely to happen in loops which is why we work around it. The
727 # real solution would be "nonlocal" all the identifiers that are
728 # leaking into a new python frame and might be used both unassigned
729 # and assigned.
730 if 'loop' in frame.identifiers.declared:
Armin Ronacherb4044392009-09-13 15:56:58 -0700731 args = args + ['l_loop=l_loop']
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200732 self.writeline('def macro(%s):' % ', '.join(args), node)
733 self.indent()
734 self.buffer(frame)
735 self.pull_locals(frame)
736 self.blockvisit(node.body, frame)
737 self.return_buffer_contents(frame)
738 self.outdent()
739 return frame
740
741 def macro_def(self, node, frame):
742 """Dump the macro definition for the def created by macro_body."""
743 arg_tuple = ', '.join(repr(x.name) for x in node.args)
744 name = getattr(node, 'name', None)
745 if len(node.args) == 1:
746 arg_tuple += ','
747 self.write('Macro(environment, macro, %r, (%s), (' %
748 (name, arg_tuple))
749 for arg in node.defaults:
750 self.visit(arg, frame)
751 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200752 self.write('), %r, %r, %r)' % (
753 bool(frame.accesses_kwargs),
754 bool(frame.accesses_varargs),
755 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200756 ))
757
Armin Ronacher547d0b62008-07-04 16:35:10 +0200758 def position(self, node):
759 """Return a human readable position for the node."""
760 rv = 'line %d' % node.lineno
761 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100762 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200763 return rv
764
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200765 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200766
767 def visit_Template(self, node, frame=None):
768 assert frame is None, 'no root frame allowed'
Armin Ronacher1da23d12010-04-05 18:11:18 +0200769 eval_ctx = EvalContext(self.environment, self.name)
Armin Ronacher8346bd72010-03-14 19:43:47 +0100770
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200771 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200772 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200773 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher821a4232010-02-17 07:59:38 +0100774 if not unoptimize_before_dead_code:
775 self.writeline('dummy = lambda *x: None')
Armin Ronacher8edbe492008-04-10 20:43:43 +0200776
Armin Ronacher64b08a02010-03-12 03:17:41 +0100777 # if we want a deferred initialization we cannot move the
778 # environment into a local name
779 envenv = not self.defer_init and ', environment=environment' or ''
780
Armin Ronacher75cfb862008-04-11 13:47:22 +0200781 # do we have an extends tag at all? If not, we can save some
782 # overhead by just not processing any inheritance code.
783 have_extends = node.find(nodes.Extends) is not None
784
Armin Ronacher8edbe492008-04-10 20:43:43 +0200785 # find all blocks
786 for block in node.find_all(nodes.Block):
787 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200788 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200789 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200790
Armin Ronacher023b5e92008-05-08 11:03:10 +0200791 # find all imports and import them
792 for import_ in node.find_all(nodes.ImportedName):
793 if import_.importname not in self.import_aliases:
794 imp = import_.importname
795 self.import_aliases[imp] = alias = self.temporary_identifier()
796 if '.' in imp:
797 module, obj = imp.rsplit('.', 1)
798 self.writeline('from %s import %s as %s' %
799 (module, obj, alias))
800 else:
801 self.writeline('import %s as %s' % (imp, alias))
802
803 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200804 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200805
Armin Ronacher8efc5222008-04-08 14:47:40 +0200806 # generate the root render function.
Armin Ronacher64b08a02010-03-12 03:17:41 +0100807 self.writeline('def root(context%s):' % envenv, extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200808
809 # process the root
Armin Ronacher8346bd72010-03-14 19:43:47 +0100810 frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200811 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200812 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200813 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200814 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200815 if have_extends:
816 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200817 if 'self' in find_undeclared(node.body, ('self',)):
818 frame.identifiers.add_special('self')
819 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200820 self.pull_locals(frame)
821 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200822 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200823 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200824
Armin Ronacher8efc5222008-04-08 14:47:40 +0200825 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200826 if have_extends:
827 if not self.has_known_extends:
828 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200829 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200830 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200831 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200832 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200833 self.indent()
834 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200835 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200836
837 # at this point we now have the blocks collected and can visit them too.
Thomas Waldmanne0003552013-05-17 23:52:14 +0200838 for name, block in six.iteritems(self.blocks):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100839 block_frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200840 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200841 block_frame.block = name
Armin Ronacher64b08a02010-03-12 03:17:41 +0100842 self.writeline('def block_%s(context%s):' % (name, envenv),
843 block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200844 self.indent()
845 undeclared = find_undeclared(block.body, ('self', 'super'))
846 if 'self' in undeclared:
847 block_frame.identifiers.add_special('self')
848 self.writeline('l_self = TemplateReference(context)')
849 if 'super' in undeclared:
850 block_frame.identifiers.add_special('super')
851 self.writeline('l_super = context.super(%r, '
852 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200853 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200854 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200855 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200856 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200857
Armin Ronacher75cfb862008-04-11 13:47:22 +0200858 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200859 for x in self.blocks),
860 extra=1)
861
862 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200863 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
864 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200865
Armin Ronachere791c2a2008-04-07 18:39:54 +0200866 def visit_Block(self, node, frame):
867 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200868 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200869 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200870 # if we know that we are a child template, there is no need to
871 # check if we are one
872 if self.has_known_extends:
873 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200874 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200875 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200876 self.indent()
877 level += 1
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100878 context = node.scoped and 'context.derived(locals())' or 'context'
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100879 self.writeline('for event in context.blocks[%r][0](%s):' % (
880 node.name, context), node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200881 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200882 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200883 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200884
885 def visit_Extends(self, node, frame):
886 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200887 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200888 self.fail('cannot use extend from a non top-level scope',
889 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200890
Armin Ronacher7fb38972008-04-11 13:54:28 +0200891 # if the number of extends statements in general is zero so
892 # far, we don't have to add a check if something extended
893 # the template before this one.
894 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200895
Armin Ronacher7fb38972008-04-11 13:54:28 +0200896 # if we have a known extends we just add a template runtime
897 # error into the generated code. We could catch that at compile
898 # time too, but i welcome it not to confuse users by throwing the
899 # same error at different times just "because we can".
900 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200901 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200902 self.indent()
903 self.writeline('raise TemplateRuntimeError(%r)' %
904 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200905 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200906
Armin Ronacher7fb38972008-04-11 13:54:28 +0200907 # if we have a known extends already we don't need that code here
908 # as we know that the template execution will end here.
909 if self.has_known_extends:
910 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200911
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200912 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200913 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200914 self.write(', %r)' % self.name)
915 self.writeline('for name, parent_block in parent_template.'
Armin Ronacher0d242be2010-02-10 01:35:13 +0100916 'blocks.%s():' % dict_item_iter)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200917 self.indent()
918 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200919 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200920 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200921
922 # if this extends statement was in the root level we can take
923 # advantage of that information and simplify the generated code
924 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200925 if frame.rootlevel:
926 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200927
Armin Ronacher7fb38972008-04-11 13:54:28 +0200928 # and now we have one more
929 self.extends_so_far += 1
930
Armin Ronacherf059ec12008-04-11 22:21:00 +0200931 def visit_Include(self, node, frame):
932 """Handles includes."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100933 if node.with_context:
934 self.unoptimize_scope(frame)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100935 if node.ignore_missing:
936 self.writeline('try:')
937 self.indent()
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100938
939 func_name = 'get_or_select_template'
940 if isinstance(node.template, nodes.Const):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200941 if isinstance(node.template.value, six.string_types):
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100942 func_name = 'get_template'
943 elif isinstance(node.template.value, (tuple, list)):
944 func_name = 'select_template'
945 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
946 func_name = 'select_template'
947
948 self.writeline('template = environment.%s(' % func_name, node)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100949 self.visit(node.template, frame)
950 self.write(', %r)' % self.name)
951 if node.ignore_missing:
952 self.outdent()
953 self.writeline('except TemplateNotFound:')
954 self.indent()
955 self.writeline('pass')
956 self.outdent()
957 self.writeline('else:')
958 self.indent()
959
Armin Ronacherea847c52008-05-02 20:04:32 +0200960 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200961 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200962 'template.new_context(context.parent, True, '
963 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200964 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100965 self.writeline('for event in template.module._body_stream:')
966
Armin Ronacherf059ec12008-04-11 22:21:00 +0200967 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200968 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200969 self.outdent()
970
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100971 if node.ignore_missing:
972 self.outdent()
973
Armin Ronacher0611e492008-04-25 23:44:14 +0200974 def visit_Import(self, node, frame):
975 """Visit regular imports."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100976 if node.with_context:
977 self.unoptimize_scope(frame)
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200978 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200979 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200980 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200981 self.write('environment.get_template(')
982 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200983 self.write(', %r).' % self.name)
984 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200985 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200986 else:
987 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200988 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200989 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100990 frame.assigned_names.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200991
992 def visit_FromImport(self, node, frame):
993 """Visit named imports."""
994 self.newline(node)
995 self.write('included_template = environment.get_template(')
996 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200997 self.write(', %r).' % self.name)
998 if node.with_context:
999 self.write('make_module(context.parent, True)')
1000 else:
1001 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +02001002
1003 var_names = []
1004 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +02001005 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +02001006 if isinstance(name, tuple):
1007 name, alias = name
1008 else:
1009 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001010 self.writeline('l_%s = getattr(included_template, '
1011 '%r, missing)' % (alias, name))
1012 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +02001013 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001014 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +02001015 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +02001016 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001017 (alias, 'the template %%r (imported on %s) does '
1018 'not export the requested name %s' % (
1019 self.position(node),
1020 repr(name)
1021 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +02001022 self.outdent()
1023 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +02001024 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +02001025 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +02001026 discarded_names.append(alias)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001027 frame.assigned_names.add(alias)
Armin Ronachera78d2762008-05-15 23:18:07 +02001028
1029 if var_names:
1030 if len(var_names) == 1:
1031 name = var_names[0]
1032 self.writeline('context.vars[%r] = l_%s' % (name, name))
1033 else:
1034 self.writeline('context.vars.update({%s})' % ', '.join(
1035 '%r: l_%s' % (name, name) for name in var_names
1036 ))
1037 if discarded_names:
1038 if len(discarded_names) == 1:
1039 self.writeline('context.exported_vars.discard(%r)' %
1040 discarded_names[0])
1041 else:
1042 self.writeline('context.exported_vars.difference_'
1043 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +02001044
Armin Ronachere791c2a2008-04-07 18:39:54 +02001045 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001046 # when calculating the nodes for the inner frame we have to exclude
1047 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001048 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001049 if node.recursive:
1050 loop_frame = self.function_scoping(node, frame, children,
1051 find_special=False)
1052 else:
1053 loop_frame = frame.inner()
1054 loop_frame.inspect(children)
1055
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001056 # try to figure out if we have an extended loop. An extended loop
1057 # is necessary if the loop is in recursive mode if the special loop
1058 # variable is accessed in the body.
1059 extended_loop = node.recursive or 'loop' in \
1060 find_undeclared(node.iter_child_nodes(
1061 only=('body',)), ('loop',))
1062
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001063 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +02001064 # variables at that point. Because loops can be nested but the loop
1065 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001066 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +02001067 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001068
1069 # otherwise we set up a buffer and add a function def
1070 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001071 self.writeline('def loop(reciter, loop_render_func):', node)
1072 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +02001073 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001074 aliases = {}
1075
Armin Ronacherff53c782008-08-13 18:55:50 +02001076 # make sure the loop variable is a special one and raise a template
1077 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +02001078 if extended_loop:
1079 loop_frame.identifiers.add_special('loop')
Armin Ronacherff53c782008-08-13 18:55:50 +02001080 for name in node.find_all(nodes.Name):
1081 if name.ctx == 'store' and name.name == 'loop':
1082 self.fail('Can\'t assign to special loop variable '
1083 'in for-loop target', name.lineno)
1084
Armin Ronacherc9705c22008-04-27 21:28:03 +02001085 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001086 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001087 iteration_indicator = self.temporary_identifier()
1088 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001089
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001090 # Create a fake parent loop if the else or test section of a
1091 # loop is accessing the special loop variable and no parent loop
1092 # exists.
1093 if 'loop' not in aliases and 'loop' in find_undeclared(
1094 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1095 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001096 ("'loop' is undefined. the filter section of a loop as well "
Armin Ronacherbc56cd22011-01-15 18:35:45 +01001097 "as the else block don't have access to the special 'loop'"
Armin Ronacher547d0b62008-07-04 16:35:10 +02001098 " variable of the current loop. Because there is no parent "
1099 "loop it's undefined. Happened in loop on %s" %
1100 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001101
1102 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001103 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +02001104 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001105
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001106 # if we have an extened loop and a node test, we filter in the
1107 # "outer frame".
1108 if extended_loop and node.test is not None:
1109 self.write('(')
1110 self.visit(node.target, loop_frame)
1111 self.write(' for ')
1112 self.visit(node.target, loop_frame)
1113 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001114 if node.recursive:
1115 self.write('reciter')
1116 else:
1117 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001118 self.write(' if (')
1119 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001120 self.visit(node.test, test_frame)
1121 self.write('))')
1122
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001123 elif node.recursive:
1124 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001125 else:
1126 self.visit(node.iter, loop_frame)
1127
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001128 if node.recursive:
1129 self.write(', recurse=loop_render_func):')
1130 else:
1131 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001132
1133 # tests in not extended loops become a continue
1134 if not extended_loop and node.test is not None:
1135 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +02001136 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +02001137 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001138 self.write(':')
1139 self.indent()
1140 self.writeline('continue')
1141 self.outdent(2)
1142
Armin Ronacherc9705c22008-04-27 21:28:03 +02001143 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001144 self.blockvisit(node.body, loop_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001145 if node.else_:
1146 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001147 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001148
1149 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001150 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001151 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001152 self.blockvisit(node.else_, loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001153 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001154
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001155 # reset the aliases if there are any.
Armin Ronachercebd8382008-12-25 18:33:46 +01001156 if not node.recursive:
1157 self.pop_scope(aliases, loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001158
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001159 # if the node was recursive we have to return the buffer contents
1160 # and start the iteration code
1161 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001162 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001163 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001164 self.start_write(frame, node)
1165 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001166 self.visit(node.iter, frame)
1167 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001168 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001169
Armin Ronachere791c2a2008-04-07 18:39:54 +02001170 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001171 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001172 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001173 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001174 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001175 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001176 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001177 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001178 if node.else_:
1179 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001180 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001181 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001182 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001183
Armin Ronacher8efc5222008-04-08 14:47:40 +02001184 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001185 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001186 self.newline()
1187 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001188 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001189 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001190 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001191 self.write('l_%s = ' % node.name)
1192 self.macro_def(node, macro_frame)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001193 frame.assigned_names.add(node.name)
Armin Ronacher71082072008-04-12 14:19:36 +02001194
1195 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001196 children = node.iter_child_nodes(exclude=('call',))
1197 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001198 self.writeline('caller = ')
1199 self.macro_def(node, call_frame)
1200 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001201 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001202 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001203
1204 def visit_FilterBlock(self, node, frame):
1205 filter_frame = frame.inner()
1206 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacher673aa882008-10-04 18:06:57 +02001207 aliases = self.push_scope(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001208 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001209 self.buffer(filter_frame)
Armin Ronacherf40c8842008-09-17 18:51:26 +02001210 self.blockvisit(node.body, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001211 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001212 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001213 self.end_write(frame)
Armin Ronacher673aa882008-10-04 18:06:57 +02001214 self.pop_scope(aliases, filter_frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001215
Armin Ronachere791c2a2008-04-07 18:39:54 +02001216 def visit_ExprStmt(self, node, frame):
1217 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001218 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001219
1220 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001221 # if we have a known extends statement, we don't output anything
Armin Ronacher79668952008-09-23 22:52:46 +02001222 # if we are in a require_output_check section
1223 if self.has_known_extends and frame.require_output_check:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001224 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001225
Armin Ronacher665bfb82008-07-14 13:41:46 +02001226 if self.environment.finalize:
Thomas Waldmanne0003552013-05-17 23:52:14 +02001227 finalize = lambda x: six.text_type(self.environment.finalize(x))
Armin Ronacher665bfb82008-07-14 13:41:46 +02001228 else:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001229 finalize = six.text_type
Armin Ronacher665bfb82008-07-14 13:41:46 +02001230
Armin Ronacher79668952008-09-23 22:52:46 +02001231 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001232 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001233 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001234 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001235 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001236 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001237
Armin Ronachere791c2a2008-04-07 18:39:54 +02001238 # try to evaluate as many chunks as possible into a static
1239 # string at compile time.
1240 body = []
1241 for child in node.nodes:
1242 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001243 const = child.as_const(frame.eval_ctx)
Armin Ronacher9cf95912008-05-24 19:54:43 +02001244 except nodes.Impossible:
1245 body.append(child)
1246 continue
Armin Ronacher8346bd72010-03-14 19:43:47 +01001247 # the frame can't be volatile here, becaus otherwise the
1248 # as_const() function would raise an Impossible exception
1249 # at that point.
Armin Ronacher9cf95912008-05-24 19:54:43 +02001250 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001251 if frame.eval_ctx.autoescape:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001252 if hasattr(const, '__html__'):
1253 const = const.__html__()
1254 else:
1255 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001256 const = finalize(const)
Ian Lewisab014bd2010-10-31 20:29:28 +09001257 except Exception:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001258 # if something goes wrong here we evaluate the node
1259 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001260 body.append(child)
1261 continue
1262 if body and isinstance(body[-1], list):
1263 body[-1].append(const)
1264 else:
1265 body.append([const])
1266
Armin Ronachered1e0d42008-05-18 20:25:28 +02001267 # if we have less than 3 nodes or a buffer we yield or extend/append
1268 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001269 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001270 # for one item we append, for more we extend
1271 if len(body) == 1:
1272 self.writeline('%s.append(' % frame.buffer)
1273 else:
1274 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001275 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001276 for item in body:
1277 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001278 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001279 if frame.buffer is None:
1280 self.writeline('yield ' + val)
1281 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001282 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001283 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001284 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001285 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001286 else:
1287 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001288 close = 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001289 if frame.eval_ctx.volatile:
1290 self.write('(context.eval_ctx.autoescape and'
1291 ' escape or to_string)(')
1292 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001293 self.write('escape(')
1294 else:
Armin Ronacherbd357722009-08-05 20:25:06 +02001295 self.write('to_string(')
Armin Ronacherd1342312008-04-28 12:20:12 +02001296 if self.environment.finalize is not None:
1297 self.write('environment.finalize(')
1298 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001299 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001300 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001301 if frame.buffer is not None:
1302 self.write(', ')
1303 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001304 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001305 self.outdent()
1306 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001307
1308 # otherwise we create a format string as this is faster in that case
1309 else:
1310 format = []
1311 arguments = []
1312 for item in body:
1313 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001314 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001315 else:
1316 format.append('%s')
1317 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001318 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001319 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001320 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001321 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001322 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001323 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001324 close = 0
Armin Ronacher8346bd72010-03-14 19:43:47 +01001325 if frame.eval_ctx.volatile:
1326 self.write('(context.eval_ctx.autoescape and'
1327 ' escape or to_string)(')
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001328 close += 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001329 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001330 self.write('escape(')
1331 close += 1
1332 if self.environment.finalize is not None:
1333 self.write('environment.finalize(')
1334 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001335 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001336 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001337 self.outdent()
1338 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001339
Armin Ronacher7fb38972008-04-11 13:54:28 +02001340 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001341 self.outdent()
1342
Armin Ronacher8efc5222008-04-08 14:47:40 +02001343 def visit_Assign(self, node, frame):
1344 self.newline(node)
1345 # toplevel assignments however go into the local namespace and
1346 # the current template's context. We create a copy of the frame
1347 # here and add a set so that the Name visitor can add the assigned
1348 # names here.
1349 if frame.toplevel:
1350 assignment_frame = frame.copy()
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001351 assignment_frame.toplevel_assignments = set()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001352 else:
1353 assignment_frame = frame
1354 self.visit(node.target, assignment_frame)
1355 self.write(' = ')
1356 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001357
1358 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001359 if frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001360 public_names = [x for x in assignment_frame.toplevel_assignments
Armin Ronacher903d1682008-05-23 00:51:58 +02001361 if not x.startswith('_')]
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001362 if len(assignment_frame.toplevel_assignments) == 1:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001363 name = six.advance_iterator(iter(assignment_frame.toplevel_assignments))
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001364 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001365 else:
1366 self.writeline('context.vars.update({')
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001367 for idx, name in enumerate(assignment_frame.toplevel_assignments):
Armin Ronacher69e12db2008-05-12 09:00:03 +02001368 if idx:
1369 self.write(', ')
1370 self.write('%r: l_%s' % (name, name))
1371 self.write('})')
1372 if public_names:
1373 if len(public_names) == 1:
1374 self.writeline('context.exported_vars.add(%r)' %
1375 public_names[0])
1376 else:
1377 self.writeline('context.exported_vars.update((%s))' %
1378 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001379
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001380 # -- Expression Visitors
1381
Armin Ronachere791c2a2008-04-07 18:39:54 +02001382 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001383 if node.ctx == 'store' and frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001384 frame.toplevel_assignments.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001385 self.write('l_' + node.name)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001386 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001387
1388 def visit_Const(self, node, frame):
1389 val = node.value
1390 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001391 self.write(str(val))
1392 else:
1393 self.write(repr(val))
1394
Armin Ronacher5411ce72008-05-25 11:36:22 +02001395 def visit_TemplateData(self, node, frame):
Armin Ronacherffaa2e72010-05-29 20:57:16 +02001396 try:
1397 self.write(repr(node.as_const(frame.eval_ctx)))
1398 except nodes.Impossible:
1399 self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)'
1400 % node.data)
Armin Ronacher5411ce72008-05-25 11:36:22 +02001401
Armin Ronacher8efc5222008-04-08 14:47:40 +02001402 def visit_Tuple(self, node, frame):
1403 self.write('(')
1404 idx = -1
1405 for idx, item in enumerate(node.items):
1406 if idx:
1407 self.write(', ')
1408 self.visit(item, frame)
1409 self.write(idx == 0 and ',)' or ')')
1410
Armin Ronacher8edbe492008-04-10 20:43:43 +02001411 def visit_List(self, node, frame):
1412 self.write('[')
1413 for idx, item in enumerate(node.items):
1414 if idx:
1415 self.write(', ')
1416 self.visit(item, frame)
1417 self.write(']')
1418
1419 def visit_Dict(self, node, frame):
1420 self.write('{')
1421 for idx, item in enumerate(node.items):
1422 if idx:
1423 self.write(', ')
1424 self.visit(item.key, frame)
1425 self.write(': ')
1426 self.visit(item.value, frame)
1427 self.write('}')
1428
Armin Ronachera9195382010-11-29 13:21:57 +01001429 def binop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001430 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001431 if self.environment.sandboxed and \
1432 operator in self.environment.intercepted_binops:
1433 self.write('environment.call_binop(context, %r, ' % operator)
1434 self.visit(node.left, frame)
1435 self.write(', ')
1436 self.visit(node.right, frame)
1437 else:
1438 self.write('(')
1439 self.visit(node.left, frame)
1440 self.write(' %s ' % operator)
1441 self.visit(node.right, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001442 self.write(')')
1443 return visitor
1444
Armin Ronachera9195382010-11-29 13:21:57 +01001445 def uaop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001446 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001447 if self.environment.sandboxed and \
1448 operator in self.environment.intercepted_unops:
1449 self.write('environment.call_unop(context, %r, ' % operator)
1450 self.visit(node.node, frame)
1451 else:
1452 self.write('(' + operator)
1453 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001454 self.write(')')
1455 return visitor
1456
1457 visit_Add = binop('+')
1458 visit_Sub = binop('-')
1459 visit_Mul = binop('*')
1460 visit_Div = binop('/')
1461 visit_FloorDiv = binop('//')
1462 visit_Pow = binop('**')
1463 visit_Mod = binop('%')
Armin Ronachera9195382010-11-29 13:21:57 +01001464 visit_And = binop('and', interceptable=False)
1465 visit_Or = binop('or', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001466 visit_Pos = uaop('+')
1467 visit_Neg = uaop('-')
Armin Ronachera9195382010-11-29 13:21:57 +01001468 visit_Not = uaop('not ', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001469 del binop, uaop
1470
Armin Ronacherd1342312008-04-28 12:20:12 +02001471 def visit_Concat(self, node, frame):
Armin Ronacher8346bd72010-03-14 19:43:47 +01001472 if frame.eval_ctx.volatile:
1473 func_name = '(context.eval_ctx.volatile and' \
1474 ' markup_join or unicode_join)'
1475 elif frame.eval_ctx.autoescape:
1476 func_name = 'markup_join'
1477 else:
1478 func_name = 'unicode_join'
1479 self.write('%s((' % func_name)
Armin Ronacherd1342312008-04-28 12:20:12 +02001480 for arg in node.nodes:
1481 self.visit(arg, frame)
1482 self.write(', ')
1483 self.write('))')
1484
Armin Ronachere791c2a2008-04-07 18:39:54 +02001485 def visit_Compare(self, node, frame):
1486 self.visit(node.expr, frame)
1487 for op in node.ops:
1488 self.visit(op, frame)
1489
1490 def visit_Operand(self, node, frame):
1491 self.write(' %s ' % operators[node.op])
1492 self.visit(node.expr, frame)
1493
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001494 def visit_Getattr(self, node, frame):
1495 self.write('environment.getattr(')
1496 self.visit(node.node, frame)
1497 self.write(', %r)' % node.attr)
1498
1499 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001500 # slices bypass the environment getitem method.
1501 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001502 self.visit(node.node, frame)
1503 self.write('[')
1504 self.visit(node.arg, frame)
1505 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001506 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001507 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001508 self.visit(node.node, frame)
1509 self.write(', ')
1510 self.visit(node.arg, frame)
1511 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001512
1513 def visit_Slice(self, node, frame):
1514 if node.start is not None:
1515 self.visit(node.start, frame)
1516 self.write(':')
1517 if node.stop is not None:
1518 self.visit(node.stop, frame)
1519 if node.step is not None:
1520 self.write(':')
1521 self.visit(node.step, frame)
1522
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001523 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001524 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001525 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001526 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001527 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001528 if getattr(func, 'contextfilter', False):
1529 self.write('context, ')
Armin Ronacher8346bd72010-03-14 19:43:47 +01001530 elif getattr(func, 'evalcontextfilter', False):
1531 self.write('context.eval_ctx, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001532 elif getattr(func, 'environmentfilter', False):
1533 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001534
1535 # if the filter node is None we are inside a filter block
1536 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001537 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001538 self.visit(node.node, frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001539 elif frame.eval_ctx.volatile:
1540 self.write('(context.eval_ctx.autoescape and'
1541 ' Markup(concat(%s)) or concat(%s))' %
1542 (frame.buffer, frame.buffer))
1543 elif frame.eval_ctx.autoescape:
Armin Ronacher3da90312008-05-23 16:37:28 +02001544 self.write('Markup(concat(%s))' % frame.buffer)
1545 else:
1546 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001547 self.signature(node, frame)
1548 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001549
1550 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001551 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001552 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001553 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001554 self.visit(node.node, frame)
1555 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001556 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001557
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001558 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001559 def write_expr2():
1560 if node.expr2 is not None:
1561 return self.visit(node.expr2, frame)
1562 self.write('environment.undefined(%r)' % ('the inline if-'
1563 'expression on %s evaluated to false and '
1564 'no else section was defined.' % self.position(node)))
1565
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001566 if not have_condexpr:
1567 self.write('((')
1568 self.visit(node.test, frame)
1569 self.write(') and (')
1570 self.visit(node.expr1, frame)
1571 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001572 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001573 self.write(',))[0]')
1574 else:
1575 self.write('(')
1576 self.visit(node.expr1, frame)
1577 self.write(' if ')
1578 self.visit(node.test, frame)
1579 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001580 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001581 self.write(')')
1582
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001583 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001584 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001585 self.write('environment.call(context, ')
1586 else:
1587 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001588 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001589 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001590 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001591 self.write(')')
1592
1593 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001594 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001595 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001596
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001597 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001598
1599 def visit_MarkSafe(self, node, frame):
1600 self.write('Markup(')
1601 self.visit(node.expr, frame)
1602 self.write(')')
1603
Armin Ronacher4da90342010-05-29 17:35:10 +02001604 def visit_MarkSafeIfAutoescape(self, node, frame):
1605 self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1606 self.visit(node.expr, frame)
1607 self.write(')')
1608
Armin Ronachered1e0d42008-05-18 20:25:28 +02001609 def visit_EnvironmentAttribute(self, node, frame):
1610 self.write('environment.' + node.name)
1611
1612 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001613 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001614
1615 def visit_ImportedName(self, node, frame):
1616 self.write(self.import_aliases[node.importname])
1617
1618 def visit_InternalName(self, node, frame):
1619 self.write(node.name)
1620
Armin Ronacher6df604e2008-05-23 22:18:38 +02001621 def visit_ContextReference(self, node, frame):
1622 self.write('context')
1623
Armin Ronachered1e0d42008-05-18 20:25:28 +02001624 def visit_Continue(self, node, frame):
1625 self.writeline('continue', node)
1626
1627 def visit_Break(self, node, frame):
1628 self.writeline('break', node)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001629
1630 def visit_Scope(self, node, frame):
1631 scope_frame = frame.inner()
1632 scope_frame.inspect(node.iter_child_nodes())
1633 aliases = self.push_scope(scope_frame)
1634 self.pull_locals(scope_frame)
1635 self.blockvisit(node.body, scope_frame)
1636 self.pop_scope(aliases, scope_frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001637
1638 def visit_EvalContextModifier(self, node, frame):
1639 for keyword in node.options:
1640 self.writeline('context.eval_ctx.%s = ' % keyword.key)
1641 self.visit(keyword.value, frame)
1642 try:
1643 val = keyword.value.as_const(frame.eval_ctx)
1644 except nodes.Impossible:
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001645 frame.eval_ctx.volatile = True
Armin Ronacher8346bd72010-03-14 19:43:47 +01001646 else:
1647 setattr(frame.eval_ctx, keyword.key, val)
1648
1649 def visit_ScopedEvalContextModifier(self, node, frame):
1650 old_ctx_name = self.temporary_identifier()
1651 safed_ctx = frame.eval_ctx.save()
1652 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1653 self.visit_EvalContextModifier(node, frame)
1654 for child in node.body:
1655 self.visit(child, frame)
1656 frame.eval_ctx.revert(safed_ctx)
1657 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)