blob: 57641596a32aadc87b43d68528a2846ea749b80f [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 Ronacher8a672512010-04-05 18:43:07 +0200296 old_names = real_identifiers.declared_locally | \
Armin Ronacher74230e62009-10-25 12:46:31 +0100297 real_identifiers.declared_parameter
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200298
Armin Ronacher74230e62009-10-25 12:46:31 +0100299 def inner_visit(nodes):
Armin Ronacher1965e312009-10-25 13:03:08 +0100300 if not nodes:
301 return set()
Armin Ronacher74230e62009-10-25 12:46:31 +0100302 self.identifiers = real_identifiers.copy()
303 for subnode in nodes:
304 self.visit(subnode)
305 rv = self.identifiers.declared_locally - old_names
306 # we have to remember the undeclared variables of this branch
307 # because we will have to pull them.
308 real_identifiers.undeclared.update(self.identifiers.undeclared)
309 self.identifiers = real_identifiers
310 return rv
311
312 body = inner_visit(node.body)
313 else_ = inner_visit(node.else_ or ())
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200314
315 # the differences between the two branches are also pulled as
316 # undeclared variables
Armin Ronacher8a672512010-04-05 18:43:07 +0200317 real_identifiers.undeclared.update(body.symmetric_difference(else_) -
318 real_identifiers.declared)
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 if frame.eval_ctx.volatile:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100443 self.writeline('if context.eval_ctx.autoescape:')
444 self.indent()
445 self.writeline('return Markup(concat(%s))' % frame.buffer)
446 self.outdent()
447 self.writeline('else:')
448 self.indent()
449 self.writeline('return concat(%s)' % frame.buffer)
450 self.outdent()
Armin Ronacher8346bd72010-03-14 19:43:47 +0100451 elif frame.eval_ctx.autoescape:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100452 self.writeline('return Markup(concat(%s))' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200453 else:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100454 self.writeline('return concat(%s)' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200455
Armin Ronachere791c2a2008-04-07 18:39:54 +0200456 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200457 """Indent by one."""
458 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200459
Armin Ronacher8efc5222008-04-08 14:47:40 +0200460 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200461 """Outdent by step."""
462 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200463
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200464 def start_write(self, frame, node=None):
465 """Yield or write into the frame buffer."""
466 if frame.buffer is None:
467 self.writeline('yield ', node)
468 else:
469 self.writeline('%s.append(' % frame.buffer, node)
470
471 def end_write(self, frame):
472 """End the writing process started by `start_write`."""
473 if frame.buffer is not None:
474 self.write(')')
475
476 def simple_write(self, s, frame, node=None):
477 """Simple shortcut for start_write + write + end_write."""
478 self.start_write(frame, node)
479 self.write(s)
480 self.end_write(frame)
481
Armin Ronacherf40c8842008-09-17 18:51:26 +0200482 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200483 """Visit a list of nodes as block in a frame. If the current frame
484 is no buffer a dummy ``if 0: yield None`` is written automatically
485 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200486 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200487 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200488 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200489 else:
490 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200491 try:
492 for node in nodes:
493 self.visit(node, frame)
494 except CompilerExit:
495 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200496
497 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200498 """Write a string into the output stream."""
499 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200500 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200501 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200502 self.code_lineno += self._new_lines
503 if self._write_debug_info is not None:
504 self.debug_info.append((self._write_debug_info,
505 self.code_lineno))
506 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200507 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200508 self.stream.write(' ' * self._indentation)
509 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200510 self.stream.write(x)
511
512 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200513 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200514 self.newline(node, extra)
515 self.write(x)
516
517 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200518 """Add one or more newlines before the next write."""
519 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200520 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200521 self._write_debug_info = node.lineno
522 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200523
Armin Ronacherfd310492008-05-25 00:16:51 +0200524 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200525 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200526 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200527 arguments may not include python keywords otherwise a syntax
528 error could occour. The extra keyword arguments should be given
529 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200530 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200531 # if any of the given keyword arguments is a python keyword
532 # we have to make sure that no invalid call is created.
533 kwarg_workaround = False
534 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200535 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200536 kwarg_workaround = True
537 break
538
Armin Ronacher8efc5222008-04-08 14:47:40 +0200539 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200540 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200541 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200542
543 if not kwarg_workaround:
544 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200545 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200546 self.visit(kwarg, frame)
547 if extra_kwargs is not None:
548 for key, value in extra_kwargs.iteritems():
Armin Ronacherfd310492008-05-25 00:16:51 +0200549 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200550 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200551 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200552 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200553
554 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200555 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200556 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200557 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200558 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200559 for kwarg in node.kwargs:
560 self.write('%r: ' % kwarg.key)
561 self.visit(kwarg.value, frame)
562 self.write(', ')
563 if extra_kwargs is not None:
564 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200565 self.write('%r: %s, ' % (key, value))
566 if node.dyn_kwargs is not None:
567 self.write('}, **')
568 self.visit(node.dyn_kwargs, frame)
569 self.write(')')
570 else:
571 self.write('}')
572
573 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200574 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200575 self.visit(node.dyn_kwargs, frame)
576
Armin Ronacherc9705c22008-04-27 21:28:03 +0200577 def pull_locals(self, frame):
578 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200579 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200580 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200581
582 def pull_dependencies(self, nodes):
583 """Pull all the dependencies."""
584 visitor = DependencyFinderVisitor()
585 for node in nodes:
586 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200587 for dependency in 'filters', 'tests':
588 mapping = getattr(self, dependency)
589 for name in getattr(visitor, dependency):
590 if name not in mapping:
591 mapping[name] = self.temporary_identifier()
592 self.writeline('%s = environment.%s[%r]' %
593 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200594
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100595 def unoptimize_scope(self, frame):
596 """Disable Python optimizations for the frame."""
597 # XXX: this is not that nice but it has no real overhead. It
598 # mainly works because python finds the locals before dead code
599 # is removed. If that breaks we have to add a dummy function
600 # that just accepts the arguments and does nothing.
601 if frame.identifiers.declared:
Armin Ronacher821a4232010-02-17 07:59:38 +0100602 self.writeline('%sdummy(%s)' % (
603 unoptimize_before_dead_code and 'if 0: ' or '',
604 ', '.join('l_' + name for name in frame.identifiers.declared)
605 ))
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100606
Armin Ronacher673aa882008-10-04 18:06:57 +0200607 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200608 """This function returns all the shadowed variables in a dict
609 in the form name: alias and will write the required assignments
610 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200611
Armin Ronacher673aa882008-10-04 18:06:57 +0200612 This also predefines locally declared variables from the loop
613 body because under some circumstances it may be the case that
614
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100615 `extra_vars` is passed to `Frame.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200616 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200617 aliases = {}
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100618 for name in frame.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200619 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200620 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200621 to_declare = set()
622 for name in frame.identifiers.declared_locally:
623 if name not in aliases:
624 to_declare.add('l_' + name)
625 if to_declare:
626 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200627 return aliases
628
Armin Ronacher673aa882008-10-04 18:06:57 +0200629 def pop_scope(self, aliases, frame):
630 """Restore all aliases and delete unused variables."""
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200631 for name, alias in aliases.iteritems():
632 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200633 to_delete = set()
634 for name in frame.identifiers.declared_locally:
635 if name not in aliases:
636 to_delete.add('l_' + name)
637 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100638 # we cannot use the del statement here because enclosed
639 # scopes can trigger a SyntaxError:
640 # a = 42; b = lambda: a; del a
641 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200642
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200643 def function_scoping(self, node, frame, children=None,
644 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200645 """In Jinja a few statements require the help of anonymous
646 functions. Those are currently macros and call blocks and in
647 the future also recursive loops. As there is currently
648 technical limitation that doesn't allow reading and writing a
649 variable in a scope where the initial value is coming from an
650 outer scope, this function tries to fall back with a common
651 error message. Additionally the frame passed is modified so
652 that the argumetns are collected and callers are looked up.
653
654 This will return the modified frame.
655 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200656 # we have to iterate twice over it, make sure that works
657 if children is None:
658 children = node.iter_child_nodes()
659 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200660 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200661 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200662
663 # variables that are undeclared (accessed before declaration) and
664 # declared locally *and* part of an outside scope raise a template
665 # assertion error. Reason: we can't generate reasonable code from
Armin Ronacher02b42a82009-03-18 00:59:32 +0100666 # it without aliasing all the variables.
667 # this could be fixed in Python 3 where we have the nonlocal
668 # keyword or if we switch to bytecode generation
Armin Ronacher71082072008-04-12 14:19:36 +0200669 overriden_closure_vars = (
670 func_frame.identifiers.undeclared &
671 func_frame.identifiers.declared &
672 (func_frame.identifiers.declared_locally |
673 func_frame.identifiers.declared_parameter)
674 )
675 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200676 self.fail('It\'s not possible to set and access variables '
Armin Ronacherefcc0e52009-09-13 00:22:50 -0700677 'derived from an outer scope! (affects: %s)' %
Armin Ronachere2244882008-05-19 09:25:57 +0200678 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200679
680 # remove variables from a closure from the frame's undeclared
681 # identifiers.
682 func_frame.identifiers.undeclared -= (
683 func_frame.identifiers.undeclared &
684 func_frame.identifiers.declared
685 )
686
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200687 # no special variables for this scope, abort early
688 if not find_special:
689 return func_frame
690
Armin Ronacher963f97d2008-04-25 11:44:59 +0200691 func_frame.accesses_kwargs = False
692 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200693 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200694 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200695
Armin Ronacherc9705c22008-04-27 21:28:03 +0200696 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
697
698 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200699 func_frame.accesses_caller = True
700 func_frame.identifiers.add_special('caller')
701 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200702 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200703 func_frame.accesses_kwargs = True
704 func_frame.identifiers.add_special('kwargs')
705 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200706 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200707 func_frame.accesses_varargs = True
708 func_frame.identifiers.add_special('varargs')
709 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200710 return func_frame
711
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200712 def macro_body(self, node, frame, children=None):
713 """Dump the function def of a macro or call block."""
714 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100715 # macros are delayed, they never require output checks
716 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200717 args = frame.arguments
Armin Ronachereabf3dd2009-09-12 23:48:18 -0700718 # XXX: this is an ugly fix for the loop nesting bug
719 # (tests.test_old_bugs.test_loop_call_bug). This works around
720 # a identifier nesting problem we have in general. It's just more
721 # likely to happen in loops which is why we work around it. The
722 # real solution would be "nonlocal" all the identifiers that are
723 # leaking into a new python frame and might be used both unassigned
724 # and assigned.
725 if 'loop' in frame.identifiers.declared:
Armin Ronacherb4044392009-09-13 15:56:58 -0700726 args = args + ['l_loop=l_loop']
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200727 self.writeline('def macro(%s):' % ', '.join(args), node)
728 self.indent()
729 self.buffer(frame)
730 self.pull_locals(frame)
731 self.blockvisit(node.body, frame)
732 self.return_buffer_contents(frame)
733 self.outdent()
734 return frame
735
736 def macro_def(self, node, frame):
737 """Dump the macro definition for the def created by macro_body."""
738 arg_tuple = ', '.join(repr(x.name) for x in node.args)
739 name = getattr(node, 'name', None)
740 if len(node.args) == 1:
741 arg_tuple += ','
742 self.write('Macro(environment, macro, %r, (%s), (' %
743 (name, arg_tuple))
744 for arg in node.defaults:
745 self.visit(arg, frame)
746 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200747 self.write('), %r, %r, %r)' % (
748 bool(frame.accesses_kwargs),
749 bool(frame.accesses_varargs),
750 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200751 ))
752
Armin Ronacher547d0b62008-07-04 16:35:10 +0200753 def position(self, node):
754 """Return a human readable position for the node."""
755 rv = 'line %d' % node.lineno
756 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100757 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200758 return rv
759
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200760 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200761
762 def visit_Template(self, node, frame=None):
763 assert frame is None, 'no root frame allowed'
Armin Ronacher1da23d12010-04-05 18:11:18 +0200764 eval_ctx = EvalContext(self.environment, self.name)
Armin Ronacher8346bd72010-03-14 19:43:47 +0100765
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200766 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200767 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200768 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher821a4232010-02-17 07:59:38 +0100769 if not unoptimize_before_dead_code:
770 self.writeline('dummy = lambda *x: None')
Armin Ronacher8edbe492008-04-10 20:43:43 +0200771
Armin Ronacher64b08a02010-03-12 03:17:41 +0100772 # if we want a deferred initialization we cannot move the
773 # environment into a local name
774 envenv = not self.defer_init and ', environment=environment' or ''
775
Armin Ronacher75cfb862008-04-11 13:47:22 +0200776 # do we have an extends tag at all? If not, we can save some
777 # overhead by just not processing any inheritance code.
778 have_extends = node.find(nodes.Extends) is not None
779
Armin Ronacher8edbe492008-04-10 20:43:43 +0200780 # find all blocks
781 for block in node.find_all(nodes.Block):
782 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200783 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200784 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200785
Armin Ronacher023b5e92008-05-08 11:03:10 +0200786 # find all imports and import them
787 for import_ in node.find_all(nodes.ImportedName):
788 if import_.importname not in self.import_aliases:
789 imp = import_.importname
790 self.import_aliases[imp] = alias = self.temporary_identifier()
791 if '.' in imp:
792 module, obj = imp.rsplit('.', 1)
793 self.writeline('from %s import %s as %s' %
794 (module, obj, alias))
795 else:
796 self.writeline('import %s as %s' % (imp, alias))
797
798 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200799 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200800
Armin Ronacher8efc5222008-04-08 14:47:40 +0200801 # generate the root render function.
Armin Ronacher64b08a02010-03-12 03:17:41 +0100802 self.writeline('def root(context%s):' % envenv, extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200803
804 # process the root
Armin Ronacher8346bd72010-03-14 19:43:47 +0100805 frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200806 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200807 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200808 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200809 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200810 if have_extends:
811 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200812 if 'self' in find_undeclared(node.body, ('self',)):
813 frame.identifiers.add_special('self')
814 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200815 self.pull_locals(frame)
816 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200817 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200818 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200819
Armin Ronacher8efc5222008-04-08 14:47:40 +0200820 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200821 if have_extends:
822 if not self.has_known_extends:
823 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200824 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200825 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200826 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200827 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200828 self.indent()
829 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200830 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200831
832 # at this point we now have the blocks collected and can visit them too.
833 for name, block in self.blocks.iteritems():
Armin Ronacher8346bd72010-03-14 19:43:47 +0100834 block_frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200835 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200836 block_frame.block = name
Armin Ronacher64b08a02010-03-12 03:17:41 +0100837 self.writeline('def block_%s(context%s):' % (name, envenv),
838 block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200839 self.indent()
840 undeclared = find_undeclared(block.body, ('self', 'super'))
841 if 'self' in undeclared:
842 block_frame.identifiers.add_special('self')
843 self.writeline('l_self = TemplateReference(context)')
844 if 'super' in undeclared:
845 block_frame.identifiers.add_special('super')
846 self.writeline('l_super = context.super(%r, '
847 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200848 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200849 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200850 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200851 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200852
Armin Ronacher75cfb862008-04-11 13:47:22 +0200853 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200854 for x in self.blocks),
855 extra=1)
856
857 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200858 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
859 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200860
Armin Ronachere791c2a2008-04-07 18:39:54 +0200861 def visit_Block(self, node, frame):
862 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200863 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200864 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200865 # if we know that we are a child template, there is no need to
866 # check if we are one
867 if self.has_known_extends:
868 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200869 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200870 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200871 self.indent()
872 level += 1
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100873 context = node.scoped and 'context.derived(locals())' or 'context'
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100874 self.writeline('for event in context.blocks[%r][0](%s):' % (
875 node.name, context), node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200876 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200877 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200878 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200879
880 def visit_Extends(self, node, frame):
881 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200882 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200883 self.fail('cannot use extend from a non top-level scope',
884 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200885
Armin Ronacher7fb38972008-04-11 13:54:28 +0200886 # if the number of extends statements in general is zero so
887 # far, we don't have to add a check if something extended
888 # the template before this one.
889 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200890
Armin Ronacher7fb38972008-04-11 13:54:28 +0200891 # if we have a known extends we just add a template runtime
892 # error into the generated code. We could catch that at compile
893 # time too, but i welcome it not to confuse users by throwing the
894 # same error at different times just "because we can".
895 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200896 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200897 self.indent()
898 self.writeline('raise TemplateRuntimeError(%r)' %
899 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200900 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200901
Armin Ronacher7fb38972008-04-11 13:54:28 +0200902 # if we have a known extends already we don't need that code here
903 # as we know that the template execution will end here.
904 if self.has_known_extends:
905 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200906
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200907 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200908 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200909 self.write(', %r)' % self.name)
910 self.writeline('for name, parent_block in parent_template.'
Armin Ronacher0d242be2010-02-10 01:35:13 +0100911 'blocks.%s():' % dict_item_iter)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200912 self.indent()
913 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200914 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200915 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200916
917 # if this extends statement was in the root level we can take
918 # advantage of that information and simplify the generated code
919 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200920 if frame.rootlevel:
921 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200922
Armin Ronacher7fb38972008-04-11 13:54:28 +0200923 # and now we have one more
924 self.extends_so_far += 1
925
Armin Ronacherf059ec12008-04-11 22:21:00 +0200926 def visit_Include(self, node, frame):
927 """Handles includes."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100928 if node.with_context:
929 self.unoptimize_scope(frame)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100930 if node.ignore_missing:
931 self.writeline('try:')
932 self.indent()
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100933
934 func_name = 'get_or_select_template'
935 if isinstance(node.template, nodes.Const):
936 if isinstance(node.template.value, basestring):
937 func_name = 'get_template'
938 elif isinstance(node.template.value, (tuple, list)):
939 func_name = 'select_template'
940 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
941 func_name = 'select_template'
942
943 self.writeline('template = environment.%s(' % func_name, node)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100944 self.visit(node.template, frame)
945 self.write(', %r)' % self.name)
946 if node.ignore_missing:
947 self.outdent()
948 self.writeline('except TemplateNotFound:')
949 self.indent()
950 self.writeline('pass')
951 self.outdent()
952 self.writeline('else:')
953 self.indent()
954
Armin Ronacherea847c52008-05-02 20:04:32 +0200955 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200956 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200957 'template.new_context(context.parent, True, '
958 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200959 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100960 self.writeline('for event in template.module._body_stream:')
961
Armin Ronacherf059ec12008-04-11 22:21:00 +0200962 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200963 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200964 self.outdent()
965
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100966 if node.ignore_missing:
967 self.outdent()
968
Armin Ronacher0611e492008-04-25 23:44:14 +0200969 def visit_Import(self, node, frame):
970 """Visit regular imports."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100971 if node.with_context:
972 self.unoptimize_scope(frame)
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200973 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200974 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200975 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200976 self.write('environment.get_template(')
977 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200978 self.write(', %r).' % self.name)
979 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200980 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200981 else:
982 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200983 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200984 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100985 frame.assigned_names.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200986
987 def visit_FromImport(self, node, frame):
988 """Visit named imports."""
989 self.newline(node)
990 self.write('included_template = environment.get_template(')
991 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200992 self.write(', %r).' % self.name)
993 if node.with_context:
994 self.write('make_module(context.parent, True)')
995 else:
996 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200997
998 var_names = []
999 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +02001000 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +02001001 if isinstance(name, tuple):
1002 name, alias = name
1003 else:
1004 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001005 self.writeline('l_%s = getattr(included_template, '
1006 '%r, missing)' % (alias, name))
1007 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +02001008 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001009 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +02001010 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +02001011 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001012 (alias, 'the template %%r (imported on %s) does '
1013 'not export the requested name %s' % (
1014 self.position(node),
1015 repr(name)
1016 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +02001017 self.outdent()
1018 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +02001019 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +02001020 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +02001021 discarded_names.append(alias)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001022 frame.assigned_names.add(alias)
Armin Ronachera78d2762008-05-15 23:18:07 +02001023
1024 if var_names:
1025 if len(var_names) == 1:
1026 name = var_names[0]
1027 self.writeline('context.vars[%r] = l_%s' % (name, name))
1028 else:
1029 self.writeline('context.vars.update({%s})' % ', '.join(
1030 '%r: l_%s' % (name, name) for name in var_names
1031 ))
1032 if discarded_names:
1033 if len(discarded_names) == 1:
1034 self.writeline('context.exported_vars.discard(%r)' %
1035 discarded_names[0])
1036 else:
1037 self.writeline('context.exported_vars.difference_'
1038 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +02001039
Armin Ronachere791c2a2008-04-07 18:39:54 +02001040 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001041 # when calculating the nodes for the inner frame we have to exclude
1042 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001043 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001044 if node.recursive:
1045 loop_frame = self.function_scoping(node, frame, children,
1046 find_special=False)
1047 else:
1048 loop_frame = frame.inner()
1049 loop_frame.inspect(children)
1050
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001051 # try to figure out if we have an extended loop. An extended loop
1052 # is necessary if the loop is in recursive mode if the special loop
1053 # variable is accessed in the body.
1054 extended_loop = node.recursive or 'loop' in \
1055 find_undeclared(node.iter_child_nodes(
1056 only=('body',)), ('loop',))
1057
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001058 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +02001059 # variables at that point. Because loops can be nested but the loop
1060 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001061 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +02001062 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001063
1064 # otherwise we set up a buffer and add a function def
1065 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001066 self.writeline('def loop(reciter, loop_render_func):', node)
1067 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +02001068 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001069 aliases = {}
1070
Armin Ronacherff53c782008-08-13 18:55:50 +02001071 # make sure the loop variable is a special one and raise a template
1072 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +02001073 if extended_loop:
1074 loop_frame.identifiers.add_special('loop')
Armin Ronacherff53c782008-08-13 18:55:50 +02001075 for name in node.find_all(nodes.Name):
1076 if name.ctx == 'store' and name.name == 'loop':
1077 self.fail('Can\'t assign to special loop variable '
1078 'in for-loop target', name.lineno)
1079
Armin Ronacherc9705c22008-04-27 21:28:03 +02001080 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001081 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001082 iteration_indicator = self.temporary_identifier()
1083 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001084
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001085 # Create a fake parent loop if the else or test section of a
1086 # loop is accessing the special loop variable and no parent loop
1087 # exists.
1088 if 'loop' not in aliases and 'loop' in find_undeclared(
1089 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1090 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001091 ("'loop' is undefined. the filter section of a loop as well "
1092 "as the else block doesn't have access to the special 'loop'"
1093 " variable of the current loop. Because there is no parent "
1094 "loop it's undefined. Happened in loop on %s" %
1095 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001096
1097 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001098 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +02001099 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001100
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001101 # if we have an extened loop and a node test, we filter in the
1102 # "outer frame".
1103 if extended_loop and node.test is not None:
1104 self.write('(')
1105 self.visit(node.target, loop_frame)
1106 self.write(' for ')
1107 self.visit(node.target, loop_frame)
1108 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001109 if node.recursive:
1110 self.write('reciter')
1111 else:
1112 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001113 self.write(' if (')
1114 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001115 self.visit(node.test, test_frame)
1116 self.write('))')
1117
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001118 elif node.recursive:
1119 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001120 else:
1121 self.visit(node.iter, loop_frame)
1122
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001123 if node.recursive:
1124 self.write(', recurse=loop_render_func):')
1125 else:
1126 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001127
1128 # tests in not extended loops become a continue
1129 if not extended_loop and node.test is not None:
1130 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +02001131 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +02001132 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001133 self.write(':')
1134 self.indent()
1135 self.writeline('continue')
1136 self.outdent(2)
1137
Armin Ronacherc9705c22008-04-27 21:28:03 +02001138 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001139 self.blockvisit(node.body, loop_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001140 if node.else_:
1141 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001142 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001143
1144 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001145 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001146 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001147 self.blockvisit(node.else_, loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001148 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001149
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001150 # reset the aliases if there are any.
Armin Ronachercebd8382008-12-25 18:33:46 +01001151 if not node.recursive:
1152 self.pop_scope(aliases, loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001153
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001154 # if the node was recursive we have to return the buffer contents
1155 # and start the iteration code
1156 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001157 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001158 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001159 self.start_write(frame, node)
1160 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001161 self.visit(node.iter, frame)
1162 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001163 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001164
Armin Ronachere791c2a2008-04-07 18:39:54 +02001165 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001166 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001167 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001168 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001169 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001170 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001171 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001172 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001173 if node.else_:
1174 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001175 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001176 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001177 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001178
Armin Ronacher8efc5222008-04-08 14:47:40 +02001179 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001180 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001181 self.newline()
1182 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001183 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001184 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001185 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001186 self.write('l_%s = ' % node.name)
1187 self.macro_def(node, macro_frame)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001188 frame.assigned_names.add(node.name)
Armin Ronacher71082072008-04-12 14:19:36 +02001189
1190 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001191 children = node.iter_child_nodes(exclude=('call',))
1192 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001193 self.writeline('caller = ')
1194 self.macro_def(node, call_frame)
1195 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001196 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001197 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001198
1199 def visit_FilterBlock(self, node, frame):
1200 filter_frame = frame.inner()
1201 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacher673aa882008-10-04 18:06:57 +02001202 aliases = self.push_scope(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001203 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001204 self.buffer(filter_frame)
Armin Ronacherf40c8842008-09-17 18:51:26 +02001205 self.blockvisit(node.body, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001206 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001207 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001208 self.end_write(frame)
Armin Ronacher673aa882008-10-04 18:06:57 +02001209 self.pop_scope(aliases, filter_frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001210
Armin Ronachere791c2a2008-04-07 18:39:54 +02001211 def visit_ExprStmt(self, node, frame):
1212 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001213 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001214
1215 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001216 # if we have a known extends statement, we don't output anything
Armin Ronacher79668952008-09-23 22:52:46 +02001217 # if we are in a require_output_check section
1218 if self.has_known_extends and frame.require_output_check:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001219 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001220
Armin Ronacher665bfb82008-07-14 13:41:46 +02001221 if self.environment.finalize:
1222 finalize = lambda x: unicode(self.environment.finalize(x))
1223 else:
1224 finalize = unicode
1225
Armin Ronacher79668952008-09-23 22:52:46 +02001226 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001227 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001228 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001229 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001230 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001231 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001232
Armin Ronachere791c2a2008-04-07 18:39:54 +02001233 # try to evaluate as many chunks as possible into a static
1234 # string at compile time.
1235 body = []
1236 for child in node.nodes:
1237 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001238 const = child.as_const(frame.eval_ctx)
Armin Ronacher9cf95912008-05-24 19:54:43 +02001239 except nodes.Impossible:
1240 body.append(child)
1241 continue
Armin Ronacher8346bd72010-03-14 19:43:47 +01001242 # the frame can't be volatile here, becaus otherwise the
1243 # as_const() function would raise an Impossible exception
1244 # at that point.
Armin Ronacher9cf95912008-05-24 19:54:43 +02001245 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001246 if frame.eval_ctx.autoescape:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001247 if hasattr(const, '__html__'):
1248 const = const.__html__()
1249 else:
1250 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001251 const = finalize(const)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001252 except:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001253 # if something goes wrong here we evaluate the node
1254 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001255 body.append(child)
1256 continue
1257 if body and isinstance(body[-1], list):
1258 body[-1].append(const)
1259 else:
1260 body.append([const])
1261
Armin Ronachered1e0d42008-05-18 20:25:28 +02001262 # if we have less than 3 nodes or a buffer we yield or extend/append
1263 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001264 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001265 # for one item we append, for more we extend
1266 if len(body) == 1:
1267 self.writeline('%s.append(' % frame.buffer)
1268 else:
1269 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001270 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001271 for item in body:
1272 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001273 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001274 if frame.buffer is None:
1275 self.writeline('yield ' + val)
1276 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001277 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001278 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001279 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001280 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001281 else:
1282 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001283 close = 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001284 if frame.eval_ctx.volatile:
1285 self.write('(context.eval_ctx.autoescape and'
1286 ' escape or to_string)(')
1287 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001288 self.write('escape(')
1289 else:
Armin Ronacherbd357722009-08-05 20:25:06 +02001290 self.write('to_string(')
Armin Ronacherd1342312008-04-28 12:20:12 +02001291 if self.environment.finalize is not None:
1292 self.write('environment.finalize(')
1293 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001294 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001295 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001296 if frame.buffer is not None:
1297 self.write(', ')
1298 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001299 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001300 self.outdent()
1301 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001302
1303 # otherwise we create a format string as this is faster in that case
1304 else:
1305 format = []
1306 arguments = []
1307 for item in body:
1308 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001309 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001310 else:
1311 format.append('%s')
1312 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001313 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001314 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001315 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001316 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001317 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001318 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001319 close = 0
Armin Ronacher8346bd72010-03-14 19:43:47 +01001320 if frame.eval_ctx.volatile:
1321 self.write('(context.eval_ctx.autoescape and'
1322 ' escape or to_string)(')
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001323 close += 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001324 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001325 self.write('escape(')
1326 close += 1
1327 if self.environment.finalize is not None:
1328 self.write('environment.finalize(')
1329 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001330 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001331 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001332 self.outdent()
1333 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001334
Armin Ronacher7fb38972008-04-11 13:54:28 +02001335 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001336 self.outdent()
1337
Armin Ronacher8efc5222008-04-08 14:47:40 +02001338 def visit_Assign(self, node, frame):
1339 self.newline(node)
1340 # toplevel assignments however go into the local namespace and
1341 # the current template's context. We create a copy of the frame
1342 # here and add a set so that the Name visitor can add the assigned
1343 # names here.
1344 if frame.toplevel:
1345 assignment_frame = frame.copy()
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001346 assignment_frame.toplevel_assignments = set()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001347 else:
1348 assignment_frame = frame
1349 self.visit(node.target, assignment_frame)
1350 self.write(' = ')
1351 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001352
1353 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001354 if frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001355 public_names = [x for x in assignment_frame.toplevel_assignments
Armin Ronacher903d1682008-05-23 00:51:58 +02001356 if not x.startswith('_')]
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001357 if len(assignment_frame.toplevel_assignments) == 1:
Armin Ronacherbd357722009-08-05 20:25:06 +02001358 name = next(iter(assignment_frame.toplevel_assignments))
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001359 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001360 else:
1361 self.writeline('context.vars.update({')
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001362 for idx, name in enumerate(assignment_frame.toplevel_assignments):
Armin Ronacher69e12db2008-05-12 09:00:03 +02001363 if idx:
1364 self.write(', ')
1365 self.write('%r: l_%s' % (name, name))
1366 self.write('})')
1367 if public_names:
1368 if len(public_names) == 1:
1369 self.writeline('context.exported_vars.add(%r)' %
1370 public_names[0])
1371 else:
1372 self.writeline('context.exported_vars.update((%s))' %
1373 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001374
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001375 # -- Expression Visitors
1376
Armin Ronachere791c2a2008-04-07 18:39:54 +02001377 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001378 if node.ctx == 'store' and frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001379 frame.toplevel_assignments.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001380 self.write('l_' + node.name)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001381 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001382
1383 def visit_Const(self, node, frame):
1384 val = node.value
1385 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001386 self.write(str(val))
1387 else:
1388 self.write(repr(val))
1389
Armin Ronacher5411ce72008-05-25 11:36:22 +02001390 def visit_TemplateData(self, node, frame):
Armin Ronacherffaa2e72010-05-29 20:57:16 +02001391 try:
1392 self.write(repr(node.as_const(frame.eval_ctx)))
1393 except nodes.Impossible:
1394 self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)'
1395 % node.data)
Armin Ronacher5411ce72008-05-25 11:36:22 +02001396
Armin Ronacher8efc5222008-04-08 14:47:40 +02001397 def visit_Tuple(self, node, frame):
1398 self.write('(')
1399 idx = -1
1400 for idx, item in enumerate(node.items):
1401 if idx:
1402 self.write(', ')
1403 self.visit(item, frame)
1404 self.write(idx == 0 and ',)' or ')')
1405
Armin Ronacher8edbe492008-04-10 20:43:43 +02001406 def visit_List(self, node, frame):
1407 self.write('[')
1408 for idx, item in enumerate(node.items):
1409 if idx:
1410 self.write(', ')
1411 self.visit(item, frame)
1412 self.write(']')
1413
1414 def visit_Dict(self, node, frame):
1415 self.write('{')
1416 for idx, item in enumerate(node.items):
1417 if idx:
1418 self.write(', ')
1419 self.visit(item.key, frame)
1420 self.write(': ')
1421 self.visit(item.value, frame)
1422 self.write('}')
1423
Armin Ronachere791c2a2008-04-07 18:39:54 +02001424 def binop(operator):
1425 def visitor(self, node, frame):
1426 self.write('(')
1427 self.visit(node.left, frame)
1428 self.write(' %s ' % operator)
1429 self.visit(node.right, frame)
1430 self.write(')')
1431 return visitor
1432
1433 def uaop(operator):
1434 def visitor(self, node, frame):
1435 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001436 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001437 self.write(')')
1438 return visitor
1439
1440 visit_Add = binop('+')
1441 visit_Sub = binop('-')
1442 visit_Mul = binop('*')
1443 visit_Div = binop('/')
1444 visit_FloorDiv = binop('//')
1445 visit_Pow = binop('**')
1446 visit_Mod = binop('%')
1447 visit_And = binop('and')
1448 visit_Or = binop('or')
1449 visit_Pos = uaop('+')
1450 visit_Neg = uaop('-')
1451 visit_Not = uaop('not ')
1452 del binop, uaop
1453
Armin Ronacherd1342312008-04-28 12:20:12 +02001454 def visit_Concat(self, node, frame):
Armin Ronacher8346bd72010-03-14 19:43:47 +01001455 if frame.eval_ctx.volatile:
1456 func_name = '(context.eval_ctx.volatile and' \
1457 ' markup_join or unicode_join)'
1458 elif frame.eval_ctx.autoescape:
1459 func_name = 'markup_join'
1460 else:
1461 func_name = 'unicode_join'
1462 self.write('%s((' % func_name)
Armin Ronacherd1342312008-04-28 12:20:12 +02001463 for arg in node.nodes:
1464 self.visit(arg, frame)
1465 self.write(', ')
1466 self.write('))')
1467
Armin Ronachere791c2a2008-04-07 18:39:54 +02001468 def visit_Compare(self, node, frame):
1469 self.visit(node.expr, frame)
1470 for op in node.ops:
1471 self.visit(op, frame)
1472
1473 def visit_Operand(self, node, frame):
1474 self.write(' %s ' % operators[node.op])
1475 self.visit(node.expr, frame)
1476
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001477 def visit_Getattr(self, node, frame):
1478 self.write('environment.getattr(')
1479 self.visit(node.node, frame)
1480 self.write(', %r)' % node.attr)
1481
1482 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001483 # slices bypass the environment getitem method.
1484 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001485 self.visit(node.node, frame)
1486 self.write('[')
1487 self.visit(node.arg, frame)
1488 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001489 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001490 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001491 self.visit(node.node, frame)
1492 self.write(', ')
1493 self.visit(node.arg, frame)
1494 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001495
1496 def visit_Slice(self, node, frame):
1497 if node.start is not None:
1498 self.visit(node.start, frame)
1499 self.write(':')
1500 if node.stop is not None:
1501 self.visit(node.stop, frame)
1502 if node.step is not None:
1503 self.write(':')
1504 self.visit(node.step, frame)
1505
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001506 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001507 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001508 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001509 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001510 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001511 if getattr(func, 'contextfilter', False):
1512 self.write('context, ')
Armin Ronacher8346bd72010-03-14 19:43:47 +01001513 elif getattr(func, 'evalcontextfilter', False):
1514 self.write('context.eval_ctx, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001515 elif getattr(func, 'environmentfilter', False):
1516 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001517
1518 # if the filter node is None we are inside a filter block
1519 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001520 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001521 self.visit(node.node, frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001522 elif frame.eval_ctx.volatile:
1523 self.write('(context.eval_ctx.autoescape and'
1524 ' Markup(concat(%s)) or concat(%s))' %
1525 (frame.buffer, frame.buffer))
1526 elif frame.eval_ctx.autoescape:
Armin Ronacher3da90312008-05-23 16:37:28 +02001527 self.write('Markup(concat(%s))' % frame.buffer)
1528 else:
1529 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001530 self.signature(node, frame)
1531 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001532
1533 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001534 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001535 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001536 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001537 self.visit(node.node, frame)
1538 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001539 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001540
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001541 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001542 def write_expr2():
1543 if node.expr2 is not None:
1544 return self.visit(node.expr2, frame)
1545 self.write('environment.undefined(%r)' % ('the inline if-'
1546 'expression on %s evaluated to false and '
1547 'no else section was defined.' % self.position(node)))
1548
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001549 if not have_condexpr:
1550 self.write('((')
1551 self.visit(node.test, frame)
1552 self.write(') and (')
1553 self.visit(node.expr1, frame)
1554 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001555 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001556 self.write(',))[0]')
1557 else:
1558 self.write('(')
1559 self.visit(node.expr1, frame)
1560 self.write(' if ')
1561 self.visit(node.test, frame)
1562 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001563 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001564 self.write(')')
1565
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001566 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001567 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001568 self.write('environment.call(context, ')
1569 else:
1570 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001571 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001572 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001573 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001574 self.write(')')
1575
1576 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001577 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001578 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001579
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001580 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001581
1582 def visit_MarkSafe(self, node, frame):
1583 self.write('Markup(')
1584 self.visit(node.expr, frame)
1585 self.write(')')
1586
Armin Ronacher4da90342010-05-29 17:35:10 +02001587 def visit_MarkSafeIfAutoescape(self, node, frame):
1588 self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1589 self.visit(node.expr, frame)
1590 self.write(')')
1591
Armin Ronachered1e0d42008-05-18 20:25:28 +02001592 def visit_EnvironmentAttribute(self, node, frame):
1593 self.write('environment.' + node.name)
1594
1595 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001596 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001597
1598 def visit_ImportedName(self, node, frame):
1599 self.write(self.import_aliases[node.importname])
1600
1601 def visit_InternalName(self, node, frame):
1602 self.write(node.name)
1603
Armin Ronacher6df604e2008-05-23 22:18:38 +02001604 def visit_ContextReference(self, node, frame):
1605 self.write('context')
1606
Armin Ronachered1e0d42008-05-18 20:25:28 +02001607 def visit_Continue(self, node, frame):
1608 self.writeline('continue', node)
1609
1610 def visit_Break(self, node, frame):
1611 self.writeline('break', node)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001612
1613 def visit_Scope(self, node, frame):
1614 scope_frame = frame.inner()
1615 scope_frame.inspect(node.iter_child_nodes())
1616 aliases = self.push_scope(scope_frame)
1617 self.pull_locals(scope_frame)
1618 self.blockvisit(node.body, scope_frame)
1619 self.pop_scope(aliases, scope_frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001620
1621 def visit_EvalContextModifier(self, node, frame):
1622 for keyword in node.options:
1623 self.writeline('context.eval_ctx.%s = ' % keyword.key)
1624 self.visit(keyword.value, frame)
1625 try:
1626 val = keyword.value.as_const(frame.eval_ctx)
1627 except nodes.Impossible:
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001628 frame.eval_ctx.volatile = True
Armin Ronacher8346bd72010-03-14 19:43:47 +01001629 else:
1630 setattr(frame.eval_ctx, keyword.key, val)
1631
1632 def visit_ScopedEvalContextModifier(self, node, frame):
1633 old_ctx_name = self.temporary_identifier()
1634 safed_ctx = frame.eval_ctx.save()
1635 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1636 self.visit_EvalContextModifier(node, frame)
1637 for child in node.body:
1638 self.visit(child, frame)
1639 frame.eval_ctx.revert(safed_ctx)
1640 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)