blob: 4ee39f89f793af71b78955fc2d3c297f74eae1cf [file] [log] [blame]
Armin Ronachere791c2a2008-04-07 18:39:54 +02001# -*- coding: utf-8 -*-
2"""
3 jinja2.compiler
4 ~~~~~~~~~~~~~~~
5
6 Compiles nodes into python code.
7
Armin Ronacher55494e42010-01-22 09:41:48 +01008 :copyright: (c) 2010 by the Jinja Team.
Armin Ronacher7af781c2010-02-09 16:05:08 +01009 :license: BSD, see LICENSE for more details.
Armin Ronachere791c2a2008-04-07 18:39:54 +020010"""
Armin Ronacherd1ff8582008-05-11 00:30:43 +020011from itertools import chain
Armin Ronacher74230e62009-10-25 12:46:31 +010012from copy import deepcopy
Armin Ronachere791c2a2008-04-07 18:39:54 +020013from jinja2 import nodes
Armin Ronacher8346bd72010-03-14 19:43:47 +010014from jinja2.nodes import EvalContext
Armin Ronacher9573b662010-12-21 00:44:34 +010015from jinja2.visitor import NodeVisitor
Armin Ronachere791c2a2008-04-07 18:39:54 +020016from jinja2.exceptions import TemplateAssertionError
Thomas Waldmann7d295622013-05-18 00:06:22 +020017from jinja2.utils import Markup, concat, escape, is_python_keyword
Thomas Waldmanne0003552013-05-17 23:52:14 +020018import six
Thomas Waldmann7d295622013-05-18 00:06:22 +020019from six.moves import cStringIO as StringIO
20from six.moves import map, zip
Armin Ronachere791c2a2008-04-07 18:39:54 +020021
22
23operators = {
24 'eq': '==',
25 'ne': '!=',
26 'gt': '>',
27 'gteq': '>=',
28 'lt': '<',
29 'lteq': '<=',
30 'in': 'in',
31 'notin': 'not in'
32}
33
Armin Ronacher3d8b7842008-04-13 13:16:50 +020034try:
Thomas Waldmanne0003552013-05-17 23:52:14 +020035 exec('(0 if 0 else 0)')
Armin Ronacher3d8b7842008-04-13 13:16:50 +020036except SyntaxError:
37 have_condexpr = False
38else:
39 have_condexpr = True
40
41
Armin Ronacher0d242be2010-02-10 01:35:13 +010042# what method to iterate over items do we want to use for dict iteration
43# in generated code? on 2.x let's go with iteritems, on 3.x with items
44if hasattr(dict, 'iteritems'):
45 dict_item_iter = 'iteritems'
46else:
47 dict_item_iter = 'items'
48
49
Armin Ronacher821a4232010-02-17 07:59:38 +010050# does if 0: dummy(x) get us x into the scope?
51def unoptimize_before_dead_code():
52 x = 42
53 def f():
54 if 0: dummy(x)
55 return f
Thomas Waldmanne0003552013-05-17 23:52:14 +020056unoptimize_before_dead_code = bool(unoptimize_before_dead_code().__closure__)
Armin Ronacher821a4232010-02-17 07:59:38 +010057
58
Armin Ronacher64b08a02010-03-12 03:17:41 +010059def generate(node, environment, name, filename, stream=None,
60 defer_init=False):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020061 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020062 if not isinstance(node, nodes.Template):
63 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher64b08a02010-03-12 03:17:41 +010064 generator = CodeGenerator(environment, name, filename, stream, defer_init)
Armin Ronachere791c2a2008-04-07 18:39:54 +020065 generator.visit(node)
66 if stream is None:
67 return generator.stream.getvalue()
68
69
Armin Ronacher4dfc9752008-04-09 15:03:29 +020070def has_safe_repr(value):
71 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020072 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020073 return True
Thomas Waldmann7d295622013-05-18 00:06:22 +020074 try:
75 range_type = xrange
76 except NameError:
77 range_type = range
78 if isinstance(value, (bool, int, float, complex, range_type, Markup) + six.string_types):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020079 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020080 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020081 for item in value:
82 if not has_safe_repr(item):
83 return False
84 return True
85 elif isinstance(value, dict):
Thomas Waldmanne0003552013-05-17 23:52:14 +020086 for key, value in six.iteritems(value):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020087 if not has_safe_repr(key):
88 return False
89 if not has_safe_repr(value):
90 return False
91 return True
92 return False
93
94
Armin Ronacherc9705c22008-04-27 21:28:03 +020095def find_undeclared(nodes, names):
96 """Check if the names passed are accessed undeclared. The return value
97 is a set of all the undeclared names from the sequence of names found.
98 """
99 visitor = UndeclaredNameVisitor(names)
100 try:
101 for node in nodes:
102 visitor.visit(node)
103 except VisitorExit:
104 pass
105 return visitor.undeclared
106
107
Armin Ronachere791c2a2008-04-07 18:39:54 +0200108class Identifiers(object):
109 """Tracks the status of identifiers in frames."""
110
111 def __init__(self):
112 # variables that are known to be declared (probably from outer
113 # frames or because they are special for the frame)
114 self.declared = set()
115
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200116 # undeclared variables from outer scopes
117 self.outer_undeclared = set()
118
Armin Ronachere791c2a2008-04-07 18:39:54 +0200119 # names that are accessed without being explicitly declared by
120 # this one or any of the outer scopes. Names can appear both in
121 # declared and undeclared.
122 self.undeclared = set()
123
124 # names that are declared locally
125 self.declared_locally = set()
126
127 # names that are declared by parameters
128 self.declared_parameter = set()
129
130 def add_special(self, name):
131 """Register a special name like `loop`."""
132 self.undeclared.discard(name)
133 self.declared.add(name)
134
Armin Ronacherda632622011-03-13 14:33:27 -0400135 def is_declared(self, name):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200136 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200137 if name in self.declared_locally or name in self.declared_parameter:
138 return True
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200139 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200140
Armin Ronacher74230e62009-10-25 12:46:31 +0100141 def copy(self):
142 return deepcopy(self)
143
Armin Ronachere791c2a2008-04-07 18:39:54 +0200144
145class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200146 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200147
Armin Ronacher8346bd72010-03-14 19:43:47 +0100148 def __init__(self, eval_ctx, parent=None):
149 self.eval_ctx = eval_ctx
Armin Ronachere791c2a2008-04-07 18:39:54 +0200150 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200151
Armin Ronacher75cfb862008-04-11 13:47:22 +0200152 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200153 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200154
Armin Ronacher75cfb862008-04-11 13:47:22 +0200155 # the root frame is basically just the outermost frame, so no if
156 # conditions. This information is used to optimize inheritance
157 # situations.
158 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200159
Armin Ronacher79668952008-09-23 22:52:46 +0200160 # in some dynamic inheritance situations the compiler needs to add
161 # write tests around output statements.
162 self.require_output_check = parent and parent.require_output_check
Armin Ronacherf40c8842008-09-17 18:51:26 +0200163
Armin Ronacherfed44b52008-04-13 19:42:53 +0200164 # inside some tags we are using a buffer rather than yield statements.
165 # this for example affects {% filter %} or {% macro %}. If a frame
166 # is buffered this variable points to the name of the list used as
167 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200168 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200169
Armin Ronacherfed44b52008-04-13 19:42:53 +0200170 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200171 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200172
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100173 # a set of actually assigned names
174 self.assigned_names = set()
175
Armin Ronacherfed44b52008-04-13 19:42:53 +0200176 # the parent of this frame
177 self.parent = parent
178
Armin Ronachere791c2a2008-04-07 18:39:54 +0200179 if parent is not None:
180 self.identifiers.declared.update(
181 parent.identifiers.declared |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200182 parent.identifiers.declared_parameter |
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100183 parent.assigned_names
Armin Ronachere791c2a2008-04-07 18:39:54 +0200184 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200185 self.identifiers.outer_undeclared.update(
186 parent.identifiers.undeclared -
187 self.identifiers.declared
188 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200189 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200190
Armin Ronacher8efc5222008-04-08 14:47:40 +0200191 def copy(self):
192 """Create a copy of the current one."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200193 rv = object.__new__(self.__class__)
194 rv.__dict__.update(self.__dict__)
195 rv.identifiers = object.__new__(self.identifiers.__class__)
196 rv.identifiers.__dict__.update(self.identifiers.__dict__)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200197 return rv
198
Armin Ronacherda632622011-03-13 14:33:27 -0400199 def inspect(self, nodes):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200200 """Walk the node and check for identifiers. If the scope is hard (eg:
201 enforce on a python level) overrides from outer scopes are tracked
202 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200203 """
Armin Ronacherda632622011-03-13 14:33:27 -0400204 visitor = FrameIdentifierVisitor(self.identifiers)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200205 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200206 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200207
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100208 def find_shadowed(self, extra=()):
209 """Find all the shadowed names. extra is an iterable of variables
210 that may be defined with `add_special` which may occour scoped.
211 """
212 i = self.identifiers
213 return (i.declared | i.outer_undeclared) & \
214 (i.declared_locally | i.declared_parameter) | \
215 set(x for x in extra if i.is_declared(x))
216
Armin Ronachere791c2a2008-04-07 18:39:54 +0200217 def inner(self):
218 """Return an inner frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100219 return Frame(self.eval_ctx, self)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200220
Armin Ronacher75cfb862008-04-11 13:47:22 +0200221 def soft(self):
222 """Return a soft frame. A soft frame may not be modified as
223 standalone thing as it shares the resources with the frame it
224 was created of, but it's not a rootlevel frame any longer.
225 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200226 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200227 rv.rootlevel = False
228 return rv
229
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200230 __copy__ = copy
231
Armin Ronachere791c2a2008-04-07 18:39:54 +0200232
Armin Ronacherc9705c22008-04-27 21:28:03 +0200233class VisitorExit(RuntimeError):
234 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
235
236
237class DependencyFinderVisitor(NodeVisitor):
238 """A visitor that collects filter and test calls."""
239
240 def __init__(self):
241 self.filters = set()
242 self.tests = set()
243
244 def visit_Filter(self, node):
245 self.generic_visit(node)
246 self.filters.add(node.name)
247
248 def visit_Test(self, node):
249 self.generic_visit(node)
250 self.tests.add(node.name)
251
252 def visit_Block(self, node):
253 """Stop visiting at blocks."""
254
255
256class UndeclaredNameVisitor(NodeVisitor):
257 """A visitor that checks if a name is accessed without being
258 declared. This is different from the frame visitor as it will
259 not stop at closure frames.
260 """
261
262 def __init__(self, names):
263 self.names = set(names)
264 self.undeclared = set()
265
266 def visit_Name(self, node):
267 if node.ctx == 'load' and node.name in self.names:
268 self.undeclared.add(node.name)
269 if self.undeclared == self.names:
270 raise VisitorExit()
271 else:
272 self.names.discard(node.name)
273
274 def visit_Block(self, node):
275 """Stop visiting a blocks."""
276
277
Armin Ronachere791c2a2008-04-07 18:39:54 +0200278class FrameIdentifierVisitor(NodeVisitor):
279 """A visitor for `Frame.inspect`."""
280
Armin Ronacherda632622011-03-13 14:33:27 -0400281 def __init__(self, identifiers):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200282 self.identifiers = identifiers
283
Armin Ronacherc9705c22008-04-27 21:28:03 +0200284 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200285 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200286 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200287 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200288 elif node.ctx == 'param':
289 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200290 elif node.ctx == 'load' and not \
Armin Ronacherda632622011-03-13 14:33:27 -0400291 self.identifiers.is_declared(node.name):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200292 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200293
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200294 def visit_If(self, node):
295 self.visit(node.test)
Armin Ronacher74230e62009-10-25 12:46:31 +0100296 real_identifiers = self.identifiers
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200297
Armin Ronacher8a672512010-04-05 18:43:07 +0200298 old_names = real_identifiers.declared_locally | \
Armin Ronacher74230e62009-10-25 12:46:31 +0100299 real_identifiers.declared_parameter
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200300
Armin Ronacher74230e62009-10-25 12:46:31 +0100301 def inner_visit(nodes):
Armin Ronacher1965e312009-10-25 13:03:08 +0100302 if not nodes:
303 return set()
Armin Ronacher74230e62009-10-25 12:46:31 +0100304 self.identifiers = real_identifiers.copy()
305 for subnode in nodes:
306 self.visit(subnode)
307 rv = self.identifiers.declared_locally - old_names
308 # we have to remember the undeclared variables of this branch
309 # because we will have to pull them.
310 real_identifiers.undeclared.update(self.identifiers.undeclared)
311 self.identifiers = real_identifiers
312 return rv
313
314 body = inner_visit(node.body)
315 else_ = inner_visit(node.else_ or ())
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200316
317 # the differences between the two branches are also pulled as
318 # undeclared variables
Armin Ronacher8a672512010-04-05 18:43:07 +0200319 real_identifiers.undeclared.update(body.symmetric_difference(else_) -
320 real_identifiers.declared)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200321
Armin Ronacher74230e62009-10-25 12:46:31 +0100322 # remember those that are declared.
323 real_identifiers.declared_locally.update(body | else_)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200324
Armin Ronacherc9705c22008-04-27 21:28:03 +0200325 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200326 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200327
Armin Ronacherc9705c22008-04-27 21:28:03 +0200328 def visit_Import(self, node):
329 self.generic_visit(node)
330 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200331
Armin Ronacherc9705c22008-04-27 21:28:03 +0200332 def visit_FromImport(self, node):
333 self.generic_visit(node)
334 for name in node.names:
335 if isinstance(name, tuple):
336 self.identifiers.declared_locally.add(name[1])
337 else:
338 self.identifiers.declared_locally.add(name)
339
340 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200341 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200342 self.visit(node.node)
343 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200344
Armin Ronacherc9705c22008-04-27 21:28:03 +0200345 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200346 """Visiting stops at for blocks. However the block sequence
347 is visited as part of the outer scope.
348 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200349 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200350
Armin Ronacherc9705c22008-04-27 21:28:03 +0200351 def visit_CallBlock(self, node):
Armin Ronacheref189442010-01-14 01:26:40 +0100352 self.visit(node.call)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200353
354 def visit_FilterBlock(self, node):
355 self.visit(node.filter)
356
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100357 def visit_Scope(self, node):
358 """Stop visiting at scopes."""
359
Armin Ronacherc9705c22008-04-27 21:28:03 +0200360 def visit_Block(self, node):
361 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200362
363
Armin Ronacher75cfb862008-04-11 13:47:22 +0200364class CompilerExit(Exception):
365 """Raised if the compiler encountered a situation where it just
366 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200367 raises such an exception is not further processed.
368 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200369
370
Armin Ronachere791c2a2008-04-07 18:39:54 +0200371class CodeGenerator(NodeVisitor):
372
Armin Ronacher64b08a02010-03-12 03:17:41 +0100373 def __init__(self, environment, name, filename, stream=None,
374 defer_init=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200375 if stream is None:
376 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200377 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200378 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200379 self.filename = filename
380 self.stream = stream
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100381 self.created_block_context = False
Armin Ronacher64b08a02010-03-12 03:17:41 +0100382 self.defer_init = defer_init
Armin Ronacherfed44b52008-04-13 19:42:53 +0200383
Armin Ronacher023b5e92008-05-08 11:03:10 +0200384 # aliases for imports
385 self.import_aliases = {}
386
Armin Ronacherfed44b52008-04-13 19:42:53 +0200387 # a registry for all blocks. Because blocks are moved out
388 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200389 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200390
391 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200392 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200393
394 # some templates have a rootlevel extends. In this case we
395 # can safely assume that we're a child template and do some
396 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200397 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200398
Armin Ronacherba3757b2008-04-16 19:43:16 +0200399 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200400 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200401
Armin Ronacherb9e78752008-05-10 23:36:28 +0200402 # registry of all filters and tests (global, not block local)
403 self.tests = {}
404 self.filters = {}
405
Armin Ronacherba3757b2008-04-16 19:43:16 +0200406 # the debug information
407 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200408 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200409
Armin Ronacherfed44b52008-04-13 19:42:53 +0200410 # the number of new lines before the next write()
411 self._new_lines = 0
412
413 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200414 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200415
416 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200417 self._first_write = True
418
Armin Ronacherfed44b52008-04-13 19:42:53 +0200419 # used by the `temporary_identifier` method to get new
420 # unique, temporary identifier
421 self._last_identifier = 0
422
423 # the current indentation
424 self._indentation = 0
425
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200426 # -- Various compilation helpers
427
Armin Ronachere2244882008-05-19 09:25:57 +0200428 def fail(self, msg, lineno):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100429 """Fail with a :exc:`TemplateAssertionError`."""
Armin Ronachere2244882008-05-19 09:25:57 +0200430 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
431
Armin Ronachere791c2a2008-04-07 18:39:54 +0200432 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200433 """Get a new unique identifier."""
434 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200435 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200436
Armin Ronachered1e0d42008-05-18 20:25:28 +0200437 def buffer(self, frame):
438 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200439 frame.buffer = self.temporary_identifier()
440 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200441
442 def return_buffer_contents(self, frame):
443 """Return the buffer contents of the frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100444 if frame.eval_ctx.volatile:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100445 self.writeline('if context.eval_ctx.autoescape:')
446 self.indent()
447 self.writeline('return Markup(concat(%s))' % frame.buffer)
448 self.outdent()
449 self.writeline('else:')
450 self.indent()
451 self.writeline('return concat(%s)' % frame.buffer)
452 self.outdent()
Armin Ronacher8346bd72010-03-14 19:43:47 +0100453 elif frame.eval_ctx.autoescape:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100454 self.writeline('return Markup(concat(%s))' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200455 else:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100456 self.writeline('return concat(%s)' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200457
Armin Ronachere791c2a2008-04-07 18:39:54 +0200458 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200459 """Indent by one."""
460 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200461
Armin Ronacher8efc5222008-04-08 14:47:40 +0200462 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200463 """Outdent by step."""
464 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200465
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200466 def start_write(self, frame, node=None):
467 """Yield or write into the frame buffer."""
468 if frame.buffer is None:
469 self.writeline('yield ', node)
470 else:
471 self.writeline('%s.append(' % frame.buffer, node)
472
473 def end_write(self, frame):
474 """End the writing process started by `start_write`."""
475 if frame.buffer is not None:
476 self.write(')')
477
478 def simple_write(self, s, frame, node=None):
479 """Simple shortcut for start_write + write + end_write."""
480 self.start_write(frame, node)
481 self.write(s)
482 self.end_write(frame)
483
Armin Ronacherf40c8842008-09-17 18:51:26 +0200484 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200485 """Visit a list of nodes as block in a frame. If the current frame
486 is no buffer a dummy ``if 0: yield None`` is written automatically
487 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200488 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200489 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200490 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200491 else:
492 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200493 try:
494 for node in nodes:
495 self.visit(node, frame)
496 except CompilerExit:
497 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200498
499 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200500 """Write a string into the output stream."""
501 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200502 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200503 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200504 self.code_lineno += self._new_lines
505 if self._write_debug_info is not None:
506 self.debug_info.append((self._write_debug_info,
507 self.code_lineno))
508 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200509 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200510 self.stream.write(' ' * self._indentation)
511 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200512 self.stream.write(x)
513
514 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200515 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200516 self.newline(node, extra)
517 self.write(x)
518
519 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200520 """Add one or more newlines before the next write."""
521 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200522 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200523 self._write_debug_info = node.lineno
524 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200525
Armin Ronacherfd310492008-05-25 00:16:51 +0200526 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200527 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200528 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200529 arguments may not include python keywords otherwise a syntax
530 error could occour. The extra keyword arguments should be given
531 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200532 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200533 # if any of the given keyword arguments is a python keyword
534 # we have to make sure that no invalid call is created.
535 kwarg_workaround = False
536 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200537 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200538 kwarg_workaround = True
539 break
540
Armin Ronacher8efc5222008-04-08 14:47:40 +0200541 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200542 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200543 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200544
545 if not kwarg_workaround:
546 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200547 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200548 self.visit(kwarg, frame)
549 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200550 for key, value in six.iteritems(extra_kwargs):
Armin Ronacherfd310492008-05-25 00:16:51 +0200551 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200552 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200553 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200554 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200555
556 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200557 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200558 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200559 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200560 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200561 for kwarg in node.kwargs:
562 self.write('%r: ' % kwarg.key)
563 self.visit(kwarg.value, frame)
564 self.write(', ')
565 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200566 for key, value in six.iteritems(extra_kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200567 self.write('%r: %s, ' % (key, value))
568 if node.dyn_kwargs is not None:
569 self.write('}, **')
570 self.visit(node.dyn_kwargs, frame)
571 self.write(')')
572 else:
573 self.write('}')
574
575 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200576 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200577 self.visit(node.dyn_kwargs, frame)
578
Armin Ronacherc9705c22008-04-27 21:28:03 +0200579 def pull_locals(self, frame):
580 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200581 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200582 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200583
584 def pull_dependencies(self, nodes):
585 """Pull all the dependencies."""
586 visitor = DependencyFinderVisitor()
587 for node in nodes:
588 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200589 for dependency in 'filters', 'tests':
590 mapping = getattr(self, dependency)
591 for name in getattr(visitor, dependency):
592 if name not in mapping:
593 mapping[name] = self.temporary_identifier()
594 self.writeline('%s = environment.%s[%r]' %
595 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200596
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100597 def unoptimize_scope(self, frame):
598 """Disable Python optimizations for the frame."""
599 # XXX: this is not that nice but it has no real overhead. It
600 # mainly works because python finds the locals before dead code
601 # is removed. If that breaks we have to add a dummy function
602 # that just accepts the arguments and does nothing.
603 if frame.identifiers.declared:
Armin Ronacher821a4232010-02-17 07:59:38 +0100604 self.writeline('%sdummy(%s)' % (
605 unoptimize_before_dead_code and 'if 0: ' or '',
606 ', '.join('l_' + name for name in frame.identifiers.declared)
607 ))
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100608
Armin Ronacher673aa882008-10-04 18:06:57 +0200609 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200610 """This function returns all the shadowed variables in a dict
611 in the form name: alias and will write the required assignments
612 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200613
Armin Ronacher673aa882008-10-04 18:06:57 +0200614 This also predefines locally declared variables from the loop
615 body because under some circumstances it may be the case that
616
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100617 `extra_vars` is passed to `Frame.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200618 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200619 aliases = {}
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100620 for name in frame.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200621 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200622 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200623 to_declare = set()
624 for name in frame.identifiers.declared_locally:
625 if name not in aliases:
626 to_declare.add('l_' + name)
627 if to_declare:
628 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200629 return aliases
630
Armin Ronacher673aa882008-10-04 18:06:57 +0200631 def pop_scope(self, aliases, frame):
632 """Restore all aliases and delete unused variables."""
Thomas Waldmanne0003552013-05-17 23:52:14 +0200633 for name, alias in six.iteritems(aliases):
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200634 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200635 to_delete = set()
636 for name in frame.identifiers.declared_locally:
637 if name not in aliases:
638 to_delete.add('l_' + name)
639 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100640 # we cannot use the del statement here because enclosed
641 # scopes can trigger a SyntaxError:
642 # a = 42; b = lambda: a; del a
643 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200644
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200645 def function_scoping(self, node, frame, children=None,
646 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200647 """In Jinja a few statements require the help of anonymous
648 functions. Those are currently macros and call blocks and in
649 the future also recursive loops. As there is currently
650 technical limitation that doesn't allow reading and writing a
651 variable in a scope where the initial value is coming from an
652 outer scope, this function tries to fall back with a common
653 error message. Additionally the frame passed is modified so
654 that the argumetns are collected and callers are looked up.
655
656 This will return the modified frame.
657 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200658 # we have to iterate twice over it, make sure that works
659 if children is None:
660 children = node.iter_child_nodes()
661 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200662 func_frame = frame.inner()
Armin Ronacherda632622011-03-13 14:33:27 -0400663 func_frame.inspect(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200664
665 # variables that are undeclared (accessed before declaration) and
666 # declared locally *and* part of an outside scope raise a template
667 # assertion error. Reason: we can't generate reasonable code from
Armin Ronacher02b42a82009-03-18 00:59:32 +0100668 # it without aliasing all the variables.
669 # this could be fixed in Python 3 where we have the nonlocal
670 # keyword or if we switch to bytecode generation
Armin Ronacher71082072008-04-12 14:19:36 +0200671 overriden_closure_vars = (
672 func_frame.identifiers.undeclared &
673 func_frame.identifiers.declared &
674 (func_frame.identifiers.declared_locally |
675 func_frame.identifiers.declared_parameter)
676 )
677 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200678 self.fail('It\'s not possible to set and access variables '
Armin Ronacherefcc0e52009-09-13 00:22:50 -0700679 'derived from an outer scope! (affects: %s)' %
Armin Ronachere2244882008-05-19 09:25:57 +0200680 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200681
682 # remove variables from a closure from the frame's undeclared
683 # identifiers.
684 func_frame.identifiers.undeclared -= (
685 func_frame.identifiers.undeclared &
686 func_frame.identifiers.declared
687 )
688
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200689 # no special variables for this scope, abort early
690 if not find_special:
691 return func_frame
692
Armin Ronacher963f97d2008-04-25 11:44:59 +0200693 func_frame.accesses_kwargs = False
694 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200695 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200696 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200697
Armin Ronacherc9705c22008-04-27 21:28:03 +0200698 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
699
700 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200701 func_frame.accesses_caller = True
702 func_frame.identifiers.add_special('caller')
703 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200704 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200705 func_frame.accesses_kwargs = True
706 func_frame.identifiers.add_special('kwargs')
707 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200708 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200709 func_frame.accesses_varargs = True
710 func_frame.identifiers.add_special('varargs')
711 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200712 return func_frame
713
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200714 def macro_body(self, node, frame, children=None):
715 """Dump the function def of a macro or call block."""
716 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100717 # macros are delayed, they never require output checks
718 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200719 args = frame.arguments
Armin Ronachereabf3dd2009-09-12 23:48:18 -0700720 # XXX: this is an ugly fix for the loop nesting bug
721 # (tests.test_old_bugs.test_loop_call_bug). This works around
722 # a identifier nesting problem we have in general. It's just more
723 # likely to happen in loops which is why we work around it. The
724 # real solution would be "nonlocal" all the identifiers that are
725 # leaking into a new python frame and might be used both unassigned
726 # and assigned.
727 if 'loop' in frame.identifiers.declared:
Armin Ronacherb4044392009-09-13 15:56:58 -0700728 args = args + ['l_loop=l_loop']
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200729 self.writeline('def macro(%s):' % ', '.join(args), node)
730 self.indent()
731 self.buffer(frame)
732 self.pull_locals(frame)
733 self.blockvisit(node.body, frame)
734 self.return_buffer_contents(frame)
735 self.outdent()
736 return frame
737
738 def macro_def(self, node, frame):
739 """Dump the macro definition for the def created by macro_body."""
740 arg_tuple = ', '.join(repr(x.name) for x in node.args)
741 name = getattr(node, 'name', None)
742 if len(node.args) == 1:
743 arg_tuple += ','
744 self.write('Macro(environment, macro, %r, (%s), (' %
745 (name, arg_tuple))
746 for arg in node.defaults:
747 self.visit(arg, frame)
748 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200749 self.write('), %r, %r, %r)' % (
750 bool(frame.accesses_kwargs),
751 bool(frame.accesses_varargs),
752 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200753 ))
754
Armin Ronacher547d0b62008-07-04 16:35:10 +0200755 def position(self, node):
756 """Return a human readable position for the node."""
757 rv = 'line %d' % node.lineno
758 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100759 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200760 return rv
761
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200762 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200763
764 def visit_Template(self, node, frame=None):
765 assert frame is None, 'no root frame allowed'
Armin Ronacher1da23d12010-04-05 18:11:18 +0200766 eval_ctx = EvalContext(self.environment, self.name)
Armin Ronacher8346bd72010-03-14 19:43:47 +0100767
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200768 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200769 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200770 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher821a4232010-02-17 07:59:38 +0100771 if not unoptimize_before_dead_code:
772 self.writeline('dummy = lambda *x: None')
Armin Ronacher8edbe492008-04-10 20:43:43 +0200773
Armin Ronacher64b08a02010-03-12 03:17:41 +0100774 # if we want a deferred initialization we cannot move the
775 # environment into a local name
776 envenv = not self.defer_init and ', environment=environment' or ''
777
Armin Ronacher75cfb862008-04-11 13:47:22 +0200778 # do we have an extends tag at all? If not, we can save some
779 # overhead by just not processing any inheritance code.
780 have_extends = node.find(nodes.Extends) is not None
781
Armin Ronacher8edbe492008-04-10 20:43:43 +0200782 # find all blocks
783 for block in node.find_all(nodes.Block):
784 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200785 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200786 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200787
Armin Ronacher023b5e92008-05-08 11:03:10 +0200788 # find all imports and import them
789 for import_ in node.find_all(nodes.ImportedName):
790 if import_.importname not in self.import_aliases:
791 imp = import_.importname
792 self.import_aliases[imp] = alias = self.temporary_identifier()
793 if '.' in imp:
794 module, obj = imp.rsplit('.', 1)
795 self.writeline('from %s import %s as %s' %
796 (module, obj, alias))
797 else:
798 self.writeline('import %s as %s' % (imp, alias))
799
800 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200801 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200802
Armin Ronacher8efc5222008-04-08 14:47:40 +0200803 # generate the root render function.
Armin Ronacher64b08a02010-03-12 03:17:41 +0100804 self.writeline('def root(context%s):' % envenv, extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200805
806 # process the root
Armin Ronacher8346bd72010-03-14 19:43:47 +0100807 frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200808 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200809 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200810 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200811 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200812 if have_extends:
813 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200814 if 'self' in find_undeclared(node.body, ('self',)):
815 frame.identifiers.add_special('self')
816 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200817 self.pull_locals(frame)
818 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200819 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200820 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200821
Armin Ronacher8efc5222008-04-08 14:47:40 +0200822 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200823 if have_extends:
824 if not self.has_known_extends:
825 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200826 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200827 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200828 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200829 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200830 self.indent()
831 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200832 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200833
834 # at this point we now have the blocks collected and can visit them too.
Thomas Waldmanne0003552013-05-17 23:52:14 +0200835 for name, block in six.iteritems(self.blocks):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100836 block_frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200837 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200838 block_frame.block = name
Armin Ronacher64b08a02010-03-12 03:17:41 +0100839 self.writeline('def block_%s(context%s):' % (name, envenv),
840 block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200841 self.indent()
842 undeclared = find_undeclared(block.body, ('self', 'super'))
843 if 'self' in undeclared:
844 block_frame.identifiers.add_special('self')
845 self.writeline('l_self = TemplateReference(context)')
846 if 'super' in undeclared:
847 block_frame.identifiers.add_special('super')
848 self.writeline('l_super = context.super(%r, '
849 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200850 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200851 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200852 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200853 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200854
Armin Ronacher75cfb862008-04-11 13:47:22 +0200855 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200856 for x in self.blocks),
857 extra=1)
858
859 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200860 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
861 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200862
Armin Ronachere791c2a2008-04-07 18:39:54 +0200863 def visit_Block(self, node, frame):
864 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200865 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200866 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200867 # if we know that we are a child template, there is no need to
868 # check if we are one
869 if self.has_known_extends:
870 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200871 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200872 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200873 self.indent()
874 level += 1
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100875 context = node.scoped and 'context.derived(locals())' or 'context'
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100876 self.writeline('for event in context.blocks[%r][0](%s):' % (
877 node.name, context), node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200878 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200879 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200880 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200881
882 def visit_Extends(self, node, frame):
883 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200884 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200885 self.fail('cannot use extend from a non top-level scope',
886 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200887
Armin Ronacher7fb38972008-04-11 13:54:28 +0200888 # if the number of extends statements in general is zero so
889 # far, we don't have to add a check if something extended
890 # the template before this one.
891 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200892
Armin Ronacher7fb38972008-04-11 13:54:28 +0200893 # if we have a known extends we just add a template runtime
894 # error into the generated code. We could catch that at compile
895 # time too, but i welcome it not to confuse users by throwing the
896 # same error at different times just "because we can".
897 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200898 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200899 self.indent()
900 self.writeline('raise TemplateRuntimeError(%r)' %
901 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200902 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200903
Armin Ronacher7fb38972008-04-11 13:54:28 +0200904 # if we have a known extends already we don't need that code here
905 # as we know that the template execution will end here.
906 if self.has_known_extends:
907 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200908
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200909 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200910 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200911 self.write(', %r)' % self.name)
912 self.writeline('for name, parent_block in parent_template.'
Armin Ronacher0d242be2010-02-10 01:35:13 +0100913 'blocks.%s():' % dict_item_iter)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200914 self.indent()
915 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200916 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200917 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200918
919 # if this extends statement was in the root level we can take
920 # advantage of that information and simplify the generated code
921 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200922 if frame.rootlevel:
923 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200924
Armin Ronacher7fb38972008-04-11 13:54:28 +0200925 # and now we have one more
926 self.extends_so_far += 1
927
Armin Ronacherf059ec12008-04-11 22:21:00 +0200928 def visit_Include(self, node, frame):
929 """Handles includes."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100930 if node.with_context:
931 self.unoptimize_scope(frame)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100932 if node.ignore_missing:
933 self.writeline('try:')
934 self.indent()
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100935
936 func_name = 'get_or_select_template'
937 if isinstance(node.template, nodes.Const):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200938 if isinstance(node.template.value, six.string_types):
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100939 func_name = 'get_template'
940 elif isinstance(node.template.value, (tuple, list)):
941 func_name = 'select_template'
942 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
943 func_name = 'select_template'
944
945 self.writeline('template = environment.%s(' % func_name, node)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100946 self.visit(node.template, frame)
947 self.write(', %r)' % self.name)
948 if node.ignore_missing:
949 self.outdent()
950 self.writeline('except TemplateNotFound:')
951 self.indent()
952 self.writeline('pass')
953 self.outdent()
954 self.writeline('else:')
955 self.indent()
956
Armin Ronacherea847c52008-05-02 20:04:32 +0200957 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200958 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200959 'template.new_context(context.parent, True, '
960 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200961 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100962 self.writeline('for event in template.module._body_stream:')
963
Armin Ronacherf059ec12008-04-11 22:21:00 +0200964 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200965 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200966 self.outdent()
967
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100968 if node.ignore_missing:
969 self.outdent()
970
Armin Ronacher0611e492008-04-25 23:44:14 +0200971 def visit_Import(self, node, frame):
972 """Visit regular imports."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100973 if node.with_context:
974 self.unoptimize_scope(frame)
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200975 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200976 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200977 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200978 self.write('environment.get_template(')
979 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200980 self.write(', %r).' % self.name)
981 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200982 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200983 else:
984 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200985 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200986 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100987 frame.assigned_names.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200988
989 def visit_FromImport(self, node, frame):
990 """Visit named imports."""
991 self.newline(node)
992 self.write('included_template = environment.get_template(')
993 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200994 self.write(', %r).' % self.name)
995 if node.with_context:
996 self.write('make_module(context.parent, True)')
997 else:
998 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200999
1000 var_names = []
1001 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +02001002 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +02001003 if isinstance(name, tuple):
1004 name, alias = name
1005 else:
1006 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001007 self.writeline('l_%s = getattr(included_template, '
1008 '%r, missing)' % (alias, name))
1009 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +02001010 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001011 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +02001012 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +02001013 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001014 (alias, 'the template %%r (imported on %s) does '
1015 'not export the requested name %s' % (
1016 self.position(node),
1017 repr(name)
1018 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +02001019 self.outdent()
1020 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +02001021 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +02001022 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +02001023 discarded_names.append(alias)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001024 frame.assigned_names.add(alias)
Armin Ronachera78d2762008-05-15 23:18:07 +02001025
1026 if var_names:
1027 if len(var_names) == 1:
1028 name = var_names[0]
1029 self.writeline('context.vars[%r] = l_%s' % (name, name))
1030 else:
1031 self.writeline('context.vars.update({%s})' % ', '.join(
1032 '%r: l_%s' % (name, name) for name in var_names
1033 ))
1034 if discarded_names:
1035 if len(discarded_names) == 1:
1036 self.writeline('context.exported_vars.discard(%r)' %
1037 discarded_names[0])
1038 else:
1039 self.writeline('context.exported_vars.difference_'
1040 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +02001041
Armin Ronachere791c2a2008-04-07 18:39:54 +02001042 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001043 # when calculating the nodes for the inner frame we have to exclude
1044 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001045 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001046 if node.recursive:
1047 loop_frame = self.function_scoping(node, frame, children,
1048 find_special=False)
1049 else:
1050 loop_frame = frame.inner()
1051 loop_frame.inspect(children)
1052
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001053 # try to figure out if we have an extended loop. An extended loop
1054 # is necessary if the loop is in recursive mode if the special loop
1055 # variable is accessed in the body.
1056 extended_loop = node.recursive or 'loop' in \
1057 find_undeclared(node.iter_child_nodes(
1058 only=('body',)), ('loop',))
1059
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001060 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +02001061 # variables at that point. Because loops can be nested but the loop
1062 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001063 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +02001064 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001065
1066 # otherwise we set up a buffer and add a function def
1067 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001068 self.writeline('def loop(reciter, loop_render_func):', node)
1069 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +02001070 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001071 aliases = {}
1072
Armin Ronacherff53c782008-08-13 18:55:50 +02001073 # make sure the loop variable is a special one and raise a template
1074 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +02001075 if extended_loop:
1076 loop_frame.identifiers.add_special('loop')
Armin Ronacherff53c782008-08-13 18:55:50 +02001077 for name in node.find_all(nodes.Name):
1078 if name.ctx == 'store' and name.name == 'loop':
1079 self.fail('Can\'t assign to special loop variable '
1080 'in for-loop target', name.lineno)
1081
Armin Ronacherc9705c22008-04-27 21:28:03 +02001082 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001083 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001084 iteration_indicator = self.temporary_identifier()
1085 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001086
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001087 # Create a fake parent loop if the else or test section of a
1088 # loop is accessing the special loop variable and no parent loop
1089 # exists.
1090 if 'loop' not in aliases and 'loop' in find_undeclared(
1091 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1092 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001093 ("'loop' is undefined. the filter section of a loop as well "
Armin Ronacherbc56cd22011-01-15 18:35:45 +01001094 "as the else block don't have access to the special 'loop'"
Armin Ronacher547d0b62008-07-04 16:35:10 +02001095 " variable of the current loop. Because there is no parent "
1096 "loop it's undefined. Happened in loop on %s" %
1097 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001098
1099 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001100 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +02001101 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001102
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001103 # if we have an extened loop and a node test, we filter in the
1104 # "outer frame".
1105 if extended_loop and node.test is not None:
1106 self.write('(')
1107 self.visit(node.target, loop_frame)
1108 self.write(' for ')
1109 self.visit(node.target, loop_frame)
1110 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001111 if node.recursive:
1112 self.write('reciter')
1113 else:
1114 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001115 self.write(' if (')
1116 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001117 self.visit(node.test, test_frame)
1118 self.write('))')
1119
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001120 elif node.recursive:
1121 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001122 else:
1123 self.visit(node.iter, loop_frame)
1124
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001125 if node.recursive:
1126 self.write(', recurse=loop_render_func):')
1127 else:
1128 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001129
1130 # tests in not extended loops become a continue
1131 if not extended_loop and node.test is not None:
1132 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +02001133 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +02001134 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001135 self.write(':')
1136 self.indent()
1137 self.writeline('continue')
1138 self.outdent(2)
1139
Armin Ronacherc9705c22008-04-27 21:28:03 +02001140 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001141 self.blockvisit(node.body, loop_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001142 if node.else_:
1143 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001144 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001145
1146 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001147 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001148 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001149 self.blockvisit(node.else_, loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001150 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001151
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001152 # reset the aliases if there are any.
Armin Ronachercebd8382008-12-25 18:33:46 +01001153 if not node.recursive:
1154 self.pop_scope(aliases, loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001155
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001156 # if the node was recursive we have to return the buffer contents
1157 # and start the iteration code
1158 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001159 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001160 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001161 self.start_write(frame, node)
1162 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001163 self.visit(node.iter, frame)
1164 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001165 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001166
Armin Ronachere791c2a2008-04-07 18:39:54 +02001167 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001168 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001169 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001170 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001171 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001172 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001173 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001174 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001175 if node.else_:
1176 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001177 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001178 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001179 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001180
Armin Ronacher8efc5222008-04-08 14:47:40 +02001181 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001182 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001183 self.newline()
1184 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001185 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001186 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001187 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001188 self.write('l_%s = ' % node.name)
1189 self.macro_def(node, macro_frame)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001190 frame.assigned_names.add(node.name)
Armin Ronacher71082072008-04-12 14:19:36 +02001191
1192 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001193 children = node.iter_child_nodes(exclude=('call',))
1194 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001195 self.writeline('caller = ')
1196 self.macro_def(node, call_frame)
1197 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001198 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001199 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001200
1201 def visit_FilterBlock(self, node, frame):
1202 filter_frame = frame.inner()
1203 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacher673aa882008-10-04 18:06:57 +02001204 aliases = self.push_scope(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001205 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001206 self.buffer(filter_frame)
Armin Ronacherf40c8842008-09-17 18:51:26 +02001207 self.blockvisit(node.body, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001208 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001209 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001210 self.end_write(frame)
Armin Ronacher673aa882008-10-04 18:06:57 +02001211 self.pop_scope(aliases, filter_frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001212
Armin Ronachere791c2a2008-04-07 18:39:54 +02001213 def visit_ExprStmt(self, node, frame):
1214 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001215 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001216
1217 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001218 # if we have a known extends statement, we don't output anything
Armin Ronacher79668952008-09-23 22:52:46 +02001219 # if we are in a require_output_check section
1220 if self.has_known_extends and frame.require_output_check:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001221 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001222
Armin Ronacher665bfb82008-07-14 13:41:46 +02001223 if self.environment.finalize:
Thomas Waldmanne0003552013-05-17 23:52:14 +02001224 finalize = lambda x: six.text_type(self.environment.finalize(x))
Armin Ronacher665bfb82008-07-14 13:41:46 +02001225 else:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001226 finalize = six.text_type
Armin Ronacher665bfb82008-07-14 13:41:46 +02001227
Armin Ronacher79668952008-09-23 22:52:46 +02001228 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001229 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001230 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001231 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001232 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001233 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001234
Armin Ronachere791c2a2008-04-07 18:39:54 +02001235 # try to evaluate as many chunks as possible into a static
1236 # string at compile time.
1237 body = []
1238 for child in node.nodes:
1239 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001240 const = child.as_const(frame.eval_ctx)
Armin Ronacher9cf95912008-05-24 19:54:43 +02001241 except nodes.Impossible:
1242 body.append(child)
1243 continue
Armin Ronacher8346bd72010-03-14 19:43:47 +01001244 # the frame can't be volatile here, becaus otherwise the
1245 # as_const() function would raise an Impossible exception
1246 # at that point.
Armin Ronacher9cf95912008-05-24 19:54:43 +02001247 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001248 if frame.eval_ctx.autoescape:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001249 if hasattr(const, '__html__'):
1250 const = const.__html__()
1251 else:
1252 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001253 const = finalize(const)
Ian Lewisab014bd2010-10-31 20:29:28 +09001254 except Exception:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001255 # if something goes wrong here we evaluate the node
1256 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001257 body.append(child)
1258 continue
1259 if body and isinstance(body[-1], list):
1260 body[-1].append(const)
1261 else:
1262 body.append([const])
1263
Armin Ronachered1e0d42008-05-18 20:25:28 +02001264 # if we have less than 3 nodes or a buffer we yield or extend/append
1265 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001266 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001267 # for one item we append, for more we extend
1268 if len(body) == 1:
1269 self.writeline('%s.append(' % frame.buffer)
1270 else:
1271 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001272 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001273 for item in body:
1274 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001275 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001276 if frame.buffer is None:
1277 self.writeline('yield ' + val)
1278 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001279 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001280 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001281 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001282 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001283 else:
1284 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001285 close = 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001286 if frame.eval_ctx.volatile:
1287 self.write('(context.eval_ctx.autoescape and'
1288 ' escape or to_string)(')
1289 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001290 self.write('escape(')
1291 else:
Armin Ronacherbd357722009-08-05 20:25:06 +02001292 self.write('to_string(')
Armin Ronacherd1342312008-04-28 12:20:12 +02001293 if self.environment.finalize is not None:
1294 self.write('environment.finalize(')
1295 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001296 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001297 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001298 if frame.buffer is not None:
1299 self.write(', ')
1300 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001301 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001302 self.outdent()
1303 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001304
1305 # otherwise we create a format string as this is faster in that case
1306 else:
1307 format = []
1308 arguments = []
1309 for item in body:
1310 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001311 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001312 else:
1313 format.append('%s')
1314 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001315 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001316 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001317 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001318 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001319 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001320 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001321 close = 0
Armin Ronacher8346bd72010-03-14 19:43:47 +01001322 if frame.eval_ctx.volatile:
1323 self.write('(context.eval_ctx.autoescape and'
1324 ' escape or to_string)(')
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001325 close += 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001326 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001327 self.write('escape(')
1328 close += 1
1329 if self.environment.finalize is not None:
1330 self.write('environment.finalize(')
1331 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001332 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001333 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001334 self.outdent()
1335 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001336
Armin Ronacher7fb38972008-04-11 13:54:28 +02001337 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001338 self.outdent()
1339
Armin Ronacher8efc5222008-04-08 14:47:40 +02001340 def visit_Assign(self, node, frame):
1341 self.newline(node)
1342 # toplevel assignments however go into the local namespace and
1343 # the current template's context. We create a copy of the frame
1344 # here and add a set so that the Name visitor can add the assigned
1345 # names here.
1346 if frame.toplevel:
1347 assignment_frame = frame.copy()
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001348 assignment_frame.toplevel_assignments = set()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001349 else:
1350 assignment_frame = frame
1351 self.visit(node.target, assignment_frame)
1352 self.write(' = ')
1353 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001354
1355 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001356 if frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001357 public_names = [x for x in assignment_frame.toplevel_assignments
Armin Ronacher903d1682008-05-23 00:51:58 +02001358 if not x.startswith('_')]
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001359 if len(assignment_frame.toplevel_assignments) == 1:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001360 name = six.advance_iterator(iter(assignment_frame.toplevel_assignments))
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001361 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001362 else:
1363 self.writeline('context.vars.update({')
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001364 for idx, name in enumerate(assignment_frame.toplevel_assignments):
Armin Ronacher69e12db2008-05-12 09:00:03 +02001365 if idx:
1366 self.write(', ')
1367 self.write('%r: l_%s' % (name, name))
1368 self.write('})')
1369 if public_names:
1370 if len(public_names) == 1:
1371 self.writeline('context.exported_vars.add(%r)' %
1372 public_names[0])
1373 else:
1374 self.writeline('context.exported_vars.update((%s))' %
1375 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001376
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001377 # -- Expression Visitors
1378
Armin Ronachere791c2a2008-04-07 18:39:54 +02001379 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001380 if node.ctx == 'store' and frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001381 frame.toplevel_assignments.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001382 self.write('l_' + node.name)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001383 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001384
1385 def visit_Const(self, node, frame):
1386 val = node.value
1387 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001388 self.write(str(val))
1389 else:
1390 self.write(repr(val))
1391
Armin Ronacher5411ce72008-05-25 11:36:22 +02001392 def visit_TemplateData(self, node, frame):
Armin Ronacherffaa2e72010-05-29 20:57:16 +02001393 try:
1394 self.write(repr(node.as_const(frame.eval_ctx)))
1395 except nodes.Impossible:
1396 self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)'
1397 % node.data)
Armin Ronacher5411ce72008-05-25 11:36:22 +02001398
Armin Ronacher8efc5222008-04-08 14:47:40 +02001399 def visit_Tuple(self, node, frame):
1400 self.write('(')
1401 idx = -1
1402 for idx, item in enumerate(node.items):
1403 if idx:
1404 self.write(', ')
1405 self.visit(item, frame)
1406 self.write(idx == 0 and ',)' or ')')
1407
Armin Ronacher8edbe492008-04-10 20:43:43 +02001408 def visit_List(self, node, frame):
1409 self.write('[')
1410 for idx, item in enumerate(node.items):
1411 if idx:
1412 self.write(', ')
1413 self.visit(item, frame)
1414 self.write(']')
1415
1416 def visit_Dict(self, node, frame):
1417 self.write('{')
1418 for idx, item in enumerate(node.items):
1419 if idx:
1420 self.write(', ')
1421 self.visit(item.key, frame)
1422 self.write(': ')
1423 self.visit(item.value, frame)
1424 self.write('}')
1425
Armin Ronachera9195382010-11-29 13:21:57 +01001426 def binop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001427 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001428 if self.environment.sandboxed and \
1429 operator in self.environment.intercepted_binops:
1430 self.write('environment.call_binop(context, %r, ' % operator)
1431 self.visit(node.left, frame)
1432 self.write(', ')
1433 self.visit(node.right, frame)
1434 else:
1435 self.write('(')
1436 self.visit(node.left, frame)
1437 self.write(' %s ' % operator)
1438 self.visit(node.right, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001439 self.write(')')
1440 return visitor
1441
Armin Ronachera9195382010-11-29 13:21:57 +01001442 def uaop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001443 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001444 if self.environment.sandboxed and \
1445 operator in self.environment.intercepted_unops:
1446 self.write('environment.call_unop(context, %r, ' % operator)
1447 self.visit(node.node, frame)
1448 else:
1449 self.write('(' + operator)
1450 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001451 self.write(')')
1452 return visitor
1453
1454 visit_Add = binop('+')
1455 visit_Sub = binop('-')
1456 visit_Mul = binop('*')
1457 visit_Div = binop('/')
1458 visit_FloorDiv = binop('//')
1459 visit_Pow = binop('**')
1460 visit_Mod = binop('%')
Armin Ronachera9195382010-11-29 13:21:57 +01001461 visit_And = binop('and', interceptable=False)
1462 visit_Or = binop('or', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001463 visit_Pos = uaop('+')
1464 visit_Neg = uaop('-')
Armin Ronachera9195382010-11-29 13:21:57 +01001465 visit_Not = uaop('not ', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001466 del binop, uaop
1467
Armin Ronacherd1342312008-04-28 12:20:12 +02001468 def visit_Concat(self, node, frame):
Armin Ronacher8346bd72010-03-14 19:43:47 +01001469 if frame.eval_ctx.volatile:
1470 func_name = '(context.eval_ctx.volatile and' \
1471 ' markup_join or unicode_join)'
1472 elif frame.eval_ctx.autoescape:
1473 func_name = 'markup_join'
1474 else:
1475 func_name = 'unicode_join'
1476 self.write('%s((' % func_name)
Armin Ronacherd1342312008-04-28 12:20:12 +02001477 for arg in node.nodes:
1478 self.visit(arg, frame)
1479 self.write(', ')
1480 self.write('))')
1481
Armin Ronachere791c2a2008-04-07 18:39:54 +02001482 def visit_Compare(self, node, frame):
1483 self.visit(node.expr, frame)
1484 for op in node.ops:
1485 self.visit(op, frame)
1486
1487 def visit_Operand(self, node, frame):
1488 self.write(' %s ' % operators[node.op])
1489 self.visit(node.expr, frame)
1490
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001491 def visit_Getattr(self, node, frame):
1492 self.write('environment.getattr(')
1493 self.visit(node.node, frame)
1494 self.write(', %r)' % node.attr)
1495
1496 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001497 # slices bypass the environment getitem method.
1498 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001499 self.visit(node.node, frame)
1500 self.write('[')
1501 self.visit(node.arg, frame)
1502 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001503 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001504 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001505 self.visit(node.node, frame)
1506 self.write(', ')
1507 self.visit(node.arg, frame)
1508 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001509
1510 def visit_Slice(self, node, frame):
1511 if node.start is not None:
1512 self.visit(node.start, frame)
1513 self.write(':')
1514 if node.stop is not None:
1515 self.visit(node.stop, frame)
1516 if node.step is not None:
1517 self.write(':')
1518 self.visit(node.step, frame)
1519
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001520 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001521 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001522 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001523 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001524 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001525 if getattr(func, 'contextfilter', False):
1526 self.write('context, ')
Armin Ronacher8346bd72010-03-14 19:43:47 +01001527 elif getattr(func, 'evalcontextfilter', False):
1528 self.write('context.eval_ctx, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001529 elif getattr(func, 'environmentfilter', False):
1530 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001531
1532 # if the filter node is None we are inside a filter block
1533 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001534 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001535 self.visit(node.node, frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001536 elif frame.eval_ctx.volatile:
1537 self.write('(context.eval_ctx.autoescape and'
1538 ' Markup(concat(%s)) or concat(%s))' %
1539 (frame.buffer, frame.buffer))
1540 elif frame.eval_ctx.autoescape:
Armin Ronacher3da90312008-05-23 16:37:28 +02001541 self.write('Markup(concat(%s))' % frame.buffer)
1542 else:
1543 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001544 self.signature(node, frame)
1545 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001546
1547 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001548 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001549 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001550 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001551 self.visit(node.node, frame)
1552 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001553 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001554
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001555 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001556 def write_expr2():
1557 if node.expr2 is not None:
1558 return self.visit(node.expr2, frame)
1559 self.write('environment.undefined(%r)' % ('the inline if-'
1560 'expression on %s evaluated to false and '
1561 'no else section was defined.' % self.position(node)))
1562
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001563 if not have_condexpr:
1564 self.write('((')
1565 self.visit(node.test, frame)
1566 self.write(') and (')
1567 self.visit(node.expr1, frame)
1568 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001569 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001570 self.write(',))[0]')
1571 else:
1572 self.write('(')
1573 self.visit(node.expr1, frame)
1574 self.write(' if ')
1575 self.visit(node.test, frame)
1576 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001577 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001578 self.write(')')
1579
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001580 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001581 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001582 self.write('environment.call(context, ')
1583 else:
1584 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001585 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001586 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001587 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001588 self.write(')')
1589
1590 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001591 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001592 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001593
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001594 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001595
1596 def visit_MarkSafe(self, node, frame):
1597 self.write('Markup(')
1598 self.visit(node.expr, frame)
1599 self.write(')')
1600
Armin Ronacher4da90342010-05-29 17:35:10 +02001601 def visit_MarkSafeIfAutoescape(self, node, frame):
1602 self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1603 self.visit(node.expr, frame)
1604 self.write(')')
1605
Armin Ronachered1e0d42008-05-18 20:25:28 +02001606 def visit_EnvironmentAttribute(self, node, frame):
1607 self.write('environment.' + node.name)
1608
1609 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001610 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001611
1612 def visit_ImportedName(self, node, frame):
1613 self.write(self.import_aliases[node.importname])
1614
1615 def visit_InternalName(self, node, frame):
1616 self.write(node.name)
1617
Armin Ronacher6df604e2008-05-23 22:18:38 +02001618 def visit_ContextReference(self, node, frame):
1619 self.write('context')
1620
Armin Ronachered1e0d42008-05-18 20:25:28 +02001621 def visit_Continue(self, node, frame):
1622 self.writeline('continue', node)
1623
1624 def visit_Break(self, node, frame):
1625 self.writeline('break', node)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001626
1627 def visit_Scope(self, node, frame):
1628 scope_frame = frame.inner()
1629 scope_frame.inspect(node.iter_child_nodes())
1630 aliases = self.push_scope(scope_frame)
1631 self.pull_locals(scope_frame)
1632 self.blockvisit(node.body, scope_frame)
1633 self.pop_scope(aliases, scope_frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001634
1635 def visit_EvalContextModifier(self, node, frame):
1636 for keyword in node.options:
1637 self.writeline('context.eval_ctx.%s = ' % keyword.key)
1638 self.visit(keyword.value, frame)
1639 try:
1640 val = keyword.value.as_const(frame.eval_ctx)
1641 except nodes.Impossible:
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001642 frame.eval_ctx.volatile = True
Armin Ronacher8346bd72010-03-14 19:43:47 +01001643 else:
1644 setattr(frame.eval_ctx, keyword.key, val)
1645
1646 def visit_ScopedEvalContextModifier(self, node, frame):
1647 old_ctx_name = self.temporary_identifier()
1648 safed_ctx = frame.eval_ctx.save()
1649 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1650 self.visit_EvalContextModifier(node, frame)
1651 for child in node.body:
1652 self.visit(child, frame)
1653 frame.eval_ctx.revert(safed_ctx)
1654 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)