blob: 3bc6d354fee587df6d49690751b642b44669fc55 [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 Ronachere791c2a2008-04-07 18:39:54 +020011from cStringIO import StringIO
Armin Ronacherd1ff8582008-05-11 00:30:43 +020012from itertools import chain
Armin Ronacher74230e62009-10-25 12:46:31 +010013from copy import deepcopy
Armin Ronachere791c2a2008-04-07 18:39:54 +020014from jinja2 import nodes
Armin Ronacher8346bd72010-03-14 19:43:47 +010015from jinja2.nodes import EvalContext
Armin Ronachere791c2a2008-04-07 18:39:54 +020016from jinja2.visitor import NodeVisitor, NodeTransformer
17from jinja2.exceptions import TemplateAssertionError
Armin Ronacherbd357722009-08-05 20:25:06 +020018from jinja2.utils import Markup, concat, escape, is_python_keyword, next
Armin Ronachere791c2a2008-04-07 18:39:54 +020019
20
21operators = {
22 'eq': '==',
23 'ne': '!=',
24 'gt': '>',
25 'gteq': '>=',
26 'lt': '<',
27 'lteq': '<=',
28 'in': 'in',
29 'notin': 'not in'
30}
31
Armin Ronacher3d8b7842008-04-13 13:16:50 +020032try:
33 exec '(0 if 0 else 0)'
34except SyntaxError:
35 have_condexpr = False
36else:
37 have_condexpr = True
38
39
Armin Ronacher0d242be2010-02-10 01:35:13 +010040# what method to iterate over items do we want to use for dict iteration
41# in generated code? on 2.x let's go with iteritems, on 3.x with items
42if hasattr(dict, 'iteritems'):
43 dict_item_iter = 'iteritems'
44else:
45 dict_item_iter = 'items'
46
47
Armin Ronacher821a4232010-02-17 07:59:38 +010048# does if 0: dummy(x) get us x into the scope?
49def unoptimize_before_dead_code():
50 x = 42
51 def f():
52 if 0: dummy(x)
53 return f
54unoptimize_before_dead_code = bool(unoptimize_before_dead_code().func_closure)
55
56
Armin Ronacher64b08a02010-03-12 03:17:41 +010057def generate(node, environment, name, filename, stream=None,
58 defer_init=False):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020059 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020060 if not isinstance(node, nodes.Template):
61 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher64b08a02010-03-12 03:17:41 +010062 generator = CodeGenerator(environment, name, filename, stream, defer_init)
Armin Ronachere791c2a2008-04-07 18:39:54 +020063 generator.visit(node)
64 if stream is None:
65 return generator.stream.getvalue()
66
67
Armin Ronacher4dfc9752008-04-09 15:03:29 +020068def has_safe_repr(value):
69 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020070 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020071 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020072 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher32a910f2008-04-26 23:21:03 +020073 xrange, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020074 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020075 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020076 for item in value:
77 if not has_safe_repr(item):
78 return False
79 return True
80 elif isinstance(value, dict):
81 for key, value in value.iteritems():
82 if not has_safe_repr(key):
83 return False
84 if not has_safe_repr(value):
85 return False
86 return True
87 return False
88
89
Armin Ronacherc9705c22008-04-27 21:28:03 +020090def find_undeclared(nodes, names):
91 """Check if the names passed are accessed undeclared. The return value
92 is a set of all the undeclared names from the sequence of names found.
93 """
94 visitor = UndeclaredNameVisitor(names)
95 try:
96 for node in nodes:
97 visitor.visit(node)
98 except VisitorExit:
99 pass
100 return visitor.undeclared
101
102
Armin Ronachere791c2a2008-04-07 18:39:54 +0200103class Identifiers(object):
104 """Tracks the status of identifiers in frames."""
105
106 def __init__(self):
107 # variables that are known to be declared (probably from outer
108 # frames or because they are special for the frame)
109 self.declared = set()
110
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200111 # undeclared variables from outer scopes
112 self.outer_undeclared = set()
113
Armin Ronachere791c2a2008-04-07 18:39:54 +0200114 # names that are accessed without being explicitly declared by
115 # this one or any of the outer scopes. Names can appear both in
116 # declared and undeclared.
117 self.undeclared = set()
118
119 # names that are declared locally
120 self.declared_locally = set()
121
122 # names that are declared by parameters
123 self.declared_parameter = set()
124
125 def add_special(self, name):
126 """Register a special name like `loop`."""
127 self.undeclared.discard(name)
128 self.declared.add(name)
129
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200130 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200131 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200132 if name in self.declared_locally or name in self.declared_parameter:
133 return True
134 if local_only:
135 return False
136 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200137
Armin Ronacher74230e62009-10-25 12:46:31 +0100138 def copy(self):
139 return deepcopy(self)
140
Armin Ronachere791c2a2008-04-07 18:39:54 +0200141
142class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200143 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200144
Armin Ronacher8346bd72010-03-14 19:43:47 +0100145 def __init__(self, eval_ctx, parent=None):
146 self.eval_ctx = eval_ctx
Armin Ronachere791c2a2008-04-07 18:39:54 +0200147 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200148
Armin Ronacher75cfb862008-04-11 13:47:22 +0200149 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200150 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200151
Armin Ronacher75cfb862008-04-11 13:47:22 +0200152 # the root frame is basically just the outermost frame, so no if
153 # conditions. This information is used to optimize inheritance
154 # situations.
155 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200156
Armin Ronacher79668952008-09-23 22:52:46 +0200157 # in some dynamic inheritance situations the compiler needs to add
158 # write tests around output statements.
159 self.require_output_check = parent and parent.require_output_check
Armin Ronacherf40c8842008-09-17 18:51:26 +0200160
Armin Ronacherfed44b52008-04-13 19:42:53 +0200161 # inside some tags we are using a buffer rather than yield statements.
162 # this for example affects {% filter %} or {% macro %}. If a frame
163 # is buffered this variable points to the name of the list used as
164 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200165 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200166
Armin Ronacherfed44b52008-04-13 19:42:53 +0200167 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200168 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200169
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100170 # a set of actually assigned names
171 self.assigned_names = set()
172
Armin Ronacherfed44b52008-04-13 19:42:53 +0200173 # the parent of this frame
174 self.parent = parent
175
Armin Ronachere791c2a2008-04-07 18:39:54 +0200176 if parent is not None:
177 self.identifiers.declared.update(
178 parent.identifiers.declared |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200179 parent.identifiers.declared_parameter |
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100180 parent.assigned_names
Armin Ronachere791c2a2008-04-07 18:39:54 +0200181 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200182 self.identifiers.outer_undeclared.update(
183 parent.identifiers.undeclared -
184 self.identifiers.declared
185 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200186 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200187
Armin Ronacher8efc5222008-04-08 14:47:40 +0200188 def copy(self):
189 """Create a copy of the current one."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200190 rv = object.__new__(self.__class__)
191 rv.__dict__.update(self.__dict__)
192 rv.identifiers = object.__new__(self.identifiers.__class__)
193 rv.identifiers.__dict__.update(self.identifiers.__dict__)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200194 return rv
195
Armin Ronacherc9705c22008-04-27 21:28:03 +0200196 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200197 """Walk the node and check for identifiers. If the scope is hard (eg:
198 enforce on a python level) overrides from outer scopes are tracked
199 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200200 """
201 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200202 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200203 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200204
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100205 def find_shadowed(self, extra=()):
206 """Find all the shadowed names. extra is an iterable of variables
207 that may be defined with `add_special` which may occour scoped.
208 """
209 i = self.identifiers
210 return (i.declared | i.outer_undeclared) & \
211 (i.declared_locally | i.declared_parameter) | \
212 set(x for x in extra if i.is_declared(x))
213
Armin Ronachere791c2a2008-04-07 18:39:54 +0200214 def inner(self):
215 """Return an inner frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100216 return Frame(self.eval_ctx, self)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200217
Armin Ronacher75cfb862008-04-11 13:47:22 +0200218 def soft(self):
219 """Return a soft frame. A soft frame may not be modified as
220 standalone thing as it shares the resources with the frame it
221 was created of, but it's not a rootlevel frame any longer.
222 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200223 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200224 rv.rootlevel = False
225 return rv
226
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200227 __copy__ = copy
228
Armin Ronachere791c2a2008-04-07 18:39:54 +0200229
Armin Ronacherc9705c22008-04-27 21:28:03 +0200230class VisitorExit(RuntimeError):
231 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
232
233
234class DependencyFinderVisitor(NodeVisitor):
235 """A visitor that collects filter and test calls."""
236
237 def __init__(self):
238 self.filters = set()
239 self.tests = set()
240
241 def visit_Filter(self, node):
242 self.generic_visit(node)
243 self.filters.add(node.name)
244
245 def visit_Test(self, node):
246 self.generic_visit(node)
247 self.tests.add(node.name)
248
249 def visit_Block(self, node):
250 """Stop visiting at blocks."""
251
252
253class UndeclaredNameVisitor(NodeVisitor):
254 """A visitor that checks if a name is accessed without being
255 declared. This is different from the frame visitor as it will
256 not stop at closure frames.
257 """
258
259 def __init__(self, names):
260 self.names = set(names)
261 self.undeclared = set()
262
263 def visit_Name(self, node):
264 if node.ctx == 'load' and node.name in self.names:
265 self.undeclared.add(node.name)
266 if self.undeclared == self.names:
267 raise VisitorExit()
268 else:
269 self.names.discard(node.name)
270
271 def visit_Block(self, node):
272 """Stop visiting a blocks."""
273
274
Armin Ronachere791c2a2008-04-07 18:39:54 +0200275class FrameIdentifierVisitor(NodeVisitor):
276 """A visitor for `Frame.inspect`."""
277
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200278 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200279 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200280 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200281
Armin Ronacherc9705c22008-04-27 21:28:03 +0200282 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200283 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200284 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200285 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200286 elif node.ctx == 'param':
287 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200288 elif node.ctx == 'load' and not \
289 self.identifiers.is_declared(node.name, self.hard_scope):
290 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200291
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200292 def visit_If(self, node):
293 self.visit(node.test)
Armin Ronacher74230e62009-10-25 12:46:31 +0100294 real_identifiers = self.identifiers
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200295
Armin Ronacher74230e62009-10-25 12:46:31 +0100296 old_names = real_identifiers.declared | \
297 real_identifiers.declared_locally | \
298 real_identifiers.declared_parameter
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200299
Armin Ronacher74230e62009-10-25 12:46:31 +0100300 def inner_visit(nodes):
Armin Ronacher1965e312009-10-25 13:03:08 +0100301 if not nodes:
302 return set()
Armin Ronacher74230e62009-10-25 12:46:31 +0100303 self.identifiers = real_identifiers.copy()
304 for subnode in nodes:
305 self.visit(subnode)
306 rv = self.identifiers.declared_locally - old_names
307 # we have to remember the undeclared variables of this branch
308 # because we will have to pull them.
309 real_identifiers.undeclared.update(self.identifiers.undeclared)
310 self.identifiers = real_identifiers
311 return rv
312
313 body = inner_visit(node.body)
314 else_ = inner_visit(node.else_ or ())
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200315
316 # the differences between the two branches are also pulled as
317 # undeclared variables
Armin Ronacher74230e62009-10-25 12:46:31 +0100318 real_identifiers.undeclared.update(body.symmetric_difference(else_))
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200319
Armin Ronacher74230e62009-10-25 12:46:31 +0100320 # remember those that are declared.
321 real_identifiers.declared_locally.update(body | else_)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200322
Armin Ronacherc9705c22008-04-27 21:28:03 +0200323 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200324 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200325
Armin Ronacherc9705c22008-04-27 21:28:03 +0200326 def visit_Import(self, node):
327 self.generic_visit(node)
328 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200329
Armin Ronacherc9705c22008-04-27 21:28:03 +0200330 def visit_FromImport(self, node):
331 self.generic_visit(node)
332 for name in node.names:
333 if isinstance(name, tuple):
334 self.identifiers.declared_locally.add(name[1])
335 else:
336 self.identifiers.declared_locally.add(name)
337
338 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200339 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200340 self.visit(node.node)
341 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200342
Armin Ronacherc9705c22008-04-27 21:28:03 +0200343 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200344 """Visiting stops at for blocks. However the block sequence
345 is visited as part of the outer scope.
346 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200347 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200348
Armin Ronacherc9705c22008-04-27 21:28:03 +0200349 def visit_CallBlock(self, node):
Armin Ronacheref189442010-01-14 01:26:40 +0100350 self.visit(node.call)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200351
352 def visit_FilterBlock(self, node):
353 self.visit(node.filter)
354
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100355 def visit_Scope(self, node):
356 """Stop visiting at scopes."""
357
Armin Ronacherc9705c22008-04-27 21:28:03 +0200358 def visit_Block(self, node):
359 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200360
361
Armin Ronacher75cfb862008-04-11 13:47:22 +0200362class CompilerExit(Exception):
363 """Raised if the compiler encountered a situation where it just
364 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200365 raises such an exception is not further processed.
366 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200367
368
Armin Ronachere791c2a2008-04-07 18:39:54 +0200369class CodeGenerator(NodeVisitor):
370
Armin Ronacher64b08a02010-03-12 03:17:41 +0100371 def __init__(self, environment, name, filename, stream=None,
372 defer_init=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200373 if stream is None:
374 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200375 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200376 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200377 self.filename = filename
378 self.stream = stream
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100379 self.created_block_context = False
Armin Ronacher64b08a02010-03-12 03:17:41 +0100380 self.defer_init = defer_init
Armin Ronacherfed44b52008-04-13 19:42:53 +0200381
Armin Ronacher023b5e92008-05-08 11:03:10 +0200382 # aliases for imports
383 self.import_aliases = {}
384
Armin Ronacherfed44b52008-04-13 19:42:53 +0200385 # a registry for all blocks. Because blocks are moved out
386 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200387 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200388
389 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200390 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200391
392 # some templates have a rootlevel extends. In this case we
393 # can safely assume that we're a child template and do some
394 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200395 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200396
Armin Ronacherba3757b2008-04-16 19:43:16 +0200397 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200398 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200399
Armin Ronacherb9e78752008-05-10 23:36:28 +0200400 # registry of all filters and tests (global, not block local)
401 self.tests = {}
402 self.filters = {}
403
Armin Ronacherba3757b2008-04-16 19:43:16 +0200404 # the debug information
405 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200406 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200407
Armin Ronacherfed44b52008-04-13 19:42:53 +0200408 # the number of new lines before the next write()
409 self._new_lines = 0
410
411 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200412 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200413
414 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200415 self._first_write = True
416
Armin Ronacherfed44b52008-04-13 19:42:53 +0200417 # used by the `temporary_identifier` method to get new
418 # unique, temporary identifier
419 self._last_identifier = 0
420
421 # the current indentation
422 self._indentation = 0
423
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200424 # -- Various compilation helpers
425
Armin Ronachere2244882008-05-19 09:25:57 +0200426 def fail(self, msg, lineno):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100427 """Fail with a :exc:`TemplateAssertionError`."""
Armin Ronachere2244882008-05-19 09:25:57 +0200428 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
429
Armin Ronachere791c2a2008-04-07 18:39:54 +0200430 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200431 """Get a new unique identifier."""
432 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200433 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200434
Armin Ronachered1e0d42008-05-18 20:25:28 +0200435 def buffer(self, frame):
436 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200437 frame.buffer = self.temporary_identifier()
438 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200439
440 def return_buffer_contents(self, frame):
441 """Return the buffer contents of the frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100442 self.writeline('return ')
443 if frame.eval_ctx.volatile:
444 self.write('(Markup(concat(%s)) if context.eval_ctx'
445 '.autoescape else concat(%s))' %
446 (frame.buffer, frame.buffer))
447 elif frame.eval_ctx.autoescape:
448 self.write('Markup(concat(%s))' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200449 else:
Armin Ronacher8346bd72010-03-14 19:43:47 +0100450 self.write('concat(%s)' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200451
Armin Ronachere791c2a2008-04-07 18:39:54 +0200452 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200453 """Indent by one."""
454 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200455
Armin Ronacher8efc5222008-04-08 14:47:40 +0200456 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200457 """Outdent by step."""
458 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200459
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200460 def start_write(self, frame, node=None):
461 """Yield or write into the frame buffer."""
462 if frame.buffer is None:
463 self.writeline('yield ', node)
464 else:
465 self.writeline('%s.append(' % frame.buffer, node)
466
467 def end_write(self, frame):
468 """End the writing process started by `start_write`."""
469 if frame.buffer is not None:
470 self.write(')')
471
472 def simple_write(self, s, frame, node=None):
473 """Simple shortcut for start_write + write + end_write."""
474 self.start_write(frame, node)
475 self.write(s)
476 self.end_write(frame)
477
Armin Ronacherf40c8842008-09-17 18:51:26 +0200478 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200479 """Visit a list of nodes as block in a frame. If the current frame
480 is no buffer a dummy ``if 0: yield None`` is written automatically
481 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200482 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200483 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200484 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200485 else:
486 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200487 try:
488 for node in nodes:
489 self.visit(node, frame)
490 except CompilerExit:
491 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200492
493 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200494 """Write a string into the output stream."""
495 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200496 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200497 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200498 self.code_lineno += self._new_lines
499 if self._write_debug_info is not None:
500 self.debug_info.append((self._write_debug_info,
501 self.code_lineno))
502 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200503 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200504 self.stream.write(' ' * self._indentation)
505 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200506 self.stream.write(x)
507
508 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200509 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200510 self.newline(node, extra)
511 self.write(x)
512
513 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200514 """Add one or more newlines before the next write."""
515 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200516 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200517 self._write_debug_info = node.lineno
518 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200519
Armin Ronacherfd310492008-05-25 00:16:51 +0200520 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200521 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200522 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200523 arguments may not include python keywords otherwise a syntax
524 error could occour. The extra keyword arguments should be given
525 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200526 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200527 # if any of the given keyword arguments is a python keyword
528 # we have to make sure that no invalid call is created.
529 kwarg_workaround = False
530 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200531 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200532 kwarg_workaround = True
533 break
534
Armin Ronacher8efc5222008-04-08 14:47:40 +0200535 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200536 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200537 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200538
539 if not kwarg_workaround:
540 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200541 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200542 self.visit(kwarg, frame)
543 if extra_kwargs is not None:
544 for key, value in extra_kwargs.iteritems():
Armin Ronacherfd310492008-05-25 00:16:51 +0200545 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200546 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200547 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200548 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200549
550 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200551 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200552 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200553 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200554 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200555 for kwarg in node.kwargs:
556 self.write('%r: ' % kwarg.key)
557 self.visit(kwarg.value, frame)
558 self.write(', ')
559 if extra_kwargs is not None:
560 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200561 self.write('%r: %s, ' % (key, value))
562 if node.dyn_kwargs is not None:
563 self.write('}, **')
564 self.visit(node.dyn_kwargs, frame)
565 self.write(')')
566 else:
567 self.write('}')
568
569 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200570 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200571 self.visit(node.dyn_kwargs, frame)
572
Armin Ronacherc9705c22008-04-27 21:28:03 +0200573 def pull_locals(self, frame):
574 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200575 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200576 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200577
578 def pull_dependencies(self, nodes):
579 """Pull all the dependencies."""
580 visitor = DependencyFinderVisitor()
581 for node in nodes:
582 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200583 for dependency in 'filters', 'tests':
584 mapping = getattr(self, dependency)
585 for name in getattr(visitor, dependency):
586 if name not in mapping:
587 mapping[name] = self.temporary_identifier()
588 self.writeline('%s = environment.%s[%r]' %
589 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200590
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100591 def unoptimize_scope(self, frame):
592 """Disable Python optimizations for the frame."""
593 # XXX: this is not that nice but it has no real overhead. It
594 # mainly works because python finds the locals before dead code
595 # is removed. If that breaks we have to add a dummy function
596 # that just accepts the arguments and does nothing.
597 if frame.identifiers.declared:
Armin Ronacher821a4232010-02-17 07:59:38 +0100598 self.writeline('%sdummy(%s)' % (
599 unoptimize_before_dead_code and 'if 0: ' or '',
600 ', '.join('l_' + name for name in frame.identifiers.declared)
601 ))
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100602
Armin Ronacher673aa882008-10-04 18:06:57 +0200603 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200604 """This function returns all the shadowed variables in a dict
605 in the form name: alias and will write the required assignments
606 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200607
Armin Ronacher673aa882008-10-04 18:06:57 +0200608 This also predefines locally declared variables from the loop
609 body because under some circumstances it may be the case that
610
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100611 `extra_vars` is passed to `Frame.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200612 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200613 aliases = {}
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100614 for name in frame.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200615 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200616 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200617 to_declare = set()
618 for name in frame.identifiers.declared_locally:
619 if name not in aliases:
620 to_declare.add('l_' + name)
621 if to_declare:
622 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200623 return aliases
624
Armin Ronacher673aa882008-10-04 18:06:57 +0200625 def pop_scope(self, aliases, frame):
626 """Restore all aliases and delete unused variables."""
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200627 for name, alias in aliases.iteritems():
628 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200629 to_delete = set()
630 for name in frame.identifiers.declared_locally:
631 if name not in aliases:
632 to_delete.add('l_' + name)
633 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100634 # we cannot use the del statement here because enclosed
635 # scopes can trigger a SyntaxError:
636 # a = 42; b = lambda: a; del a
637 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200638
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200639 def function_scoping(self, node, frame, children=None,
640 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200641 """In Jinja a few statements require the help of anonymous
642 functions. Those are currently macros and call blocks and in
643 the future also recursive loops. As there is currently
644 technical limitation that doesn't allow reading and writing a
645 variable in a scope where the initial value is coming from an
646 outer scope, this function tries to fall back with a common
647 error message. Additionally the frame passed is modified so
648 that the argumetns are collected and callers are looked up.
649
650 This will return the modified frame.
651 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200652 # we have to iterate twice over it, make sure that works
653 if children is None:
654 children = node.iter_child_nodes()
655 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200656 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200657 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200658
659 # variables that are undeclared (accessed before declaration) and
660 # declared locally *and* part of an outside scope raise a template
661 # assertion error. Reason: we can't generate reasonable code from
Armin Ronacher02b42a82009-03-18 00:59:32 +0100662 # it without aliasing all the variables.
663 # this could be fixed in Python 3 where we have the nonlocal
664 # keyword or if we switch to bytecode generation
Armin Ronacher71082072008-04-12 14:19:36 +0200665 overriden_closure_vars = (
666 func_frame.identifiers.undeclared &
667 func_frame.identifiers.declared &
668 (func_frame.identifiers.declared_locally |
669 func_frame.identifiers.declared_parameter)
670 )
671 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200672 self.fail('It\'s not possible to set and access variables '
Armin Ronacherefcc0e52009-09-13 00:22:50 -0700673 'derived from an outer scope! (affects: %s)' %
Armin Ronachere2244882008-05-19 09:25:57 +0200674 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200675
676 # remove variables from a closure from the frame's undeclared
677 # identifiers.
678 func_frame.identifiers.undeclared -= (
679 func_frame.identifiers.undeclared &
680 func_frame.identifiers.declared
681 )
682
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200683 # no special variables for this scope, abort early
684 if not find_special:
685 return func_frame
686
Armin Ronacher963f97d2008-04-25 11:44:59 +0200687 func_frame.accesses_kwargs = False
688 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200689 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200690 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200691
Armin Ronacherc9705c22008-04-27 21:28:03 +0200692 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
693
694 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200695 func_frame.accesses_caller = True
696 func_frame.identifiers.add_special('caller')
697 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200698 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200699 func_frame.accesses_kwargs = True
700 func_frame.identifiers.add_special('kwargs')
701 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200702 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200703 func_frame.accesses_varargs = True
704 func_frame.identifiers.add_special('varargs')
705 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200706 return func_frame
707
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200708 def macro_body(self, node, frame, children=None):
709 """Dump the function def of a macro or call block."""
710 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100711 # macros are delayed, they never require output checks
712 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200713 args = frame.arguments
Armin Ronachereabf3dd2009-09-12 23:48:18 -0700714 # XXX: this is an ugly fix for the loop nesting bug
715 # (tests.test_old_bugs.test_loop_call_bug). This works around
716 # a identifier nesting problem we have in general. It's just more
717 # likely to happen in loops which is why we work around it. The
718 # real solution would be "nonlocal" all the identifiers that are
719 # leaking into a new python frame and might be used both unassigned
720 # and assigned.
721 if 'loop' in frame.identifiers.declared:
Armin Ronacherb4044392009-09-13 15:56:58 -0700722 args = args + ['l_loop=l_loop']
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200723 self.writeline('def macro(%s):' % ', '.join(args), node)
724 self.indent()
725 self.buffer(frame)
726 self.pull_locals(frame)
727 self.blockvisit(node.body, frame)
728 self.return_buffer_contents(frame)
729 self.outdent()
730 return frame
731
732 def macro_def(self, node, frame):
733 """Dump the macro definition for the def created by macro_body."""
734 arg_tuple = ', '.join(repr(x.name) for x in node.args)
735 name = getattr(node, 'name', None)
736 if len(node.args) == 1:
737 arg_tuple += ','
738 self.write('Macro(environment, macro, %r, (%s), (' %
739 (name, arg_tuple))
740 for arg in node.defaults:
741 self.visit(arg, frame)
742 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200743 self.write('), %r, %r, %r)' % (
744 bool(frame.accesses_kwargs),
745 bool(frame.accesses_varargs),
746 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200747 ))
748
Armin Ronacher547d0b62008-07-04 16:35:10 +0200749 def position(self, node):
750 """Return a human readable position for the node."""
751 rv = 'line %d' % node.lineno
752 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100753 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200754 return rv
755
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200756 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200757
758 def visit_Template(self, node, frame=None):
759 assert frame is None, 'no root frame allowed'
Armin Ronacher8346bd72010-03-14 19:43:47 +0100760 eval_ctx = EvalContext(self.environment)
761
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200762 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200763 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200764 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher821a4232010-02-17 07:59:38 +0100765 if not unoptimize_before_dead_code:
766 self.writeline('dummy = lambda *x: None')
Armin Ronacher8edbe492008-04-10 20:43:43 +0200767
Armin Ronacher64b08a02010-03-12 03:17:41 +0100768 # if we want a deferred initialization we cannot move the
769 # environment into a local name
770 envenv = not self.defer_init and ', environment=environment' or ''
771
Armin Ronacher75cfb862008-04-11 13:47:22 +0200772 # do we have an extends tag at all? If not, we can save some
773 # overhead by just not processing any inheritance code.
774 have_extends = node.find(nodes.Extends) is not None
775
Armin Ronacher8edbe492008-04-10 20:43:43 +0200776 # find all blocks
777 for block in node.find_all(nodes.Block):
778 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200779 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200780 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200781
Armin Ronacher023b5e92008-05-08 11:03:10 +0200782 # find all imports and import them
783 for import_ in node.find_all(nodes.ImportedName):
784 if import_.importname not in self.import_aliases:
785 imp = import_.importname
786 self.import_aliases[imp] = alias = self.temporary_identifier()
787 if '.' in imp:
788 module, obj = imp.rsplit('.', 1)
789 self.writeline('from %s import %s as %s' %
790 (module, obj, alias))
791 else:
792 self.writeline('import %s as %s' % (imp, alias))
793
794 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200795 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200796
Armin Ronacher8efc5222008-04-08 14:47:40 +0200797 # generate the root render function.
Armin Ronacher64b08a02010-03-12 03:17:41 +0100798 self.writeline('def root(context%s):' % envenv, extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200799
800 # process the root
Armin Ronacher8346bd72010-03-14 19:43:47 +0100801 frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200802 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200803 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200804 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200805 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200806 if have_extends:
807 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200808 if 'self' in find_undeclared(node.body, ('self',)):
809 frame.identifiers.add_special('self')
810 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200811 self.pull_locals(frame)
812 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200813 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200814 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200815
Armin Ronacher8efc5222008-04-08 14:47:40 +0200816 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200817 if have_extends:
818 if not self.has_known_extends:
819 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200820 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200821 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200822 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200823 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200824 self.indent()
825 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200826 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200827
828 # at this point we now have the blocks collected and can visit them too.
829 for name, block in self.blocks.iteritems():
Armin Ronacher8346bd72010-03-14 19:43:47 +0100830 block_frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200831 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200832 block_frame.block = name
Armin Ronacher64b08a02010-03-12 03:17:41 +0100833 self.writeline('def block_%s(context%s):' % (name, envenv),
834 block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200835 self.indent()
836 undeclared = find_undeclared(block.body, ('self', 'super'))
837 if 'self' in undeclared:
838 block_frame.identifiers.add_special('self')
839 self.writeline('l_self = TemplateReference(context)')
840 if 'super' in undeclared:
841 block_frame.identifiers.add_special('super')
842 self.writeline('l_super = context.super(%r, '
843 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200844 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200845 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200846 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200847 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200848
Armin Ronacher75cfb862008-04-11 13:47:22 +0200849 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200850 for x in self.blocks),
851 extra=1)
852
853 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200854 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
855 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200856
Armin Ronachere791c2a2008-04-07 18:39:54 +0200857 def visit_Block(self, node, frame):
858 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200859 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200860 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200861 # if we know that we are a child template, there is no need to
862 # check if we are one
863 if self.has_known_extends:
864 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200865 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200866 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200867 self.indent()
868 level += 1
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100869 context = node.scoped and 'context.derived(locals())' or 'context'
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100870 self.writeline('for event in context.blocks[%r][0](%s):' % (
871 node.name, context), node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200872 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200873 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200874 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200875
876 def visit_Extends(self, node, frame):
877 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200878 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200879 self.fail('cannot use extend from a non top-level scope',
880 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200881
Armin Ronacher7fb38972008-04-11 13:54:28 +0200882 # if the number of extends statements in general is zero so
883 # far, we don't have to add a check if something extended
884 # the template before this one.
885 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200886
Armin Ronacher7fb38972008-04-11 13:54:28 +0200887 # if we have a known extends we just add a template runtime
888 # error into the generated code. We could catch that at compile
889 # time too, but i welcome it not to confuse users by throwing the
890 # same error at different times just "because we can".
891 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200892 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200893 self.indent()
894 self.writeline('raise TemplateRuntimeError(%r)' %
895 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200896 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200897
Armin Ronacher7fb38972008-04-11 13:54:28 +0200898 # if we have a known extends already we don't need that code here
899 # as we know that the template execution will end here.
900 if self.has_known_extends:
901 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200902
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200903 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200904 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200905 self.write(', %r)' % self.name)
906 self.writeline('for name, parent_block in parent_template.'
Armin Ronacher0d242be2010-02-10 01:35:13 +0100907 'blocks.%s():' % dict_item_iter)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200908 self.indent()
909 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200910 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200911 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200912
913 # if this extends statement was in the root level we can take
914 # advantage of that information and simplify the generated code
915 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200916 if frame.rootlevel:
917 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200918
Armin Ronacher7fb38972008-04-11 13:54:28 +0200919 # and now we have one more
920 self.extends_so_far += 1
921
Armin Ronacherf059ec12008-04-11 22:21:00 +0200922 def visit_Include(self, node, frame):
923 """Handles includes."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100924 if node.with_context:
925 self.unoptimize_scope(frame)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100926 if node.ignore_missing:
927 self.writeline('try:')
928 self.indent()
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100929
930 func_name = 'get_or_select_template'
931 if isinstance(node.template, nodes.Const):
932 if isinstance(node.template.value, basestring):
933 func_name = 'get_template'
934 elif isinstance(node.template.value, (tuple, list)):
935 func_name = 'select_template'
936 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
937 func_name = 'select_template'
938
939 self.writeline('template = environment.%s(' % func_name, node)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100940 self.visit(node.template, frame)
941 self.write(', %r)' % self.name)
942 if node.ignore_missing:
943 self.outdent()
944 self.writeline('except TemplateNotFound:')
945 self.indent()
946 self.writeline('pass')
947 self.outdent()
948 self.writeline('else:')
949 self.indent()
950
Armin Ronacherea847c52008-05-02 20:04:32 +0200951 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200952 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200953 'template.new_context(context.parent, True, '
954 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200955 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100956 self.writeline('for event in template.module._body_stream:')
957
Armin Ronacherf059ec12008-04-11 22:21:00 +0200958 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200959 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200960 self.outdent()
961
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100962 if node.ignore_missing:
963 self.outdent()
964
Armin Ronacher0611e492008-04-25 23:44:14 +0200965 def visit_Import(self, node, frame):
966 """Visit regular imports."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100967 if node.with_context:
968 self.unoptimize_scope(frame)
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200969 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200970 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200971 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200972 self.write('environment.get_template(')
973 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200974 self.write(', %r).' % self.name)
975 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200976 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200977 else:
978 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200979 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200980 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100981 frame.assigned_names.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200982
983 def visit_FromImport(self, node, frame):
984 """Visit named imports."""
985 self.newline(node)
986 self.write('included_template = environment.get_template(')
987 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200988 self.write(', %r).' % self.name)
989 if node.with_context:
990 self.write('make_module(context.parent, True)')
991 else:
992 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200993
994 var_names = []
995 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200996 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200997 if isinstance(name, tuple):
998 name, alias = name
999 else:
1000 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001001 self.writeline('l_%s = getattr(included_template, '
1002 '%r, missing)' % (alias, name))
1003 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +02001004 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001005 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +02001006 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +02001007 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001008 (alias, 'the template %%r (imported on %s) does '
1009 'not export the requested name %s' % (
1010 self.position(node),
1011 repr(name)
1012 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +02001013 self.outdent()
1014 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +02001015 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +02001016 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +02001017 discarded_names.append(alias)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001018 frame.assigned_names.add(alias)
Armin Ronachera78d2762008-05-15 23:18:07 +02001019
1020 if var_names:
1021 if len(var_names) == 1:
1022 name = var_names[0]
1023 self.writeline('context.vars[%r] = l_%s' % (name, name))
1024 else:
1025 self.writeline('context.vars.update({%s})' % ', '.join(
1026 '%r: l_%s' % (name, name) for name in var_names
1027 ))
1028 if discarded_names:
1029 if len(discarded_names) == 1:
1030 self.writeline('context.exported_vars.discard(%r)' %
1031 discarded_names[0])
1032 else:
1033 self.writeline('context.exported_vars.difference_'
1034 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +02001035
Armin Ronachere791c2a2008-04-07 18:39:54 +02001036 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001037 # when calculating the nodes for the inner frame we have to exclude
1038 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001039 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001040 if node.recursive:
1041 loop_frame = self.function_scoping(node, frame, children,
1042 find_special=False)
1043 else:
1044 loop_frame = frame.inner()
1045 loop_frame.inspect(children)
1046
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001047 # try to figure out if we have an extended loop. An extended loop
1048 # is necessary if the loop is in recursive mode if the special loop
1049 # variable is accessed in the body.
1050 extended_loop = node.recursive or 'loop' in \
1051 find_undeclared(node.iter_child_nodes(
1052 only=('body',)), ('loop',))
1053
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001054 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +02001055 # variables at that point. Because loops can be nested but the loop
1056 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001057 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +02001058 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001059
1060 # otherwise we set up a buffer and add a function def
1061 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001062 self.writeline('def loop(reciter, loop_render_func):', node)
1063 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +02001064 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001065 aliases = {}
1066
Armin Ronacherff53c782008-08-13 18:55:50 +02001067 # make sure the loop variable is a special one and raise a template
1068 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +02001069 if extended_loop:
1070 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 "
1088 "as the else block doesn't have access to the special 'loop'"
1089 " 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:
1218 finalize = lambda x: unicode(self.environment.finalize(x))
1219 else:
1220 finalize = unicode
1221
Armin Ronacher75cfb862008-04-11 13:47:22 +02001222 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001223
Armin Ronacher79668952008-09-23 22:52:46 +02001224 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001225 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001226 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001227 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001228 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001229 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001230
Armin Ronachere791c2a2008-04-07 18:39:54 +02001231 # try to evaluate as many chunks as possible into a static
1232 # string at compile time.
1233 body = []
1234 for child in node.nodes:
1235 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001236 const = child.as_const(frame.eval_ctx)
Armin Ronacher9cf95912008-05-24 19:54:43 +02001237 except nodes.Impossible:
1238 body.append(child)
1239 continue
Armin Ronacher8346bd72010-03-14 19:43:47 +01001240 # the frame can't be volatile here, becaus otherwise the
1241 # as_const() function would raise an Impossible exception
1242 # at that point.
Armin Ronacher9cf95912008-05-24 19:54:43 +02001243 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001244 if frame.eval_ctx.autoescape:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001245 if hasattr(const, '__html__'):
1246 const = const.__html__()
1247 else:
1248 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001249 const = finalize(const)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001250 except:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001251 # if something goes wrong here we evaluate the node
1252 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001253 body.append(child)
1254 continue
1255 if body and isinstance(body[-1], list):
1256 body[-1].append(const)
1257 else:
1258 body.append([const])
1259
Armin Ronachered1e0d42008-05-18 20:25:28 +02001260 # if we have less than 3 nodes or a buffer we yield or extend/append
1261 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001262 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001263 # for one item we append, for more we extend
1264 if len(body) == 1:
1265 self.writeline('%s.append(' % frame.buffer)
1266 else:
1267 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001268 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001269 for item in body:
1270 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001271 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001272 if frame.buffer is None:
1273 self.writeline('yield ' + val)
1274 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001275 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001276 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001277 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001278 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001279 else:
1280 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001281 close = 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001282 if frame.eval_ctx.volatile:
1283 self.write('(context.eval_ctx.autoescape and'
1284 ' escape or to_string)(')
1285 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001286 self.write('escape(')
1287 else:
Armin Ronacherbd357722009-08-05 20:25:06 +02001288 self.write('to_string(')
Armin Ronacherd1342312008-04-28 12:20:12 +02001289 if self.environment.finalize is not None:
1290 self.write('environment.finalize(')
1291 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001292 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001293 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001294 if frame.buffer is not None:
1295 self.write(', ')
1296 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001297 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001298 self.outdent()
1299 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001300
1301 # otherwise we create a format string as this is faster in that case
1302 else:
1303 format = []
1304 arguments = []
1305 for item in body:
1306 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001307 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001308 else:
1309 format.append('%s')
1310 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001311 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001312 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001313 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001314 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001315 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001316 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001317 close = 0
Armin Ronacher8346bd72010-03-14 19:43:47 +01001318 if frame.eval_ctx.volatile:
1319 self.write('(context.eval_ctx.autoescape and'
1320 ' escape or to_string)(')
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001321 close += 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001322 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001323 self.write('escape(')
1324 close += 1
1325 if self.environment.finalize is not None:
1326 self.write('environment.finalize(')
1327 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001328 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001329 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001330 self.outdent()
1331 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001332
Armin Ronacher7fb38972008-04-11 13:54:28 +02001333 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001334 self.outdent()
1335
Armin Ronacher8efc5222008-04-08 14:47:40 +02001336 def visit_Assign(self, node, frame):
1337 self.newline(node)
1338 # toplevel assignments however go into the local namespace and
1339 # the current template's context. We create a copy of the frame
1340 # here and add a set so that the Name visitor can add the assigned
1341 # names here.
1342 if frame.toplevel:
1343 assignment_frame = frame.copy()
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001344 assignment_frame.toplevel_assignments = set()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001345 else:
1346 assignment_frame = frame
1347 self.visit(node.target, assignment_frame)
1348 self.write(' = ')
1349 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001350
1351 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001352 if frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001353 public_names = [x for x in assignment_frame.toplevel_assignments
Armin Ronacher903d1682008-05-23 00:51:58 +02001354 if not x.startswith('_')]
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001355 if len(assignment_frame.toplevel_assignments) == 1:
Armin Ronacherbd357722009-08-05 20:25:06 +02001356 name = next(iter(assignment_frame.toplevel_assignments))
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001357 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001358 else:
1359 self.writeline('context.vars.update({')
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001360 for idx, name in enumerate(assignment_frame.toplevel_assignments):
Armin Ronacher69e12db2008-05-12 09:00:03 +02001361 if idx:
1362 self.write(', ')
1363 self.write('%r: l_%s' % (name, name))
1364 self.write('})')
1365 if public_names:
1366 if len(public_names) == 1:
1367 self.writeline('context.exported_vars.add(%r)' %
1368 public_names[0])
1369 else:
1370 self.writeline('context.exported_vars.update((%s))' %
1371 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001372
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001373 # -- Expression Visitors
1374
Armin Ronachere791c2a2008-04-07 18:39:54 +02001375 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001376 if node.ctx == 'store' and frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001377 frame.toplevel_assignments.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001378 self.write('l_' + node.name)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001379 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001380
1381 def visit_Const(self, node, frame):
1382 val = node.value
1383 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001384 self.write(str(val))
1385 else:
1386 self.write(repr(val))
1387
Armin Ronacher5411ce72008-05-25 11:36:22 +02001388 def visit_TemplateData(self, node, frame):
Armin Ronacher8346bd72010-03-14 19:43:47 +01001389 self.write(repr(node.as_const(frame.eval_ctx)))
Armin Ronacher5411ce72008-05-25 11:36:22 +02001390
Armin Ronacher8efc5222008-04-08 14:47:40 +02001391 def visit_Tuple(self, node, frame):
1392 self.write('(')
1393 idx = -1
1394 for idx, item in enumerate(node.items):
1395 if idx:
1396 self.write(', ')
1397 self.visit(item, frame)
1398 self.write(idx == 0 and ',)' or ')')
1399
Armin Ronacher8edbe492008-04-10 20:43:43 +02001400 def visit_List(self, node, frame):
1401 self.write('[')
1402 for idx, item in enumerate(node.items):
1403 if idx:
1404 self.write(', ')
1405 self.visit(item, frame)
1406 self.write(']')
1407
1408 def visit_Dict(self, node, frame):
1409 self.write('{')
1410 for idx, item in enumerate(node.items):
1411 if idx:
1412 self.write(', ')
1413 self.visit(item.key, frame)
1414 self.write(': ')
1415 self.visit(item.value, frame)
1416 self.write('}')
1417
Armin Ronachere791c2a2008-04-07 18:39:54 +02001418 def binop(operator):
1419 def visitor(self, node, frame):
1420 self.write('(')
1421 self.visit(node.left, frame)
1422 self.write(' %s ' % operator)
1423 self.visit(node.right, frame)
1424 self.write(')')
1425 return visitor
1426
1427 def uaop(operator):
1428 def visitor(self, node, frame):
1429 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001430 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001431 self.write(')')
1432 return visitor
1433
1434 visit_Add = binop('+')
1435 visit_Sub = binop('-')
1436 visit_Mul = binop('*')
1437 visit_Div = binop('/')
1438 visit_FloorDiv = binop('//')
1439 visit_Pow = binop('**')
1440 visit_Mod = binop('%')
1441 visit_And = binop('and')
1442 visit_Or = binop('or')
1443 visit_Pos = uaop('+')
1444 visit_Neg = uaop('-')
1445 visit_Not = uaop('not ')
1446 del binop, uaop
1447
Armin Ronacherd1342312008-04-28 12:20:12 +02001448 def visit_Concat(self, node, frame):
Armin Ronacher8346bd72010-03-14 19:43:47 +01001449 if frame.eval_ctx.volatile:
1450 func_name = '(context.eval_ctx.volatile and' \
1451 ' markup_join or unicode_join)'
1452 elif frame.eval_ctx.autoescape:
1453 func_name = 'markup_join'
1454 else:
1455 func_name = 'unicode_join'
1456 self.write('%s((' % func_name)
Armin Ronacherd1342312008-04-28 12:20:12 +02001457 for arg in node.nodes:
1458 self.visit(arg, frame)
1459 self.write(', ')
1460 self.write('))')
1461
Armin Ronachere791c2a2008-04-07 18:39:54 +02001462 def visit_Compare(self, node, frame):
1463 self.visit(node.expr, frame)
1464 for op in node.ops:
1465 self.visit(op, frame)
1466
1467 def visit_Operand(self, node, frame):
1468 self.write(' %s ' % operators[node.op])
1469 self.visit(node.expr, frame)
1470
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001471 def visit_Getattr(self, node, frame):
1472 self.write('environment.getattr(')
1473 self.visit(node.node, frame)
1474 self.write(', %r)' % node.attr)
1475
1476 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001477 # slices bypass the environment getitem method.
1478 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001479 self.visit(node.node, frame)
1480 self.write('[')
1481 self.visit(node.arg, frame)
1482 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001483 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001484 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001485 self.visit(node.node, frame)
1486 self.write(', ')
1487 self.visit(node.arg, frame)
1488 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001489
1490 def visit_Slice(self, node, frame):
1491 if node.start is not None:
1492 self.visit(node.start, frame)
1493 self.write(':')
1494 if node.stop is not None:
1495 self.visit(node.stop, frame)
1496 if node.step is not None:
1497 self.write(':')
1498 self.visit(node.step, frame)
1499
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001500 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001501 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001502 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001503 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001504 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001505 if getattr(func, 'contextfilter', False):
1506 self.write('context, ')
Armin Ronacher8346bd72010-03-14 19:43:47 +01001507 elif getattr(func, 'evalcontextfilter', False):
1508 self.write('context.eval_ctx, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001509 elif getattr(func, 'environmentfilter', False):
1510 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001511
1512 # if the filter node is None we are inside a filter block
1513 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001514 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001515 self.visit(node.node, frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001516 elif frame.eval_ctx.volatile:
1517 self.write('(context.eval_ctx.autoescape and'
1518 ' Markup(concat(%s)) or concat(%s))' %
1519 (frame.buffer, frame.buffer))
1520 elif frame.eval_ctx.autoescape:
Armin Ronacher3da90312008-05-23 16:37:28 +02001521 self.write('Markup(concat(%s))' % frame.buffer)
1522 else:
1523 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001524 self.signature(node, frame)
1525 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001526
1527 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001528 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001529 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001530 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001531 self.visit(node.node, frame)
1532 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001533 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001534
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001535 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001536 def write_expr2():
1537 if node.expr2 is not None:
1538 return self.visit(node.expr2, frame)
1539 self.write('environment.undefined(%r)' % ('the inline if-'
1540 'expression on %s evaluated to false and '
1541 'no else section was defined.' % self.position(node)))
1542
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001543 if not have_condexpr:
1544 self.write('((')
1545 self.visit(node.test, frame)
1546 self.write(') and (')
1547 self.visit(node.expr1, frame)
1548 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001549 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001550 self.write(',))[0]')
1551 else:
1552 self.write('(')
1553 self.visit(node.expr1, frame)
1554 self.write(' if ')
1555 self.visit(node.test, frame)
1556 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001557 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001558 self.write(')')
1559
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001560 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001561 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001562 self.write('environment.call(context, ')
1563 else:
1564 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001565 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001566 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001567 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001568 self.write(')')
1569
1570 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001571 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001572 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001573
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001574 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001575
1576 def visit_MarkSafe(self, node, frame):
1577 self.write('Markup(')
1578 self.visit(node.expr, frame)
1579 self.write(')')
1580
1581 def visit_EnvironmentAttribute(self, node, frame):
1582 self.write('environment.' + node.name)
1583
1584 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001585 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001586
1587 def visit_ImportedName(self, node, frame):
1588 self.write(self.import_aliases[node.importname])
1589
1590 def visit_InternalName(self, node, frame):
1591 self.write(node.name)
1592
Armin Ronacher6df604e2008-05-23 22:18:38 +02001593 def visit_ContextReference(self, node, frame):
1594 self.write('context')
1595
Armin Ronachered1e0d42008-05-18 20:25:28 +02001596 def visit_Continue(self, node, frame):
1597 self.writeline('continue', node)
1598
1599 def visit_Break(self, node, frame):
1600 self.writeline('break', node)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001601
1602 def visit_Scope(self, node, frame):
1603 scope_frame = frame.inner()
1604 scope_frame.inspect(node.iter_child_nodes())
1605 aliases = self.push_scope(scope_frame)
1606 self.pull_locals(scope_frame)
1607 self.blockvisit(node.body, scope_frame)
1608 self.pop_scope(aliases, scope_frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001609
1610 def visit_EvalContextModifier(self, node, frame):
1611 for keyword in node.options:
1612 self.writeline('context.eval_ctx.%s = ' % keyword.key)
1613 self.visit(keyword.value, frame)
1614 try:
1615 val = keyword.value.as_const(frame.eval_ctx)
1616 except nodes.Impossible:
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001617 frame.eval_ctx.volatile = True
Armin Ronacher8346bd72010-03-14 19:43:47 +01001618 else:
1619 setattr(frame.eval_ctx, keyword.key, val)
1620
1621 def visit_ScopedEvalContextModifier(self, node, frame):
1622 old_ctx_name = self.temporary_identifier()
1623 safed_ctx = frame.eval_ctx.save()
1624 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1625 self.visit_EvalContextModifier(node, frame)
1626 for child in node.body:
1627 self.visit(child, frame)
1628 frame.eval_ctx.revert(safed_ctx)
1629 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)