blob: 02df8c528e5c4f6e11c3cd3ebf2094781e70cb25 [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
Armin Ronacherab8991e2013-05-18 12:25:16 +010018from jinja2._compat import range_type
Thomas Waldmanne0003552013-05-17 23:52:14 +020019import six
Armin Ronacherd7d663f2013-05-18 11:38:34 +010020from six.moves import cStringIO as StringIO, map
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 Ronacher0d242be2010-02-10 01:35:13 +010034# what method to iterate over items do we want to use for dict iteration
35# in generated code? on 2.x let's go with iteritems, on 3.x with items
36if hasattr(dict, 'iteritems'):
37 dict_item_iter = 'iteritems'
38else:
39 dict_item_iter = 'items'
40
41
Armin Ronacher821a4232010-02-17 07:59:38 +010042# does if 0: dummy(x) get us x into the scope?
43def unoptimize_before_dead_code():
44 x = 42
45 def f():
46 if 0: dummy(x)
47 return f
Armin Ronacher9dd7fad2013-05-18 11:36:32 +010048
49# The getattr is necessary for pypy which does not set this attribute if
50# no closure is on the function
51unoptimize_before_dead_code = bool(
52 getattr(unoptimize_before_dead_code(), '__closure__', None))
Armin Ronacher821a4232010-02-17 07:59:38 +010053
54
Armin Ronacher64b08a02010-03-12 03:17:41 +010055def generate(node, environment, name, filename, stream=None,
56 defer_init=False):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020057 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020058 if not isinstance(node, nodes.Template):
59 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher64b08a02010-03-12 03:17:41 +010060 generator = CodeGenerator(environment, name, filename, stream, defer_init)
Armin Ronachere791c2a2008-04-07 18:39:54 +020061 generator.visit(node)
62 if stream is None:
63 return generator.stream.getvalue()
64
65
Armin Ronacher4dfc9752008-04-09 15:03:29 +020066def has_safe_repr(value):
67 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020068 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020069 return True
Armin Ronacherf6b4b042013-05-18 12:23:30 +010070 if isinstance(value, (bool, int, float, complex, range_type,
71 Markup) + six.string_types):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020072 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020073 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020074 for item in value:
75 if not has_safe_repr(item):
76 return False
77 return True
78 elif isinstance(value, dict):
Thomas Waldmanne0003552013-05-17 23:52:14 +020079 for key, value in six.iteritems(value):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020080 if not has_safe_repr(key):
81 return False
82 if not has_safe_repr(value):
83 return False
84 return True
85 return False
86
87
Armin Ronacherc9705c22008-04-27 21:28:03 +020088def find_undeclared(nodes, names):
89 """Check if the names passed are accessed undeclared. The return value
90 is a set of all the undeclared names from the sequence of names found.
91 """
92 visitor = UndeclaredNameVisitor(names)
93 try:
94 for node in nodes:
95 visitor.visit(node)
96 except VisitorExit:
97 pass
98 return visitor.undeclared
99
100
Armin Ronachere791c2a2008-04-07 18:39:54 +0200101class Identifiers(object):
102 """Tracks the status of identifiers in frames."""
103
104 def __init__(self):
105 # variables that are known to be declared (probably from outer
106 # frames or because they are special for the frame)
107 self.declared = set()
108
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200109 # undeclared variables from outer scopes
110 self.outer_undeclared = set()
111
Armin Ronachere791c2a2008-04-07 18:39:54 +0200112 # names that are accessed without being explicitly declared by
113 # this one or any of the outer scopes. Names can appear both in
114 # declared and undeclared.
115 self.undeclared = set()
116
117 # names that are declared locally
118 self.declared_locally = set()
119
120 # names that are declared by parameters
121 self.declared_parameter = set()
122
123 def add_special(self, name):
124 """Register a special name like `loop`."""
125 self.undeclared.discard(name)
126 self.declared.add(name)
127
Armin Ronacherda632622011-03-13 14:33:27 -0400128 def is_declared(self, name):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200129 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200130 if name in self.declared_locally or name in self.declared_parameter:
131 return True
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200132 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200133
Armin Ronacher74230e62009-10-25 12:46:31 +0100134 def copy(self):
135 return deepcopy(self)
136
Armin Ronachere791c2a2008-04-07 18:39:54 +0200137
138class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200139 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200140
Armin Ronacher8346bd72010-03-14 19:43:47 +0100141 def __init__(self, eval_ctx, parent=None):
142 self.eval_ctx = eval_ctx
Armin Ronachere791c2a2008-04-07 18:39:54 +0200143 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200144
Armin Ronacher75cfb862008-04-11 13:47:22 +0200145 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200146 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200147
Armin Ronacher75cfb862008-04-11 13:47:22 +0200148 # the root frame is basically just the outermost frame, so no if
149 # conditions. This information is used to optimize inheritance
150 # situations.
151 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200152
Armin Ronacher79668952008-09-23 22:52:46 +0200153 # in some dynamic inheritance situations the compiler needs to add
154 # write tests around output statements.
155 self.require_output_check = parent and parent.require_output_check
Armin Ronacherf40c8842008-09-17 18:51:26 +0200156
Armin Ronacherfed44b52008-04-13 19:42:53 +0200157 # inside some tags we are using a buffer rather than yield statements.
158 # this for example affects {% filter %} or {% macro %}. If a frame
159 # is buffered this variable points to the name of the list used as
160 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200161 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200162
Armin Ronacherfed44b52008-04-13 19:42:53 +0200163 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200164 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200165
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100166 # a set of actually assigned names
167 self.assigned_names = set()
168
Armin Ronacherfed44b52008-04-13 19:42:53 +0200169 # the parent of this frame
170 self.parent = parent
171
Armin Ronachere791c2a2008-04-07 18:39:54 +0200172 if parent is not None:
173 self.identifiers.declared.update(
174 parent.identifiers.declared |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200175 parent.identifiers.declared_parameter |
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100176 parent.assigned_names
Armin Ronachere791c2a2008-04-07 18:39:54 +0200177 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200178 self.identifiers.outer_undeclared.update(
179 parent.identifiers.undeclared -
180 self.identifiers.declared
181 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200182 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200183
Armin Ronacher8efc5222008-04-08 14:47:40 +0200184 def copy(self):
185 """Create a copy of the current one."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200186 rv = object.__new__(self.__class__)
187 rv.__dict__.update(self.__dict__)
188 rv.identifiers = object.__new__(self.identifiers.__class__)
189 rv.identifiers.__dict__.update(self.identifiers.__dict__)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200190 return rv
191
Armin Ronacherda632622011-03-13 14:33:27 -0400192 def inspect(self, nodes):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200193 """Walk the node and check for identifiers. If the scope is hard (eg:
194 enforce on a python level) overrides from outer scopes are tracked
195 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200196 """
Armin Ronacherda632622011-03-13 14:33:27 -0400197 visitor = FrameIdentifierVisitor(self.identifiers)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200198 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200199 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200200
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100201 def find_shadowed(self, extra=()):
202 """Find all the shadowed names. extra is an iterable of variables
203 that may be defined with `add_special` which may occour scoped.
204 """
205 i = self.identifiers
206 return (i.declared | i.outer_undeclared) & \
207 (i.declared_locally | i.declared_parameter) | \
208 set(x for x in extra if i.is_declared(x))
209
Armin Ronachere791c2a2008-04-07 18:39:54 +0200210 def inner(self):
211 """Return an inner frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100212 return Frame(self.eval_ctx, self)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200213
Armin Ronacher75cfb862008-04-11 13:47:22 +0200214 def soft(self):
215 """Return a soft frame. A soft frame may not be modified as
216 standalone thing as it shares the resources with the frame it
217 was created of, but it's not a rootlevel frame any longer.
218 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200219 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200220 rv.rootlevel = False
221 return rv
222
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200223 __copy__ = copy
224
Armin Ronachere791c2a2008-04-07 18:39:54 +0200225
Armin Ronacherc9705c22008-04-27 21:28:03 +0200226class VisitorExit(RuntimeError):
227 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
228
229
230class DependencyFinderVisitor(NodeVisitor):
231 """A visitor that collects filter and test calls."""
232
233 def __init__(self):
234 self.filters = set()
235 self.tests = set()
236
237 def visit_Filter(self, node):
238 self.generic_visit(node)
239 self.filters.add(node.name)
240
241 def visit_Test(self, node):
242 self.generic_visit(node)
243 self.tests.add(node.name)
244
245 def visit_Block(self, node):
246 """Stop visiting at blocks."""
247
248
249class UndeclaredNameVisitor(NodeVisitor):
250 """A visitor that checks if a name is accessed without being
251 declared. This is different from the frame visitor as it will
252 not stop at closure frames.
253 """
254
255 def __init__(self, names):
256 self.names = set(names)
257 self.undeclared = set()
258
259 def visit_Name(self, node):
260 if node.ctx == 'load' and node.name in self.names:
261 self.undeclared.add(node.name)
262 if self.undeclared == self.names:
263 raise VisitorExit()
264 else:
265 self.names.discard(node.name)
266
267 def visit_Block(self, node):
268 """Stop visiting a blocks."""
269
270
Armin Ronachere791c2a2008-04-07 18:39:54 +0200271class FrameIdentifierVisitor(NodeVisitor):
272 """A visitor for `Frame.inspect`."""
273
Armin Ronacherda632622011-03-13 14:33:27 -0400274 def __init__(self, identifiers):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200275 self.identifiers = identifiers
276
Armin Ronacherc9705c22008-04-27 21:28:03 +0200277 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200278 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200279 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200280 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200281 elif node.ctx == 'param':
282 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200283 elif node.ctx == 'load' and not \
Armin Ronacherda632622011-03-13 14:33:27 -0400284 self.identifiers.is_declared(node.name):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200285 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200286
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200287 def visit_If(self, node):
288 self.visit(node.test)
Armin Ronacher74230e62009-10-25 12:46:31 +0100289 real_identifiers = self.identifiers
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200290
Armin Ronacher8a672512010-04-05 18:43:07 +0200291 old_names = real_identifiers.declared_locally | \
Armin Ronacher74230e62009-10-25 12:46:31 +0100292 real_identifiers.declared_parameter
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200293
Armin Ronacher74230e62009-10-25 12:46:31 +0100294 def inner_visit(nodes):
Armin Ronacher1965e312009-10-25 13:03:08 +0100295 if not nodes:
296 return set()
Armin Ronacher74230e62009-10-25 12:46:31 +0100297 self.identifiers = real_identifiers.copy()
298 for subnode in nodes:
299 self.visit(subnode)
300 rv = self.identifiers.declared_locally - old_names
301 # we have to remember the undeclared variables of this branch
302 # because we will have to pull them.
303 real_identifiers.undeclared.update(self.identifiers.undeclared)
304 self.identifiers = real_identifiers
305 return rv
306
307 body = inner_visit(node.body)
308 else_ = inner_visit(node.else_ or ())
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200309
310 # the differences between the two branches are also pulled as
311 # undeclared variables
Armin Ronacher8a672512010-04-05 18:43:07 +0200312 real_identifiers.undeclared.update(body.symmetric_difference(else_) -
313 real_identifiers.declared)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200314
Armin Ronacher74230e62009-10-25 12:46:31 +0100315 # remember those that are declared.
316 real_identifiers.declared_locally.update(body | else_)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200317
Armin Ronacherc9705c22008-04-27 21:28:03 +0200318 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200319 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200320
Armin Ronacherc9705c22008-04-27 21:28:03 +0200321 def visit_Import(self, node):
322 self.generic_visit(node)
323 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200324
Armin Ronacherc9705c22008-04-27 21:28:03 +0200325 def visit_FromImport(self, node):
326 self.generic_visit(node)
327 for name in node.names:
328 if isinstance(name, tuple):
329 self.identifiers.declared_locally.add(name[1])
330 else:
331 self.identifiers.declared_locally.add(name)
332
333 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200334 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200335 self.visit(node.node)
336 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200337
Armin Ronacherc9705c22008-04-27 21:28:03 +0200338 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200339 """Visiting stops at for blocks. However the block sequence
340 is visited as part of the outer scope.
341 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200342 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200343
Armin Ronacherc9705c22008-04-27 21:28:03 +0200344 def visit_CallBlock(self, node):
Armin Ronacheref189442010-01-14 01:26:40 +0100345 self.visit(node.call)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200346
347 def visit_FilterBlock(self, node):
348 self.visit(node.filter)
349
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100350 def visit_Scope(self, node):
351 """Stop visiting at scopes."""
352
Armin Ronacherc9705c22008-04-27 21:28:03 +0200353 def visit_Block(self, node):
354 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200355
356
Armin Ronacher75cfb862008-04-11 13:47:22 +0200357class CompilerExit(Exception):
358 """Raised if the compiler encountered a situation where it just
359 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200360 raises such an exception is not further processed.
361 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200362
363
Armin Ronachere791c2a2008-04-07 18:39:54 +0200364class CodeGenerator(NodeVisitor):
365
Armin Ronacher64b08a02010-03-12 03:17:41 +0100366 def __init__(self, environment, name, filename, stream=None,
367 defer_init=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200368 if stream is None:
369 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200370 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200371 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200372 self.filename = filename
373 self.stream = stream
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100374 self.created_block_context = False
Armin Ronacher64b08a02010-03-12 03:17:41 +0100375 self.defer_init = defer_init
Armin Ronacherfed44b52008-04-13 19:42:53 +0200376
Armin Ronacher023b5e92008-05-08 11:03:10 +0200377 # aliases for imports
378 self.import_aliases = {}
379
Armin Ronacherfed44b52008-04-13 19:42:53 +0200380 # a registry for all blocks. Because blocks are moved out
381 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200382 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200383
384 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200385 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200386
387 # some templates have a rootlevel extends. In this case we
388 # can safely assume that we're a child template and do some
389 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200390 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200391
Armin Ronacherba3757b2008-04-16 19:43:16 +0200392 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200393 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200394
Armin Ronacherb9e78752008-05-10 23:36:28 +0200395 # registry of all filters and tests (global, not block local)
396 self.tests = {}
397 self.filters = {}
398
Armin Ronacherba3757b2008-04-16 19:43:16 +0200399 # the debug information
400 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200401 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200402
Armin Ronacherfed44b52008-04-13 19:42:53 +0200403 # the number of new lines before the next write()
404 self._new_lines = 0
405
406 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200407 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200408
409 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200410 self._first_write = True
411
Armin Ronacherfed44b52008-04-13 19:42:53 +0200412 # used by the `temporary_identifier` method to get new
413 # unique, temporary identifier
414 self._last_identifier = 0
415
416 # the current indentation
417 self._indentation = 0
418
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200419 # -- Various compilation helpers
420
Armin Ronachere2244882008-05-19 09:25:57 +0200421 def fail(self, msg, lineno):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100422 """Fail with a :exc:`TemplateAssertionError`."""
Armin Ronachere2244882008-05-19 09:25:57 +0200423 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
424
Armin Ronachere791c2a2008-04-07 18:39:54 +0200425 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200426 """Get a new unique identifier."""
427 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200428 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200429
Armin Ronachered1e0d42008-05-18 20:25:28 +0200430 def buffer(self, frame):
431 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200432 frame.buffer = self.temporary_identifier()
433 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200434
435 def return_buffer_contents(self, frame):
436 """Return the buffer contents of the frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100437 if frame.eval_ctx.volatile:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100438 self.writeline('if context.eval_ctx.autoescape:')
439 self.indent()
440 self.writeline('return Markup(concat(%s))' % frame.buffer)
441 self.outdent()
442 self.writeline('else:')
443 self.indent()
444 self.writeline('return concat(%s)' % frame.buffer)
445 self.outdent()
Armin Ronacher8346bd72010-03-14 19:43:47 +0100446 elif frame.eval_ctx.autoescape:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100447 self.writeline('return Markup(concat(%s))' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200448 else:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100449 self.writeline('return concat(%s)' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200450
Armin Ronachere791c2a2008-04-07 18:39:54 +0200451 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200452 """Indent by one."""
453 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200454
Armin Ronacher8efc5222008-04-08 14:47:40 +0200455 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200456 """Outdent by step."""
457 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200458
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200459 def start_write(self, frame, node=None):
460 """Yield or write into the frame buffer."""
461 if frame.buffer is None:
462 self.writeline('yield ', node)
463 else:
464 self.writeline('%s.append(' % frame.buffer, node)
465
466 def end_write(self, frame):
467 """End the writing process started by `start_write`."""
468 if frame.buffer is not None:
469 self.write(')')
470
471 def simple_write(self, s, frame, node=None):
472 """Simple shortcut for start_write + write + end_write."""
473 self.start_write(frame, node)
474 self.write(s)
475 self.end_write(frame)
476
Armin Ronacherf40c8842008-09-17 18:51:26 +0200477 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200478 """Visit a list of nodes as block in a frame. If the current frame
479 is no buffer a dummy ``if 0: yield None`` is written automatically
480 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200481 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200482 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200483 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200484 else:
485 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200486 try:
487 for node in nodes:
488 self.visit(node, frame)
489 except CompilerExit:
490 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200491
492 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200493 """Write a string into the output stream."""
494 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200495 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200496 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200497 self.code_lineno += self._new_lines
498 if self._write_debug_info is not None:
499 self.debug_info.append((self._write_debug_info,
500 self.code_lineno))
501 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200502 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200503 self.stream.write(' ' * self._indentation)
504 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200505 self.stream.write(x)
506
507 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200508 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200509 self.newline(node, extra)
510 self.write(x)
511
512 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200513 """Add one or more newlines before the next write."""
514 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200515 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200516 self._write_debug_info = node.lineno
517 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200518
Armin Ronacherfd310492008-05-25 00:16:51 +0200519 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200520 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200521 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200522 arguments may not include python keywords otherwise a syntax
523 error could occour. The extra keyword arguments should be given
524 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200525 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200526 # if any of the given keyword arguments is a python keyword
527 # we have to make sure that no invalid call is created.
528 kwarg_workaround = False
529 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200530 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200531 kwarg_workaround = True
532 break
533
Armin Ronacher8efc5222008-04-08 14:47:40 +0200534 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200535 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200536 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200537
538 if not kwarg_workaround:
539 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200540 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200541 self.visit(kwarg, frame)
542 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200543 for key, value in six.iteritems(extra_kwargs):
Armin Ronacherfd310492008-05-25 00:16:51 +0200544 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200545 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200546 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200547 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200548
549 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200550 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200551 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200552 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200553 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200554 for kwarg in node.kwargs:
555 self.write('%r: ' % kwarg.key)
556 self.visit(kwarg.value, frame)
557 self.write(', ')
558 if extra_kwargs is not None:
Thomas Waldmanne0003552013-05-17 23:52:14 +0200559 for key, value in six.iteritems(extra_kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200560 self.write('%r: %s, ' % (key, value))
561 if node.dyn_kwargs is not None:
562 self.write('}, **')
563 self.visit(node.dyn_kwargs, frame)
564 self.write(')')
565 else:
566 self.write('}')
567
568 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200569 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200570 self.visit(node.dyn_kwargs, frame)
571
Armin Ronacherc9705c22008-04-27 21:28:03 +0200572 def pull_locals(self, frame):
573 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200574 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200575 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200576
577 def pull_dependencies(self, nodes):
578 """Pull all the dependencies."""
579 visitor = DependencyFinderVisitor()
580 for node in nodes:
581 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200582 for dependency in 'filters', 'tests':
583 mapping = getattr(self, dependency)
584 for name in getattr(visitor, dependency):
585 if name not in mapping:
586 mapping[name] = self.temporary_identifier()
587 self.writeline('%s = environment.%s[%r]' %
588 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200589
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100590 def unoptimize_scope(self, frame):
591 """Disable Python optimizations for the frame."""
592 # XXX: this is not that nice but it has no real overhead. It
593 # mainly works because python finds the locals before dead code
594 # is removed. If that breaks we have to add a dummy function
595 # that just accepts the arguments and does nothing.
596 if frame.identifiers.declared:
Armin Ronacher821a4232010-02-17 07:59:38 +0100597 self.writeline('%sdummy(%s)' % (
598 unoptimize_before_dead_code and 'if 0: ' or '',
599 ', '.join('l_' + name for name in frame.identifiers.declared)
600 ))
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100601
Armin Ronacher673aa882008-10-04 18:06:57 +0200602 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200603 """This function returns all the shadowed variables in a dict
604 in the form name: alias and will write the required assignments
605 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200606
Armin Ronacher673aa882008-10-04 18:06:57 +0200607 This also predefines locally declared variables from the loop
608 body because under some circumstances it may be the case that
609
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100610 `extra_vars` is passed to `Frame.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200611 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200612 aliases = {}
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100613 for name in frame.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200614 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200615 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200616 to_declare = set()
617 for name in frame.identifiers.declared_locally:
618 if name not in aliases:
619 to_declare.add('l_' + name)
620 if to_declare:
621 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200622 return aliases
623
Armin Ronacher673aa882008-10-04 18:06:57 +0200624 def pop_scope(self, aliases, frame):
625 """Restore all aliases and delete unused variables."""
Thomas Waldmanne0003552013-05-17 23:52:14 +0200626 for name, alias in six.iteritems(aliases):
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200627 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200628 to_delete = set()
629 for name in frame.identifiers.declared_locally:
630 if name not in aliases:
631 to_delete.add('l_' + name)
632 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100633 # we cannot use the del statement here because enclosed
634 # scopes can trigger a SyntaxError:
635 # a = 42; b = lambda: a; del a
636 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200637
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200638 def function_scoping(self, node, frame, children=None,
639 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200640 """In Jinja a few statements require the help of anonymous
641 functions. Those are currently macros and call blocks and in
642 the future also recursive loops. As there is currently
643 technical limitation that doesn't allow reading and writing a
644 variable in a scope where the initial value is coming from an
645 outer scope, this function tries to fall back with a common
646 error message. Additionally the frame passed is modified so
647 that the argumetns are collected and callers are looked up.
648
649 This will return the modified frame.
650 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200651 # we have to iterate twice over it, make sure that works
652 if children is None:
653 children = node.iter_child_nodes()
654 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200655 func_frame = frame.inner()
Armin Ronacherda632622011-03-13 14:33:27 -0400656 func_frame.inspect(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200657
658 # variables that are undeclared (accessed before declaration) and
659 # declared locally *and* part of an outside scope raise a template
660 # assertion error. Reason: we can't generate reasonable code from
Armin Ronacher02b42a82009-03-18 00:59:32 +0100661 # it without aliasing all the variables.
662 # this could be fixed in Python 3 where we have the nonlocal
663 # keyword or if we switch to bytecode generation
Jonas Nockertbdd09dd2013-02-23 20:34:47 +0100664 overridden_closure_vars = (
Armin Ronacher71082072008-04-12 14:19:36 +0200665 func_frame.identifiers.undeclared &
666 func_frame.identifiers.declared &
667 (func_frame.identifiers.declared_locally |
668 func_frame.identifiers.declared_parameter)
669 )
Jonas Nockertbdd09dd2013-02-23 20:34:47 +0100670 if overridden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200671 self.fail('It\'s not possible to set and access variables '
Armin Ronacherefcc0e52009-09-13 00:22:50 -0700672 'derived from an outer scope! (affects: %s)' %
Jonas Nockertbdd09dd2013-02-23 20:34:47 +0100673 ', '.join(sorted(overridden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200674
675 # remove variables from a closure from the frame's undeclared
676 # identifiers.
677 func_frame.identifiers.undeclared -= (
678 func_frame.identifiers.undeclared &
679 func_frame.identifiers.declared
680 )
681
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200682 # no special variables for this scope, abort early
683 if not find_special:
684 return func_frame
685
Armin Ronacher963f97d2008-04-25 11:44:59 +0200686 func_frame.accesses_kwargs = False
687 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200688 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200689 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200690
Armin Ronacherc9705c22008-04-27 21:28:03 +0200691 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
692
693 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200694 func_frame.accesses_caller = True
695 func_frame.identifiers.add_special('caller')
696 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200697 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200698 func_frame.accesses_kwargs = True
699 func_frame.identifiers.add_special('kwargs')
700 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200701 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200702 func_frame.accesses_varargs = True
703 func_frame.identifiers.add_special('varargs')
704 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200705 return func_frame
706
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200707 def macro_body(self, node, frame, children=None):
708 """Dump the function def of a macro or call block."""
709 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100710 # macros are delayed, they never require output checks
711 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200712 args = frame.arguments
Armin Ronachereabf3dd2009-09-12 23:48:18 -0700713 # XXX: this is an ugly fix for the loop nesting bug
714 # (tests.test_old_bugs.test_loop_call_bug). This works around
715 # a identifier nesting problem we have in general. It's just more
716 # likely to happen in loops which is why we work around it. The
717 # real solution would be "nonlocal" all the identifiers that are
718 # leaking into a new python frame and might be used both unassigned
719 # and assigned.
720 if 'loop' in frame.identifiers.declared:
Armin Ronacherb4044392009-09-13 15:56:58 -0700721 args = args + ['l_loop=l_loop']
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200722 self.writeline('def macro(%s):' % ', '.join(args), node)
723 self.indent()
724 self.buffer(frame)
725 self.pull_locals(frame)
726 self.blockvisit(node.body, frame)
727 self.return_buffer_contents(frame)
728 self.outdent()
729 return frame
730
731 def macro_def(self, node, frame):
732 """Dump the macro definition for the def created by macro_body."""
733 arg_tuple = ', '.join(repr(x.name) for x in node.args)
734 name = getattr(node, 'name', None)
735 if len(node.args) == 1:
736 arg_tuple += ','
737 self.write('Macro(environment, macro, %r, (%s), (' %
738 (name, arg_tuple))
739 for arg in node.defaults:
740 self.visit(arg, frame)
741 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200742 self.write('), %r, %r, %r)' % (
743 bool(frame.accesses_kwargs),
744 bool(frame.accesses_varargs),
745 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200746 ))
747
Armin Ronacher547d0b62008-07-04 16:35:10 +0200748 def position(self, node):
749 """Return a human readable position for the node."""
750 rv = 'line %d' % node.lineno
751 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100752 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200753 return rv
754
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200755 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200756
757 def visit_Template(self, node, frame=None):
758 assert frame is None, 'no root frame allowed'
Armin Ronacher1da23d12010-04-05 18:11:18 +0200759 eval_ctx = EvalContext(self.environment, self.name)
Armin Ronacher8346bd72010-03-14 19:43:47 +0100760
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200761 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200762 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200763 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher821a4232010-02-17 07:59:38 +0100764 if not unoptimize_before_dead_code:
765 self.writeline('dummy = lambda *x: None')
Armin Ronacher8edbe492008-04-10 20:43:43 +0200766
Armin Ronacher64b08a02010-03-12 03:17:41 +0100767 # if we want a deferred initialization we cannot move the
768 # environment into a local name
769 envenv = not self.defer_init and ', environment=environment' or ''
770
Armin Ronacher75cfb862008-04-11 13:47:22 +0200771 # do we have an extends tag at all? If not, we can save some
772 # overhead by just not processing any inheritance code.
773 have_extends = node.find(nodes.Extends) is not None
774
Armin Ronacher8edbe492008-04-10 20:43:43 +0200775 # find all blocks
776 for block in node.find_all(nodes.Block):
777 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200778 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200779 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200780
Armin Ronacher023b5e92008-05-08 11:03:10 +0200781 # find all imports and import them
782 for import_ in node.find_all(nodes.ImportedName):
783 if import_.importname not in self.import_aliases:
784 imp = import_.importname
785 self.import_aliases[imp] = alias = self.temporary_identifier()
786 if '.' in imp:
787 module, obj = imp.rsplit('.', 1)
788 self.writeline('from %s import %s as %s' %
789 (module, obj, alias))
790 else:
791 self.writeline('import %s as %s' % (imp, alias))
792
793 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200794 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200795
Armin Ronacher8efc5222008-04-08 14:47:40 +0200796 # generate the root render function.
Armin Ronacher64b08a02010-03-12 03:17:41 +0100797 self.writeline('def root(context%s):' % envenv, extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200798
799 # process the root
Armin Ronacher8346bd72010-03-14 19:43:47 +0100800 frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200801 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200802 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200803 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200804 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200805 if have_extends:
806 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200807 if 'self' in find_undeclared(node.body, ('self',)):
808 frame.identifiers.add_special('self')
809 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200810 self.pull_locals(frame)
811 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200812 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200813 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200814
Armin Ronacher8efc5222008-04-08 14:47:40 +0200815 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200816 if have_extends:
817 if not self.has_known_extends:
818 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200819 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200820 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200821 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200822 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200823 self.indent()
824 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200825 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200826
827 # at this point we now have the blocks collected and can visit them too.
Thomas Waldmanne0003552013-05-17 23:52:14 +0200828 for name, block in six.iteritems(self.blocks):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100829 block_frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200830 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200831 block_frame.block = name
Armin Ronacher64b08a02010-03-12 03:17:41 +0100832 self.writeline('def block_%s(context%s):' % (name, envenv),
833 block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200834 self.indent()
835 undeclared = find_undeclared(block.body, ('self', 'super'))
836 if 'self' in undeclared:
837 block_frame.identifiers.add_special('self')
838 self.writeline('l_self = TemplateReference(context)')
839 if 'super' in undeclared:
840 block_frame.identifiers.add_special('super')
841 self.writeline('l_super = context.super(%r, '
842 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200843 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200844 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200845 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200846 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200847
Armin Ronacher75cfb862008-04-11 13:47:22 +0200848 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200849 for x in self.blocks),
850 extra=1)
851
852 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200853 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
854 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200855
Armin Ronachere791c2a2008-04-07 18:39:54 +0200856 def visit_Block(self, node, frame):
857 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200858 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200859 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200860 # if we know that we are a child template, there is no need to
861 # check if we are one
862 if self.has_known_extends:
863 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200864 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200865 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200866 self.indent()
867 level += 1
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100868 context = node.scoped and 'context.derived(locals())' or 'context'
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100869 self.writeline('for event in context.blocks[%r][0](%s):' % (
870 node.name, context), node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200871 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200872 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200873 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200874
875 def visit_Extends(self, node, frame):
876 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200877 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200878 self.fail('cannot use extend from a non top-level scope',
879 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200880
Armin Ronacher7fb38972008-04-11 13:54:28 +0200881 # if the number of extends statements in general is zero so
882 # far, we don't have to add a check if something extended
883 # the template before this one.
884 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200885
Armin Ronacher7fb38972008-04-11 13:54:28 +0200886 # if we have a known extends we just add a template runtime
887 # error into the generated code. We could catch that at compile
888 # time too, but i welcome it not to confuse users by throwing the
889 # same error at different times just "because we can".
890 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200891 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200892 self.indent()
893 self.writeline('raise TemplateRuntimeError(%r)' %
894 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200895 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200896
Armin Ronacher7fb38972008-04-11 13:54:28 +0200897 # if we have a known extends already we don't need that code here
898 # as we know that the template execution will end here.
899 if self.has_known_extends:
900 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200901
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200902 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200903 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200904 self.write(', %r)' % self.name)
905 self.writeline('for name, parent_block in parent_template.'
Armin Ronacher0d242be2010-02-10 01:35:13 +0100906 'blocks.%s():' % dict_item_iter)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200907 self.indent()
908 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200909 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200910 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200911
912 # if this extends statement was in the root level we can take
913 # advantage of that information and simplify the generated code
914 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200915 if frame.rootlevel:
916 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200917
Armin Ronacher7fb38972008-04-11 13:54:28 +0200918 # and now we have one more
919 self.extends_so_far += 1
920
Armin Ronacherf059ec12008-04-11 22:21:00 +0200921 def visit_Include(self, node, frame):
922 """Handles includes."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100923 if node.with_context:
924 self.unoptimize_scope(frame)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100925 if node.ignore_missing:
926 self.writeline('try:')
927 self.indent()
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100928
929 func_name = 'get_or_select_template'
930 if isinstance(node.template, nodes.Const):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200931 if isinstance(node.template.value, six.string_types):
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100932 func_name = 'get_template'
933 elif isinstance(node.template.value, (tuple, list)):
934 func_name = 'select_template'
935 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
936 func_name = 'select_template'
937
938 self.writeline('template = environment.%s(' % func_name, node)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100939 self.visit(node.template, frame)
940 self.write(', %r)' % self.name)
941 if node.ignore_missing:
942 self.outdent()
943 self.writeline('except TemplateNotFound:')
944 self.indent()
945 self.writeline('pass')
946 self.outdent()
947 self.writeline('else:')
948 self.indent()
949
Armin Ronacherea847c52008-05-02 20:04:32 +0200950 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200951 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200952 'template.new_context(context.parent, True, '
953 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200954 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100955 self.writeline('for event in template.module._body_stream:')
956
Armin Ronacherf059ec12008-04-11 22:21:00 +0200957 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200958 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200959 self.outdent()
960
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100961 if node.ignore_missing:
962 self.outdent()
963
Armin Ronacher0611e492008-04-25 23:44:14 +0200964 def visit_Import(self, node, frame):
965 """Visit regular imports."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100966 if node.with_context:
967 self.unoptimize_scope(frame)
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200968 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200969 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200970 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200971 self.write('environment.get_template(')
972 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200973 self.write(', %r).' % self.name)
974 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200975 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200976 else:
977 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200978 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200979 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100980 frame.assigned_names.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200981
982 def visit_FromImport(self, node, frame):
983 """Visit named imports."""
984 self.newline(node)
985 self.write('included_template = environment.get_template(')
986 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200987 self.write(', %r).' % self.name)
988 if node.with_context:
989 self.write('make_module(context.parent, True)')
990 else:
991 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200992
993 var_names = []
994 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200995 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200996 if isinstance(name, tuple):
997 name, alias = name
998 else:
999 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001000 self.writeline('l_%s = getattr(included_template, '
1001 '%r, missing)' % (alias, name))
1002 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +02001003 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001004 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +02001005 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +02001006 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001007 (alias, 'the template %%r (imported on %s) does '
1008 'not export the requested name %s' % (
1009 self.position(node),
1010 repr(name)
1011 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +02001012 self.outdent()
1013 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +02001014 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +02001015 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +02001016 discarded_names.append(alias)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001017 frame.assigned_names.add(alias)
Armin Ronachera78d2762008-05-15 23:18:07 +02001018
1019 if var_names:
1020 if len(var_names) == 1:
1021 name = var_names[0]
1022 self.writeline('context.vars[%r] = l_%s' % (name, name))
1023 else:
1024 self.writeline('context.vars.update({%s})' % ', '.join(
1025 '%r: l_%s' % (name, name) for name in var_names
1026 ))
1027 if discarded_names:
1028 if len(discarded_names) == 1:
1029 self.writeline('context.exported_vars.discard(%r)' %
1030 discarded_names[0])
1031 else:
1032 self.writeline('context.exported_vars.difference_'
1033 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +02001034
Armin Ronachere791c2a2008-04-07 18:39:54 +02001035 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001036 # when calculating the nodes for the inner frame we have to exclude
1037 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001038 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001039 if node.recursive:
1040 loop_frame = self.function_scoping(node, frame, children,
1041 find_special=False)
1042 else:
1043 loop_frame = frame.inner()
1044 loop_frame.inspect(children)
1045
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001046 # try to figure out if we have an extended loop. An extended loop
1047 # is necessary if the loop is in recursive mode if the special loop
1048 # variable is accessed in the body.
1049 extended_loop = node.recursive or 'loop' in \
1050 find_undeclared(node.iter_child_nodes(
1051 only=('body',)), ('loop',))
1052
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001053 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +02001054 # variables at that point. Because loops can be nested but the loop
1055 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001056 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +02001057 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001058
1059 # otherwise we set up a buffer and add a function def
1060 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001061 self.writeline('def loop(reciter, loop_render_func):', node)
1062 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +02001063 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001064 aliases = {}
1065
Armin Ronacherff53c782008-08-13 18:55:50 +02001066 # make sure the loop variable is a special one and raise a template
1067 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +02001068 if extended_loop:
Armin Ronacher15e9eef2013-05-19 12:44:50 +01001069 self.writeline('l_loop = missing')
Armin Ronacher833a3b52008-08-14 12:31:12 +02001070 loop_frame.identifiers.add_special('loop')
Armin Ronacherff53c782008-08-13 18:55:50 +02001071 for name in node.find_all(nodes.Name):
1072 if name.ctx == 'store' and name.name == 'loop':
1073 self.fail('Can\'t assign to special loop variable '
1074 'in for-loop target', name.lineno)
1075
Armin Ronacherc9705c22008-04-27 21:28:03 +02001076 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001077 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001078 iteration_indicator = self.temporary_identifier()
1079 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001080
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001081 # Create a fake parent loop if the else or test section of a
1082 # loop is accessing the special loop variable and no parent loop
1083 # exists.
1084 if 'loop' not in aliases and 'loop' in find_undeclared(
1085 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1086 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001087 ("'loop' is undefined. the filter section of a loop as well "
Armin Ronacherbc56cd22011-01-15 18:35:45 +01001088 "as the else block don't have access to the special 'loop'"
Armin Ronacher547d0b62008-07-04 16:35:10 +02001089 " variable of the current loop. Because there is no parent "
1090 "loop it's undefined. Happened in loop on %s" %
1091 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001092
1093 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001094 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +02001095 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001096
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001097 # if we have an extened loop and a node test, we filter in the
1098 # "outer frame".
1099 if extended_loop and node.test is not None:
1100 self.write('(')
1101 self.visit(node.target, loop_frame)
1102 self.write(' for ')
1103 self.visit(node.target, loop_frame)
1104 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001105 if node.recursive:
1106 self.write('reciter')
1107 else:
1108 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001109 self.write(' if (')
1110 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001111 self.visit(node.test, test_frame)
1112 self.write('))')
1113
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001114 elif node.recursive:
1115 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001116 else:
1117 self.visit(node.iter, loop_frame)
1118
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001119 if node.recursive:
1120 self.write(', recurse=loop_render_func):')
1121 else:
1122 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001123
1124 # tests in not extended loops become a continue
1125 if not extended_loop and node.test is not None:
1126 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +02001127 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +02001128 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001129 self.write(':')
1130 self.indent()
1131 self.writeline('continue')
1132 self.outdent(2)
1133
Armin Ronacherc9705c22008-04-27 21:28:03 +02001134 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001135 self.blockvisit(node.body, loop_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001136 if node.else_:
1137 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001138 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001139
1140 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001141 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001142 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001143 self.blockvisit(node.else_, loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001144 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001145
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001146 # reset the aliases if there are any.
Armin Ronachercebd8382008-12-25 18:33:46 +01001147 if not node.recursive:
1148 self.pop_scope(aliases, loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001149
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001150 # if the node was recursive we have to return the buffer contents
1151 # and start the iteration code
1152 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001153 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001154 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001155 self.start_write(frame, node)
1156 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001157 self.visit(node.iter, frame)
1158 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001159 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001160
Armin Ronachere791c2a2008-04-07 18:39:54 +02001161 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001162 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001163 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001164 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001165 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001166 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001167 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001168 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001169 if node.else_:
1170 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001171 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001172 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001173 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001174
Armin Ronacher8efc5222008-04-08 14:47:40 +02001175 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001176 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001177 self.newline()
1178 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001179 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001180 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001181 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001182 self.write('l_%s = ' % node.name)
1183 self.macro_def(node, macro_frame)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001184 frame.assigned_names.add(node.name)
Armin Ronacher71082072008-04-12 14:19:36 +02001185
1186 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001187 children = node.iter_child_nodes(exclude=('call',))
1188 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001189 self.writeline('caller = ')
1190 self.macro_def(node, call_frame)
1191 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001192 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001193 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001194
1195 def visit_FilterBlock(self, node, frame):
1196 filter_frame = frame.inner()
1197 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacher673aa882008-10-04 18:06:57 +02001198 aliases = self.push_scope(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001199 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001200 self.buffer(filter_frame)
Armin Ronacherf40c8842008-09-17 18:51:26 +02001201 self.blockvisit(node.body, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001202 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001203 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001204 self.end_write(frame)
Armin Ronacher673aa882008-10-04 18:06:57 +02001205 self.pop_scope(aliases, filter_frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001206
Armin Ronachere791c2a2008-04-07 18:39:54 +02001207 def visit_ExprStmt(self, node, frame):
1208 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001209 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001210
1211 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001212 # if we have a known extends statement, we don't output anything
Armin Ronacher79668952008-09-23 22:52:46 +02001213 # if we are in a require_output_check section
1214 if self.has_known_extends and frame.require_output_check:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001215 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001216
Armin Ronacher665bfb82008-07-14 13:41:46 +02001217 if self.environment.finalize:
Thomas Waldmanne0003552013-05-17 23:52:14 +02001218 finalize = lambda x: six.text_type(self.environment.finalize(x))
Armin Ronacher665bfb82008-07-14 13:41:46 +02001219 else:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001220 finalize = six.text_type
Armin Ronacher665bfb82008-07-14 13:41:46 +02001221
Armin Ronacher79668952008-09-23 22:52:46 +02001222 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001223 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001224 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001225 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001226 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001227 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001228
Armin Ronachere791c2a2008-04-07 18:39:54 +02001229 # try to evaluate as many chunks as possible into a static
1230 # string at compile time.
1231 body = []
1232 for child in node.nodes:
1233 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001234 const = child.as_const(frame.eval_ctx)
Armin Ronacher9cf95912008-05-24 19:54:43 +02001235 except nodes.Impossible:
1236 body.append(child)
1237 continue
Armin Ronacher8346bd72010-03-14 19:43:47 +01001238 # the frame can't be volatile here, becaus otherwise the
1239 # as_const() function would raise an Impossible exception
1240 # at that point.
Armin Ronacher9cf95912008-05-24 19:54:43 +02001241 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001242 if frame.eval_ctx.autoescape:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001243 if hasattr(const, '__html__'):
1244 const = const.__html__()
1245 else:
1246 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001247 const = finalize(const)
Ian Lewisab014bd2010-10-31 20:29:28 +09001248 except Exception:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001249 # if something goes wrong here we evaluate the node
1250 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001251 body.append(child)
1252 continue
1253 if body and isinstance(body[-1], list):
1254 body[-1].append(const)
1255 else:
1256 body.append([const])
1257
Armin Ronachered1e0d42008-05-18 20:25:28 +02001258 # if we have less than 3 nodes or a buffer we yield or extend/append
1259 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001260 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001261 # for one item we append, for more we extend
1262 if len(body) == 1:
1263 self.writeline('%s.append(' % frame.buffer)
1264 else:
1265 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001266 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001267 for item in body:
1268 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001269 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001270 if frame.buffer is None:
1271 self.writeline('yield ' + val)
1272 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001273 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001274 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001275 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001276 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001277 else:
1278 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001279 close = 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001280 if frame.eval_ctx.volatile:
1281 self.write('(context.eval_ctx.autoescape and'
1282 ' escape or to_string)(')
1283 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001284 self.write('escape(')
1285 else:
Armin Ronacherbd357722009-08-05 20:25:06 +02001286 self.write('to_string(')
Armin Ronacherd1342312008-04-28 12:20:12 +02001287 if self.environment.finalize is not None:
1288 self.write('environment.finalize(')
1289 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001290 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001291 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001292 if frame.buffer is not None:
1293 self.write(', ')
1294 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001295 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001296 self.outdent()
1297 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001298
1299 # otherwise we create a format string as this is faster in that case
1300 else:
1301 format = []
1302 arguments = []
1303 for item in body:
1304 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001305 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001306 else:
1307 format.append('%s')
1308 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001309 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001310 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001311 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001312 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001313 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001314 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001315 close = 0
Armin Ronacher8346bd72010-03-14 19:43:47 +01001316 if frame.eval_ctx.volatile:
1317 self.write('(context.eval_ctx.autoescape and'
1318 ' escape or to_string)(')
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001319 close += 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001320 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001321 self.write('escape(')
1322 close += 1
1323 if self.environment.finalize is not None:
1324 self.write('environment.finalize(')
1325 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001326 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001327 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001328 self.outdent()
1329 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001330
Armin Ronacher7fb38972008-04-11 13:54:28 +02001331 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001332 self.outdent()
1333
Armin Ronacher8efc5222008-04-08 14:47:40 +02001334 def visit_Assign(self, node, frame):
1335 self.newline(node)
1336 # toplevel assignments however go into the local namespace and
1337 # the current template's context. We create a copy of the frame
1338 # here and add a set so that the Name visitor can add the assigned
1339 # names here.
1340 if frame.toplevel:
1341 assignment_frame = frame.copy()
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001342 assignment_frame.toplevel_assignments = set()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001343 else:
1344 assignment_frame = frame
1345 self.visit(node.target, assignment_frame)
1346 self.write(' = ')
1347 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001348
1349 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001350 if frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001351 public_names = [x for x in assignment_frame.toplevel_assignments
Armin Ronacher903d1682008-05-23 00:51:58 +02001352 if not x.startswith('_')]
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001353 if len(assignment_frame.toplevel_assignments) == 1:
Thomas Waldmann7d295622013-05-18 00:06:22 +02001354 name = six.advance_iterator(iter(assignment_frame.toplevel_assignments))
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001355 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001356 else:
1357 self.writeline('context.vars.update({')
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001358 for idx, name in enumerate(assignment_frame.toplevel_assignments):
Armin Ronacher69e12db2008-05-12 09:00:03 +02001359 if idx:
1360 self.write(', ')
1361 self.write('%r: l_%s' % (name, name))
1362 self.write('})')
1363 if public_names:
1364 if len(public_names) == 1:
1365 self.writeline('context.exported_vars.add(%r)' %
1366 public_names[0])
1367 else:
1368 self.writeline('context.exported_vars.update((%s))' %
1369 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001370
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001371 # -- Expression Visitors
1372
Armin Ronachere791c2a2008-04-07 18:39:54 +02001373 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001374 if node.ctx == 'store' and frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001375 frame.toplevel_assignments.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001376 self.write('l_' + node.name)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001377 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001378
1379 def visit_Const(self, node, frame):
1380 val = node.value
1381 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001382 self.write(str(val))
1383 else:
1384 self.write(repr(val))
1385
Armin Ronacher5411ce72008-05-25 11:36:22 +02001386 def visit_TemplateData(self, node, frame):
Armin Ronacherffaa2e72010-05-29 20:57:16 +02001387 try:
1388 self.write(repr(node.as_const(frame.eval_ctx)))
1389 except nodes.Impossible:
1390 self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)'
1391 % node.data)
Armin Ronacher5411ce72008-05-25 11:36:22 +02001392
Armin Ronacher8efc5222008-04-08 14:47:40 +02001393 def visit_Tuple(self, node, frame):
1394 self.write('(')
1395 idx = -1
1396 for idx, item in enumerate(node.items):
1397 if idx:
1398 self.write(', ')
1399 self.visit(item, frame)
1400 self.write(idx == 0 and ',)' or ')')
1401
Armin Ronacher8edbe492008-04-10 20:43:43 +02001402 def visit_List(self, node, frame):
1403 self.write('[')
1404 for idx, item in enumerate(node.items):
1405 if idx:
1406 self.write(', ')
1407 self.visit(item, frame)
1408 self.write(']')
1409
1410 def visit_Dict(self, node, frame):
1411 self.write('{')
1412 for idx, item in enumerate(node.items):
1413 if idx:
1414 self.write(', ')
1415 self.visit(item.key, frame)
1416 self.write(': ')
1417 self.visit(item.value, frame)
1418 self.write('}')
1419
Armin Ronachera9195382010-11-29 13:21:57 +01001420 def binop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001421 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001422 if self.environment.sandboxed and \
1423 operator in self.environment.intercepted_binops:
1424 self.write('environment.call_binop(context, %r, ' % operator)
1425 self.visit(node.left, frame)
1426 self.write(', ')
1427 self.visit(node.right, frame)
1428 else:
1429 self.write('(')
1430 self.visit(node.left, frame)
1431 self.write(' %s ' % operator)
1432 self.visit(node.right, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001433 self.write(')')
1434 return visitor
1435
Armin Ronachera9195382010-11-29 13:21:57 +01001436 def uaop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001437 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001438 if self.environment.sandboxed and \
1439 operator in self.environment.intercepted_unops:
1440 self.write('environment.call_unop(context, %r, ' % operator)
1441 self.visit(node.node, frame)
1442 else:
1443 self.write('(' + operator)
1444 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001445 self.write(')')
1446 return visitor
1447
1448 visit_Add = binop('+')
1449 visit_Sub = binop('-')
1450 visit_Mul = binop('*')
1451 visit_Div = binop('/')
1452 visit_FloorDiv = binop('//')
1453 visit_Pow = binop('**')
1454 visit_Mod = binop('%')
Armin Ronachera9195382010-11-29 13:21:57 +01001455 visit_And = binop('and', interceptable=False)
1456 visit_Or = binop('or', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001457 visit_Pos = uaop('+')
1458 visit_Neg = uaop('-')
Armin Ronachera9195382010-11-29 13:21:57 +01001459 visit_Not = uaop('not ', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001460 del binop, uaop
1461
Armin Ronacherd1342312008-04-28 12:20:12 +02001462 def visit_Concat(self, node, frame):
Armin Ronacher8346bd72010-03-14 19:43:47 +01001463 if frame.eval_ctx.volatile:
1464 func_name = '(context.eval_ctx.volatile and' \
1465 ' markup_join or unicode_join)'
1466 elif frame.eval_ctx.autoescape:
1467 func_name = 'markup_join'
1468 else:
1469 func_name = 'unicode_join'
1470 self.write('%s((' % func_name)
Armin Ronacherd1342312008-04-28 12:20:12 +02001471 for arg in node.nodes:
1472 self.visit(arg, frame)
1473 self.write(', ')
1474 self.write('))')
1475
Armin Ronachere791c2a2008-04-07 18:39:54 +02001476 def visit_Compare(self, node, frame):
1477 self.visit(node.expr, frame)
1478 for op in node.ops:
1479 self.visit(op, frame)
1480
1481 def visit_Operand(self, node, frame):
1482 self.write(' %s ' % operators[node.op])
1483 self.visit(node.expr, frame)
1484
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001485 def visit_Getattr(self, node, frame):
1486 self.write('environment.getattr(')
1487 self.visit(node.node, frame)
1488 self.write(', %r)' % node.attr)
1489
1490 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001491 # slices bypass the environment getitem method.
1492 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001493 self.visit(node.node, frame)
1494 self.write('[')
1495 self.visit(node.arg, frame)
1496 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001497 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001498 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001499 self.visit(node.node, frame)
1500 self.write(', ')
1501 self.visit(node.arg, frame)
1502 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001503
1504 def visit_Slice(self, node, frame):
1505 if node.start is not None:
1506 self.visit(node.start, frame)
1507 self.write(':')
1508 if node.stop is not None:
1509 self.visit(node.stop, frame)
1510 if node.step is not None:
1511 self.write(':')
1512 self.visit(node.step, frame)
1513
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001514 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001515 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001516 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001517 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001518 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001519 if getattr(func, 'contextfilter', False):
1520 self.write('context, ')
Armin Ronacher8346bd72010-03-14 19:43:47 +01001521 elif getattr(func, 'evalcontextfilter', False):
1522 self.write('context.eval_ctx, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001523 elif getattr(func, 'environmentfilter', False):
1524 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001525
1526 # if the filter node is None we are inside a filter block
1527 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001528 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001529 self.visit(node.node, frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001530 elif frame.eval_ctx.volatile:
1531 self.write('(context.eval_ctx.autoescape and'
1532 ' Markup(concat(%s)) or concat(%s))' %
1533 (frame.buffer, frame.buffer))
1534 elif frame.eval_ctx.autoescape:
Armin Ronacher3da90312008-05-23 16:37:28 +02001535 self.write('Markup(concat(%s))' % frame.buffer)
1536 else:
1537 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001538 self.signature(node, frame)
1539 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001540
1541 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001542 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001543 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001544 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001545 self.visit(node.node, frame)
1546 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001547 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001548
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001549 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001550 def write_expr2():
1551 if node.expr2 is not None:
1552 return self.visit(node.expr2, frame)
1553 self.write('environment.undefined(%r)' % ('the inline if-'
1554 'expression on %s evaluated to false and '
1555 'no else section was defined.' % self.position(node)))
1556
Cory Benfielde8acd5b2013-05-18 11:58:57 +01001557 self.write('(')
1558 self.visit(node.expr1, frame)
1559 self.write(' if ')
1560 self.visit(node.test, frame)
1561 self.write(' else ')
1562 write_expr2()
1563 self.write(')')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001564
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001565 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001566 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001567 self.write('environment.call(context, ')
1568 else:
1569 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001570 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001571 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001572 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001573 self.write(')')
1574
1575 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001576 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001577 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001578
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001579 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001580
1581 def visit_MarkSafe(self, node, frame):
1582 self.write('Markup(')
1583 self.visit(node.expr, frame)
1584 self.write(')')
1585
Armin Ronacher4da90342010-05-29 17:35:10 +02001586 def visit_MarkSafeIfAutoescape(self, node, frame):
1587 self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1588 self.visit(node.expr, frame)
1589 self.write(')')
1590
Armin Ronachered1e0d42008-05-18 20:25:28 +02001591 def visit_EnvironmentAttribute(self, node, frame):
1592 self.write('environment.' + node.name)
1593
1594 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001595 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001596
1597 def visit_ImportedName(self, node, frame):
1598 self.write(self.import_aliases[node.importname])
1599
1600 def visit_InternalName(self, node, frame):
1601 self.write(node.name)
1602
Armin Ronacher6df604e2008-05-23 22:18:38 +02001603 def visit_ContextReference(self, node, frame):
1604 self.write('context')
1605
Armin Ronachered1e0d42008-05-18 20:25:28 +02001606 def visit_Continue(self, node, frame):
1607 self.writeline('continue', node)
1608
1609 def visit_Break(self, node, frame):
1610 self.writeline('break', node)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001611
1612 def visit_Scope(self, node, frame):
1613 scope_frame = frame.inner()
1614 scope_frame.inspect(node.iter_child_nodes())
1615 aliases = self.push_scope(scope_frame)
1616 self.pull_locals(scope_frame)
1617 self.blockvisit(node.body, scope_frame)
1618 self.pop_scope(aliases, scope_frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001619
1620 def visit_EvalContextModifier(self, node, frame):
1621 for keyword in node.options:
1622 self.writeline('context.eval_ctx.%s = ' % keyword.key)
1623 self.visit(keyword.value, frame)
1624 try:
1625 val = keyword.value.as_const(frame.eval_ctx)
1626 except nodes.Impossible:
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001627 frame.eval_ctx.volatile = True
Armin Ronacher8346bd72010-03-14 19:43:47 +01001628 else:
1629 setattr(frame.eval_ctx, keyword.key, val)
1630
1631 def visit_ScopedEvalContextModifier(self, node, frame):
1632 old_ctx_name = self.temporary_identifier()
1633 safed_ctx = frame.eval_ctx.save()
1634 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1635 self.visit_EvalContextModifier(node, frame)
1636 for child in node.body:
1637 self.visit(child, frame)
1638 frame.eval_ctx.revert(safed_ctx)
1639 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)