blob: b21cb3865db61c08c321117b8cf6c8a08fa44f15 [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 Ronacher9573b662010-12-21 00:44:34 +010016from jinja2.visitor import NodeVisitor
Armin Ronachere791c2a2008-04-07 18:39:54 +020017from 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 Ronacherda632622011-03-13 14:33:27 -0400130 def is_declared(self, name):
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
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200134 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200135
Armin Ronacher74230e62009-10-25 12:46:31 +0100136 def copy(self):
137 return deepcopy(self)
138
Armin Ronachere791c2a2008-04-07 18:39:54 +0200139
140class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200141 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200142
Armin Ronacher8346bd72010-03-14 19:43:47 +0100143 def __init__(self, eval_ctx, parent=None):
144 self.eval_ctx = eval_ctx
Armin Ronachere791c2a2008-04-07 18:39:54 +0200145 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200146
Armin Ronacher75cfb862008-04-11 13:47:22 +0200147 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200148 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200149
Armin Ronacher75cfb862008-04-11 13:47:22 +0200150 # the root frame is basically just the outermost frame, so no if
151 # conditions. This information is used to optimize inheritance
152 # situations.
153 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200154
Armin Ronacher79668952008-09-23 22:52:46 +0200155 # in some dynamic inheritance situations the compiler needs to add
156 # write tests around output statements.
157 self.require_output_check = parent and parent.require_output_check
Armin Ronacherf40c8842008-09-17 18:51:26 +0200158
Armin Ronacherfed44b52008-04-13 19:42:53 +0200159 # inside some tags we are using a buffer rather than yield statements.
160 # this for example affects {% filter %} or {% macro %}. If a frame
161 # is buffered this variable points to the name of the list used as
162 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200163 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200164
Armin Ronacherfed44b52008-04-13 19:42:53 +0200165 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200166 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200167
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100168 # a set of actually assigned names
169 self.assigned_names = set()
170
Armin Ronacherfed44b52008-04-13 19:42:53 +0200171 # the parent of this frame
172 self.parent = parent
173
Armin Ronachere791c2a2008-04-07 18:39:54 +0200174 if parent is not None:
175 self.identifiers.declared.update(
176 parent.identifiers.declared |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200177 parent.identifiers.declared_parameter |
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100178 parent.assigned_names
Armin Ronachere791c2a2008-04-07 18:39:54 +0200179 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200180 self.identifiers.outer_undeclared.update(
181 parent.identifiers.undeclared -
182 self.identifiers.declared
183 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200184 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200185
Armin Ronacher8efc5222008-04-08 14:47:40 +0200186 def copy(self):
187 """Create a copy of the current one."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200188 rv = object.__new__(self.__class__)
189 rv.__dict__.update(self.__dict__)
190 rv.identifiers = object.__new__(self.identifiers.__class__)
191 rv.identifiers.__dict__.update(self.identifiers.__dict__)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200192 return rv
193
Armin Ronacherda632622011-03-13 14:33:27 -0400194 def inspect(self, nodes):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200195 """Walk the node and check for identifiers. If the scope is hard (eg:
196 enforce on a python level) overrides from outer scopes are tracked
197 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200198 """
Armin Ronacherda632622011-03-13 14:33:27 -0400199 visitor = FrameIdentifierVisitor(self.identifiers)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200200 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200201 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200202
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100203 def find_shadowed(self, extra=()):
204 """Find all the shadowed names. extra is an iterable of variables
205 that may be defined with `add_special` which may occour scoped.
206 """
207 i = self.identifiers
208 return (i.declared | i.outer_undeclared) & \
209 (i.declared_locally | i.declared_parameter) | \
210 set(x for x in extra if i.is_declared(x))
211
Armin Ronachere791c2a2008-04-07 18:39:54 +0200212 def inner(self):
213 """Return an inner frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100214 return Frame(self.eval_ctx, self)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200215
Armin Ronacher75cfb862008-04-11 13:47:22 +0200216 def soft(self):
217 """Return a soft frame. A soft frame may not be modified as
218 standalone thing as it shares the resources with the frame it
219 was created of, but it's not a rootlevel frame any longer.
220 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200221 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200222 rv.rootlevel = False
223 return rv
224
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200225 __copy__ = copy
226
Armin Ronachere791c2a2008-04-07 18:39:54 +0200227
Armin Ronacherc9705c22008-04-27 21:28:03 +0200228class VisitorExit(RuntimeError):
229 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
230
231
232class DependencyFinderVisitor(NodeVisitor):
233 """A visitor that collects filter and test calls."""
234
235 def __init__(self):
236 self.filters = set()
237 self.tests = set()
238
239 def visit_Filter(self, node):
240 self.generic_visit(node)
241 self.filters.add(node.name)
242
243 def visit_Test(self, node):
244 self.generic_visit(node)
245 self.tests.add(node.name)
246
247 def visit_Block(self, node):
248 """Stop visiting at blocks."""
249
250
251class UndeclaredNameVisitor(NodeVisitor):
252 """A visitor that checks if a name is accessed without being
253 declared. This is different from the frame visitor as it will
254 not stop at closure frames.
255 """
256
257 def __init__(self, names):
258 self.names = set(names)
259 self.undeclared = set()
260
261 def visit_Name(self, node):
262 if node.ctx == 'load' and node.name in self.names:
263 self.undeclared.add(node.name)
264 if self.undeclared == self.names:
265 raise VisitorExit()
266 else:
267 self.names.discard(node.name)
268
269 def visit_Block(self, node):
270 """Stop visiting a blocks."""
271
272
Armin Ronachere791c2a2008-04-07 18:39:54 +0200273class FrameIdentifierVisitor(NodeVisitor):
274 """A visitor for `Frame.inspect`."""
275
Armin Ronacherda632622011-03-13 14:33:27 -0400276 def __init__(self, identifiers):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200277 self.identifiers = identifiers
278
Armin Ronacherc9705c22008-04-27 21:28:03 +0200279 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200280 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200281 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200282 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200283 elif node.ctx == 'param':
284 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200285 elif node.ctx == 'load' and not \
Armin Ronacherda632622011-03-13 14:33:27 -0400286 self.identifiers.is_declared(node.name):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200287 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200288
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200289 def visit_If(self, node):
290 self.visit(node.test)
Armin Ronacher74230e62009-10-25 12:46:31 +0100291 real_identifiers = self.identifiers
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200292
Armin Ronacher8a672512010-04-05 18:43:07 +0200293 old_names = real_identifiers.declared_locally | \
Armin Ronacher74230e62009-10-25 12:46:31 +0100294 real_identifiers.declared_parameter
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200295
Armin Ronacher74230e62009-10-25 12:46:31 +0100296 def inner_visit(nodes):
Armin Ronacher1965e312009-10-25 13:03:08 +0100297 if not nodes:
298 return set()
Armin Ronacher74230e62009-10-25 12:46:31 +0100299 self.identifiers = real_identifiers.copy()
300 for subnode in nodes:
301 self.visit(subnode)
302 rv = self.identifiers.declared_locally - old_names
303 # we have to remember the undeclared variables of this branch
304 # because we will have to pull them.
305 real_identifiers.undeclared.update(self.identifiers.undeclared)
306 self.identifiers = real_identifiers
307 return rv
308
309 body = inner_visit(node.body)
310 else_ = inner_visit(node.else_ or ())
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200311
312 # the differences between the two branches are also pulled as
313 # undeclared variables
Armin Ronacher8a672512010-04-05 18:43:07 +0200314 real_identifiers.undeclared.update(body.symmetric_difference(else_) -
315 real_identifiers.declared)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200316
Armin Ronacher74230e62009-10-25 12:46:31 +0100317 # remember those that are declared.
318 real_identifiers.declared_locally.update(body | else_)
Armin Ronacherf1c421d2009-09-17 00:48:41 +0200319
Armin Ronacherc9705c22008-04-27 21:28:03 +0200320 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200321 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200322
Armin Ronacherc9705c22008-04-27 21:28:03 +0200323 def visit_Import(self, node):
324 self.generic_visit(node)
325 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200326
Armin Ronacherc9705c22008-04-27 21:28:03 +0200327 def visit_FromImport(self, node):
328 self.generic_visit(node)
329 for name in node.names:
330 if isinstance(name, tuple):
331 self.identifiers.declared_locally.add(name[1])
332 else:
333 self.identifiers.declared_locally.add(name)
334
335 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200336 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200337 self.visit(node.node)
338 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200339
Armin Ronacherc9705c22008-04-27 21:28:03 +0200340 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200341 """Visiting stops at for blocks. However the block sequence
342 is visited as part of the outer scope.
343 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200344 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200345
Armin Ronacherc9705c22008-04-27 21:28:03 +0200346 def visit_CallBlock(self, node):
Armin Ronacheref189442010-01-14 01:26:40 +0100347 self.visit(node.call)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200348
349 def visit_FilterBlock(self, node):
350 self.visit(node.filter)
351
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100352 def visit_Scope(self, node):
353 """Stop visiting at scopes."""
354
Armin Ronacherc9705c22008-04-27 21:28:03 +0200355 def visit_Block(self, node):
356 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200357
358
Armin Ronacher75cfb862008-04-11 13:47:22 +0200359class CompilerExit(Exception):
360 """Raised if the compiler encountered a situation where it just
361 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200362 raises such an exception is not further processed.
363 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200364
365
Armin Ronachere791c2a2008-04-07 18:39:54 +0200366class CodeGenerator(NodeVisitor):
367
Armin Ronacher64b08a02010-03-12 03:17:41 +0100368 def __init__(self, environment, name, filename, stream=None,
369 defer_init=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200370 if stream is None:
371 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200372 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200373 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200374 self.filename = filename
375 self.stream = stream
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100376 self.created_block_context = False
Armin Ronacher64b08a02010-03-12 03:17:41 +0100377 self.defer_init = defer_init
Armin Ronacherfed44b52008-04-13 19:42:53 +0200378
Armin Ronacher023b5e92008-05-08 11:03:10 +0200379 # aliases for imports
380 self.import_aliases = {}
381
Armin Ronacherfed44b52008-04-13 19:42:53 +0200382 # a registry for all blocks. Because blocks are moved out
383 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200384 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200385
386 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200387 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200388
389 # some templates have a rootlevel extends. In this case we
390 # can safely assume that we're a child template and do some
391 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200392 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200393
Armin Ronacherba3757b2008-04-16 19:43:16 +0200394 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200395 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200396
Armin Ronacherb9e78752008-05-10 23:36:28 +0200397 # registry of all filters and tests (global, not block local)
398 self.tests = {}
399 self.filters = {}
400
Armin Ronacherba3757b2008-04-16 19:43:16 +0200401 # the debug information
402 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200403 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200404
Armin Ronacherfed44b52008-04-13 19:42:53 +0200405 # the number of new lines before the next write()
406 self._new_lines = 0
407
408 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200409 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200410
411 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200412 self._first_write = True
413
Armin Ronacherfed44b52008-04-13 19:42:53 +0200414 # used by the `temporary_identifier` method to get new
415 # unique, temporary identifier
416 self._last_identifier = 0
417
418 # the current indentation
419 self._indentation = 0
420
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200421 # -- Various compilation helpers
422
Armin Ronachere2244882008-05-19 09:25:57 +0200423 def fail(self, msg, lineno):
Armin Ronacher8346bd72010-03-14 19:43:47 +0100424 """Fail with a :exc:`TemplateAssertionError`."""
Armin Ronachere2244882008-05-19 09:25:57 +0200425 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
426
Armin Ronachere791c2a2008-04-07 18:39:54 +0200427 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200428 """Get a new unique identifier."""
429 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200430 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200431
Armin Ronachered1e0d42008-05-18 20:25:28 +0200432 def buffer(self, frame):
433 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200434 frame.buffer = self.temporary_identifier()
435 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200436
437 def return_buffer_contents(self, frame):
438 """Return the buffer contents of the frame."""
Armin Ronacher8346bd72010-03-14 19:43:47 +0100439 if frame.eval_ctx.volatile:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100440 self.writeline('if context.eval_ctx.autoescape:')
441 self.indent()
442 self.writeline('return Markup(concat(%s))' % frame.buffer)
443 self.outdent()
444 self.writeline('else:')
445 self.indent()
446 self.writeline('return concat(%s)' % frame.buffer)
447 self.outdent()
Armin Ronacher8346bd72010-03-14 19:43:47 +0100448 elif frame.eval_ctx.autoescape:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100449 self.writeline('return Markup(concat(%s))' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200450 else:
Armin Ronacherf3c66d92010-03-15 00:48:46 +0100451 self.writeline('return concat(%s)' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200452
Armin Ronachere791c2a2008-04-07 18:39:54 +0200453 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200454 """Indent by one."""
455 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200456
Armin Ronacher8efc5222008-04-08 14:47:40 +0200457 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200458 """Outdent by step."""
459 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200460
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200461 def start_write(self, frame, node=None):
462 """Yield or write into the frame buffer."""
463 if frame.buffer is None:
464 self.writeline('yield ', node)
465 else:
466 self.writeline('%s.append(' % frame.buffer, node)
467
468 def end_write(self, frame):
469 """End the writing process started by `start_write`."""
470 if frame.buffer is not None:
471 self.write(')')
472
473 def simple_write(self, s, frame, node=None):
474 """Simple shortcut for start_write + write + end_write."""
475 self.start_write(frame, node)
476 self.write(s)
477 self.end_write(frame)
478
Armin Ronacherf40c8842008-09-17 18:51:26 +0200479 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200480 """Visit a list of nodes as block in a frame. If the current frame
481 is no buffer a dummy ``if 0: yield None`` is written automatically
482 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200483 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200484 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200485 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200486 else:
487 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200488 try:
489 for node in nodes:
490 self.visit(node, frame)
491 except CompilerExit:
492 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200493
494 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200495 """Write a string into the output stream."""
496 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200497 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200498 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200499 self.code_lineno += self._new_lines
500 if self._write_debug_info is not None:
501 self.debug_info.append((self._write_debug_info,
502 self.code_lineno))
503 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200504 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200505 self.stream.write(' ' * self._indentation)
506 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200507 self.stream.write(x)
508
509 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200510 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200511 self.newline(node, extra)
512 self.write(x)
513
514 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200515 """Add one or more newlines before the next write."""
516 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200517 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200518 self._write_debug_info = node.lineno
519 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200520
Armin Ronacherfd310492008-05-25 00:16:51 +0200521 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200522 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200523 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200524 arguments may not include python keywords otherwise a syntax
525 error could occour. The extra keyword arguments should be given
526 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200527 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200528 # if any of the given keyword arguments is a python keyword
529 # we have to make sure that no invalid call is created.
530 kwarg_workaround = False
531 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200532 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200533 kwarg_workaround = True
534 break
535
Armin Ronacher8efc5222008-04-08 14:47:40 +0200536 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200537 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200538 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200539
540 if not kwarg_workaround:
541 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200542 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200543 self.visit(kwarg, frame)
544 if extra_kwargs is not None:
545 for key, value in extra_kwargs.iteritems():
Armin Ronacherfd310492008-05-25 00:16:51 +0200546 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200547 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200548 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200549 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200550
551 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200552 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200553 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200554 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200555 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200556 for kwarg in node.kwargs:
557 self.write('%r: ' % kwarg.key)
558 self.visit(kwarg.value, frame)
559 self.write(', ')
560 if extra_kwargs is not None:
561 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200562 self.write('%r: %s, ' % (key, value))
563 if node.dyn_kwargs is not None:
564 self.write('}, **')
565 self.visit(node.dyn_kwargs, frame)
566 self.write(')')
567 else:
568 self.write('}')
569
570 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200571 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200572 self.visit(node.dyn_kwargs, frame)
573
Armin Ronacherc9705c22008-04-27 21:28:03 +0200574 def pull_locals(self, frame):
575 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200576 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200577 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200578
579 def pull_dependencies(self, nodes):
580 """Pull all the dependencies."""
581 visitor = DependencyFinderVisitor()
582 for node in nodes:
583 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200584 for dependency in 'filters', 'tests':
585 mapping = getattr(self, dependency)
586 for name in getattr(visitor, dependency):
587 if name not in mapping:
588 mapping[name] = self.temporary_identifier()
589 self.writeline('%s = environment.%s[%r]' %
590 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200591
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100592 def unoptimize_scope(self, frame):
593 """Disable Python optimizations for the frame."""
594 # XXX: this is not that nice but it has no real overhead. It
595 # mainly works because python finds the locals before dead code
596 # is removed. If that breaks we have to add a dummy function
597 # that just accepts the arguments and does nothing.
598 if frame.identifiers.declared:
Armin Ronacher821a4232010-02-17 07:59:38 +0100599 self.writeline('%sdummy(%s)' % (
600 unoptimize_before_dead_code and 'if 0: ' or '',
601 ', '.join('l_' + name for name in frame.identifiers.declared)
602 ))
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100603
Armin Ronacher673aa882008-10-04 18:06:57 +0200604 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200605 """This function returns all the shadowed variables in a dict
606 in the form name: alias and will write the required assignments
607 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200608
Armin Ronacher673aa882008-10-04 18:06:57 +0200609 This also predefines locally declared variables from the loop
610 body because under some circumstances it may be the case that
611
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100612 `extra_vars` is passed to `Frame.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200613 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200614 aliases = {}
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100615 for name in frame.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200616 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200617 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200618 to_declare = set()
619 for name in frame.identifiers.declared_locally:
620 if name not in aliases:
621 to_declare.add('l_' + name)
622 if to_declare:
623 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200624 return aliases
625
Armin Ronacher673aa882008-10-04 18:06:57 +0200626 def pop_scope(self, aliases, frame):
627 """Restore all aliases and delete unused variables."""
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200628 for name, alias in aliases.iteritems():
629 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200630 to_delete = set()
631 for name in frame.identifiers.declared_locally:
632 if name not in aliases:
633 to_delete.add('l_' + name)
634 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100635 # we cannot use the del statement here because enclosed
636 # scopes can trigger a SyntaxError:
637 # a = 42; b = lambda: a; del a
638 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200639
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200640 def function_scoping(self, node, frame, children=None,
641 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200642 """In Jinja a few statements require the help of anonymous
643 functions. Those are currently macros and call blocks and in
644 the future also recursive loops. As there is currently
645 technical limitation that doesn't allow reading and writing a
646 variable in a scope where the initial value is coming from an
647 outer scope, this function tries to fall back with a common
648 error message. Additionally the frame passed is modified so
649 that the argumetns are collected and callers are looked up.
650
651 This will return the modified frame.
652 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200653 # we have to iterate twice over it, make sure that works
654 if children is None:
655 children = node.iter_child_nodes()
656 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200657 func_frame = frame.inner()
Armin Ronacherda632622011-03-13 14:33:27 -0400658 func_frame.inspect(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200659
660 # variables that are undeclared (accessed before declaration) and
661 # declared locally *and* part of an outside scope raise a template
662 # assertion error. Reason: we can't generate reasonable code from
Armin Ronacher02b42a82009-03-18 00:59:32 +0100663 # it without aliasing all the variables.
664 # this could be fixed in Python 3 where we have the nonlocal
665 # keyword or if we switch to bytecode generation
Armin Ronacher71082072008-04-12 14:19:36 +0200666 overriden_closure_vars = (
667 func_frame.identifiers.undeclared &
668 func_frame.identifiers.declared &
669 (func_frame.identifiers.declared_locally |
670 func_frame.identifiers.declared_parameter)
671 )
672 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200673 self.fail('It\'s not possible to set and access variables '
Armin Ronacherefcc0e52009-09-13 00:22:50 -0700674 'derived from an outer scope! (affects: %s)' %
Armin Ronachere2244882008-05-19 09:25:57 +0200675 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200676
677 # remove variables from a closure from the frame's undeclared
678 # identifiers.
679 func_frame.identifiers.undeclared -= (
680 func_frame.identifiers.undeclared &
681 func_frame.identifiers.declared
682 )
683
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200684 # no special variables for this scope, abort early
685 if not find_special:
686 return func_frame
687
Armin Ronacher963f97d2008-04-25 11:44:59 +0200688 func_frame.accesses_kwargs = False
689 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200690 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200691 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200692
Armin Ronacherc9705c22008-04-27 21:28:03 +0200693 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
694
695 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200696 func_frame.accesses_caller = True
697 func_frame.identifiers.add_special('caller')
698 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200699 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200700 func_frame.accesses_kwargs = True
701 func_frame.identifiers.add_special('kwargs')
702 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200703 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200704 func_frame.accesses_varargs = True
705 func_frame.identifiers.add_special('varargs')
706 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200707 return func_frame
708
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200709 def macro_body(self, node, frame, children=None):
710 """Dump the function def of a macro or call block."""
711 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100712 # macros are delayed, they never require output checks
713 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200714 args = frame.arguments
Armin Ronachereabf3dd2009-09-12 23:48:18 -0700715 # XXX: this is an ugly fix for the loop nesting bug
716 # (tests.test_old_bugs.test_loop_call_bug). This works around
717 # a identifier nesting problem we have in general. It's just more
718 # likely to happen in loops which is why we work around it. The
719 # real solution would be "nonlocal" all the identifiers that are
720 # leaking into a new python frame and might be used both unassigned
721 # and assigned.
722 if 'loop' in frame.identifiers.declared:
Armin Ronacherb4044392009-09-13 15:56:58 -0700723 args = args + ['l_loop=l_loop']
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200724 self.writeline('def macro(%s):' % ', '.join(args), node)
725 self.indent()
726 self.buffer(frame)
727 self.pull_locals(frame)
728 self.blockvisit(node.body, frame)
729 self.return_buffer_contents(frame)
730 self.outdent()
731 return frame
732
733 def macro_def(self, node, frame):
734 """Dump the macro definition for the def created by macro_body."""
735 arg_tuple = ', '.join(repr(x.name) for x in node.args)
736 name = getattr(node, 'name', None)
737 if len(node.args) == 1:
738 arg_tuple += ','
739 self.write('Macro(environment, macro, %r, (%s), (' %
740 (name, arg_tuple))
741 for arg in node.defaults:
742 self.visit(arg, frame)
743 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200744 self.write('), %r, %r, %r)' % (
745 bool(frame.accesses_kwargs),
746 bool(frame.accesses_varargs),
747 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200748 ))
749
Armin Ronacher547d0b62008-07-04 16:35:10 +0200750 def position(self, node):
751 """Return a human readable position for the node."""
752 rv = 'line %d' % node.lineno
753 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100754 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200755 return rv
756
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200757 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200758
759 def visit_Template(self, node, frame=None):
760 assert frame is None, 'no root frame allowed'
Armin Ronacher1da23d12010-04-05 18:11:18 +0200761 eval_ctx = EvalContext(self.environment, self.name)
Armin Ronacher8346bd72010-03-14 19:43:47 +0100762
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200763 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200764 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200765 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher821a4232010-02-17 07:59:38 +0100766 if not unoptimize_before_dead_code:
767 self.writeline('dummy = lambda *x: None')
Armin Ronacher8edbe492008-04-10 20:43:43 +0200768
Armin Ronacher64b08a02010-03-12 03:17:41 +0100769 # if we want a deferred initialization we cannot move the
770 # environment into a local name
771 envenv = not self.defer_init and ', environment=environment' or ''
772
Armin Ronacher75cfb862008-04-11 13:47:22 +0200773 # do we have an extends tag at all? If not, we can save some
774 # overhead by just not processing any inheritance code.
775 have_extends = node.find(nodes.Extends) is not None
776
Armin Ronacher8edbe492008-04-10 20:43:43 +0200777 # find all blocks
778 for block in node.find_all(nodes.Block):
779 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200780 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200781 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200782
Armin Ronacher023b5e92008-05-08 11:03:10 +0200783 # find all imports and import them
784 for import_ in node.find_all(nodes.ImportedName):
785 if import_.importname not in self.import_aliases:
786 imp = import_.importname
787 self.import_aliases[imp] = alias = self.temporary_identifier()
788 if '.' in imp:
789 module, obj = imp.rsplit('.', 1)
790 self.writeline('from %s import %s as %s' %
791 (module, obj, alias))
792 else:
793 self.writeline('import %s as %s' % (imp, alias))
794
795 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200796 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200797
Armin Ronacher8efc5222008-04-08 14:47:40 +0200798 # generate the root render function.
Armin Ronacher64b08a02010-03-12 03:17:41 +0100799 self.writeline('def root(context%s):' % envenv, extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200800
801 # process the root
Armin Ronacher8346bd72010-03-14 19:43:47 +0100802 frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200803 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200804 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200805 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200806 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200807 if have_extends:
808 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200809 if 'self' in find_undeclared(node.body, ('self',)):
810 frame.identifiers.add_special('self')
811 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200812 self.pull_locals(frame)
813 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200814 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200815 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200816
Armin Ronacher8efc5222008-04-08 14:47:40 +0200817 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200818 if have_extends:
819 if not self.has_known_extends:
820 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200821 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200822 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200823 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200824 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200825 self.indent()
826 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200827 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200828
829 # at this point we now have the blocks collected and can visit them too.
830 for name, block in self.blocks.iteritems():
Armin Ronacher8346bd72010-03-14 19:43:47 +0100831 block_frame = Frame(eval_ctx)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200832 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200833 block_frame.block = name
Armin Ronacher64b08a02010-03-12 03:17:41 +0100834 self.writeline('def block_%s(context%s):' % (name, envenv),
835 block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200836 self.indent()
837 undeclared = find_undeclared(block.body, ('self', 'super'))
838 if 'self' in undeclared:
839 block_frame.identifiers.add_special('self')
840 self.writeline('l_self = TemplateReference(context)')
841 if 'super' in undeclared:
842 block_frame.identifiers.add_special('super')
843 self.writeline('l_super = context.super(%r, '
844 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200845 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200846 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200847 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200848 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200849
Armin Ronacher75cfb862008-04-11 13:47:22 +0200850 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200851 for x in self.blocks),
852 extra=1)
853
854 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200855 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
856 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200857
Armin Ronachere791c2a2008-04-07 18:39:54 +0200858 def visit_Block(self, node, frame):
859 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200860 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200861 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200862 # if we know that we are a child template, there is no need to
863 # check if we are one
864 if self.has_known_extends:
865 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200866 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200867 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200868 self.indent()
869 level += 1
Armin Ronacher2f0d6592009-10-26 11:53:27 +0100870 context = node.scoped and 'context.derived(locals())' or 'context'
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100871 self.writeline('for event in context.blocks[%r][0](%s):' % (
872 node.name, context), node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200873 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200874 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200875 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200876
877 def visit_Extends(self, node, frame):
878 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200879 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200880 self.fail('cannot use extend from a non top-level scope',
881 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200882
Armin Ronacher7fb38972008-04-11 13:54:28 +0200883 # if the number of extends statements in general is zero so
884 # far, we don't have to add a check if something extended
885 # the template before this one.
886 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200887
Armin Ronacher7fb38972008-04-11 13:54:28 +0200888 # if we have a known extends we just add a template runtime
889 # error into the generated code. We could catch that at compile
890 # time too, but i welcome it not to confuse users by throwing the
891 # same error at different times just "because we can".
892 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200893 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200894 self.indent()
895 self.writeline('raise TemplateRuntimeError(%r)' %
896 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200897 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200898
Armin Ronacher7fb38972008-04-11 13:54:28 +0200899 # if we have a known extends already we don't need that code here
900 # as we know that the template execution will end here.
901 if self.has_known_extends:
902 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200903
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200904 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200905 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200906 self.write(', %r)' % self.name)
907 self.writeline('for name, parent_block in parent_template.'
Armin Ronacher0d242be2010-02-10 01:35:13 +0100908 'blocks.%s():' % dict_item_iter)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200909 self.indent()
910 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200911 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200912 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200913
914 # if this extends statement was in the root level we can take
915 # advantage of that information and simplify the generated code
916 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200917 if frame.rootlevel:
918 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200919
Armin Ronacher7fb38972008-04-11 13:54:28 +0200920 # and now we have one more
921 self.extends_so_far += 1
922
Armin Ronacherf059ec12008-04-11 22:21:00 +0200923 def visit_Include(self, node, frame):
924 """Handles includes."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100925 if node.with_context:
926 self.unoptimize_scope(frame)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100927 if node.ignore_missing:
928 self.writeline('try:')
929 self.indent()
Armin Ronacher31bbd9e2010-01-14 00:41:30 +0100930
931 func_name = 'get_or_select_template'
932 if isinstance(node.template, nodes.Const):
933 if isinstance(node.template.value, basestring):
934 func_name = 'get_template'
935 elif isinstance(node.template.value, (tuple, list)):
936 func_name = 'select_template'
937 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
938 func_name = 'select_template'
939
940 self.writeline('template = environment.%s(' % func_name, node)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100941 self.visit(node.template, frame)
942 self.write(', %r)' % self.name)
943 if node.ignore_missing:
944 self.outdent()
945 self.writeline('except TemplateNotFound:')
946 self.indent()
947 self.writeline('pass')
948 self.outdent()
949 self.writeline('else:')
950 self.indent()
951
Armin Ronacherea847c52008-05-02 20:04:32 +0200952 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200953 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200954 'template.new_context(context.parent, True, '
955 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200956 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100957 self.writeline('for event in template.module._body_stream:')
958
Armin Ronacherf059ec12008-04-11 22:21:00 +0200959 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200960 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200961 self.outdent()
962
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100963 if node.ignore_missing:
964 self.outdent()
965
Armin Ronacher0611e492008-04-25 23:44:14 +0200966 def visit_Import(self, node, frame):
967 """Visit regular imports."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100968 if node.with_context:
969 self.unoptimize_scope(frame)
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200970 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200971 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200972 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200973 self.write('environment.get_template(')
974 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200975 self.write(', %r).' % self.name)
976 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200977 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200978 else:
979 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200980 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200981 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100982 frame.assigned_names.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200983
984 def visit_FromImport(self, node, frame):
985 """Visit named imports."""
986 self.newline(node)
987 self.write('included_template = environment.get_template(')
988 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200989 self.write(', %r).' % self.name)
990 if node.with_context:
991 self.write('make_module(context.parent, True)')
992 else:
993 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200994
995 var_names = []
996 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200997 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200998 if isinstance(name, tuple):
999 name, alias = name
1000 else:
1001 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001002 self.writeline('l_%s = getattr(included_template, '
1003 '%r, missing)' % (alias, name))
1004 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +02001005 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001006 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +02001007 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +02001008 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001009 (alias, 'the template %%r (imported on %s) does '
1010 'not export the requested name %s' % (
1011 self.position(node),
1012 repr(name)
1013 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +02001014 self.outdent()
1015 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +02001016 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +02001017 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +02001018 discarded_names.append(alias)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001019 frame.assigned_names.add(alias)
Armin Ronachera78d2762008-05-15 23:18:07 +02001020
1021 if var_names:
1022 if len(var_names) == 1:
1023 name = var_names[0]
1024 self.writeline('context.vars[%r] = l_%s' % (name, name))
1025 else:
1026 self.writeline('context.vars.update({%s})' % ', '.join(
1027 '%r: l_%s' % (name, name) for name in var_names
1028 ))
1029 if discarded_names:
1030 if len(discarded_names) == 1:
1031 self.writeline('context.exported_vars.discard(%r)' %
1032 discarded_names[0])
1033 else:
1034 self.writeline('context.exported_vars.difference_'
1035 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +02001036
Armin Ronachere791c2a2008-04-07 18:39:54 +02001037 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001038 # when calculating the nodes for the inner frame we have to exclude
1039 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001040 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001041 if node.recursive:
1042 loop_frame = self.function_scoping(node, frame, children,
1043 find_special=False)
1044 else:
1045 loop_frame = frame.inner()
1046 loop_frame.inspect(children)
1047
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001048 # try to figure out if we have an extended loop. An extended loop
1049 # is necessary if the loop is in recursive mode if the special loop
1050 # variable is accessed in the body.
1051 extended_loop = node.recursive or 'loop' in \
1052 find_undeclared(node.iter_child_nodes(
1053 only=('body',)), ('loop',))
1054
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001055 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +02001056 # variables at that point. Because loops can be nested but the loop
1057 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001058 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +02001059 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001060
1061 # otherwise we set up a buffer and add a function def
1062 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001063 self.writeline('def loop(reciter, loop_render_func):', node)
1064 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +02001065 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001066 aliases = {}
1067
Armin Ronacherff53c782008-08-13 18:55:50 +02001068 # make sure the loop variable is a special one and raise a template
1069 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +02001070 if extended_loop:
1071 loop_frame.identifiers.add_special('loop')
Armin Ronacherff53c782008-08-13 18:55:50 +02001072 for name in node.find_all(nodes.Name):
1073 if name.ctx == 'store' and name.name == 'loop':
1074 self.fail('Can\'t assign to special loop variable '
1075 'in for-loop target', name.lineno)
1076
Armin Ronacherc9705c22008-04-27 21:28:03 +02001077 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001078 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001079 iteration_indicator = self.temporary_identifier()
1080 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001081
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001082 # Create a fake parent loop if the else or test section of a
1083 # loop is accessing the special loop variable and no parent loop
1084 # exists.
1085 if 'loop' not in aliases and 'loop' in find_undeclared(
1086 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1087 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001088 ("'loop' is undefined. the filter section of a loop as well "
Armin Ronacherbc56cd22011-01-15 18:35:45 +01001089 "as the else block don't have access to the special 'loop'"
Armin Ronacher547d0b62008-07-04 16:35:10 +02001090 " variable of the current loop. Because there is no parent "
1091 "loop it's undefined. Happened in loop on %s" %
1092 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001093
1094 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001095 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +02001096 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001097
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001098 # if we have an extened loop and a node test, we filter in the
1099 # "outer frame".
1100 if extended_loop and node.test is not None:
1101 self.write('(')
1102 self.visit(node.target, loop_frame)
1103 self.write(' for ')
1104 self.visit(node.target, loop_frame)
1105 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001106 if node.recursive:
1107 self.write('reciter')
1108 else:
1109 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001110 self.write(' if (')
1111 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001112 self.visit(node.test, test_frame)
1113 self.write('))')
1114
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001115 elif node.recursive:
1116 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001117 else:
1118 self.visit(node.iter, loop_frame)
1119
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001120 if node.recursive:
1121 self.write(', recurse=loop_render_func):')
1122 else:
1123 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001124
1125 # tests in not extended loops become a continue
1126 if not extended_loop and node.test is not None:
1127 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +02001128 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +02001129 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001130 self.write(':')
1131 self.indent()
1132 self.writeline('continue')
1133 self.outdent(2)
1134
Armin Ronacherc9705c22008-04-27 21:28:03 +02001135 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001136 self.blockvisit(node.body, loop_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001137 if node.else_:
1138 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001139 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001140
1141 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001142 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001143 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001144 self.blockvisit(node.else_, loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001145 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001146
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001147 # reset the aliases if there are any.
Armin Ronachercebd8382008-12-25 18:33:46 +01001148 if not node.recursive:
1149 self.pop_scope(aliases, loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001150
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001151 # if the node was recursive we have to return the buffer contents
1152 # and start the iteration code
1153 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001154 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001155 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001156 self.start_write(frame, node)
1157 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001158 self.visit(node.iter, frame)
1159 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001160 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001161
Armin Ronachere791c2a2008-04-07 18:39:54 +02001162 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001163 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001164 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001165 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001166 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001167 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001168 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001169 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001170 if node.else_:
1171 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001172 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001173 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001174 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001175
Armin Ronacher8efc5222008-04-08 14:47:40 +02001176 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001177 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001178 self.newline()
1179 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001180 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001181 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001182 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001183 self.write('l_%s = ' % node.name)
1184 self.macro_def(node, macro_frame)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001185 frame.assigned_names.add(node.name)
Armin Ronacher71082072008-04-12 14:19:36 +02001186
1187 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001188 children = node.iter_child_nodes(exclude=('call',))
1189 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001190 self.writeline('caller = ')
1191 self.macro_def(node, call_frame)
1192 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001193 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001194 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001195
1196 def visit_FilterBlock(self, node, frame):
1197 filter_frame = frame.inner()
1198 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacher673aa882008-10-04 18:06:57 +02001199 aliases = self.push_scope(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001200 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001201 self.buffer(filter_frame)
Armin Ronacherf40c8842008-09-17 18:51:26 +02001202 self.blockvisit(node.body, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001203 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001204 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001205 self.end_write(frame)
Armin Ronacher673aa882008-10-04 18:06:57 +02001206 self.pop_scope(aliases, filter_frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001207
Armin Ronachere791c2a2008-04-07 18:39:54 +02001208 def visit_ExprStmt(self, node, frame):
1209 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001210 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001211
1212 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001213 # if we have a known extends statement, we don't output anything
Armin Ronacher79668952008-09-23 22:52:46 +02001214 # if we are in a require_output_check section
1215 if self.has_known_extends and frame.require_output_check:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001216 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001217
Armin Ronacher665bfb82008-07-14 13:41:46 +02001218 if self.environment.finalize:
1219 finalize = lambda x: unicode(self.environment.finalize(x))
1220 else:
1221 finalize = unicode
1222
Armin Ronacher79668952008-09-23 22:52:46 +02001223 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001224 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001225 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001226 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001227 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001228 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001229
Armin Ronachere791c2a2008-04-07 18:39:54 +02001230 # try to evaluate as many chunks as possible into a static
1231 # string at compile time.
1232 body = []
1233 for child in node.nodes:
1234 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001235 const = child.as_const(frame.eval_ctx)
Armin Ronacher9cf95912008-05-24 19:54:43 +02001236 except nodes.Impossible:
1237 body.append(child)
1238 continue
Armin Ronacher8346bd72010-03-14 19:43:47 +01001239 # the frame can't be volatile here, becaus otherwise the
1240 # as_const() function would raise an Impossible exception
1241 # at that point.
Armin Ronacher9cf95912008-05-24 19:54:43 +02001242 try:
Armin Ronacher8346bd72010-03-14 19:43:47 +01001243 if frame.eval_ctx.autoescape:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001244 if hasattr(const, '__html__'):
1245 const = const.__html__()
1246 else:
1247 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001248 const = finalize(const)
Ian Lewisab014bd2010-10-31 20:29:28 +09001249 except Exception:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001250 # if something goes wrong here we evaluate the node
1251 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001252 body.append(child)
1253 continue
1254 if body and isinstance(body[-1], list):
1255 body[-1].append(const)
1256 else:
1257 body.append([const])
1258
Armin Ronachered1e0d42008-05-18 20:25:28 +02001259 # if we have less than 3 nodes or a buffer we yield or extend/append
1260 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001261 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001262 # for one item we append, for more we extend
1263 if len(body) == 1:
1264 self.writeline('%s.append(' % frame.buffer)
1265 else:
1266 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001267 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001268 for item in body:
1269 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001270 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001271 if frame.buffer is None:
1272 self.writeline('yield ' + val)
1273 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001274 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001275 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001276 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001277 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001278 else:
1279 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001280 close = 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001281 if frame.eval_ctx.volatile:
1282 self.write('(context.eval_ctx.autoescape and'
1283 ' escape or to_string)(')
1284 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001285 self.write('escape(')
1286 else:
Armin Ronacherbd357722009-08-05 20:25:06 +02001287 self.write('to_string(')
Armin Ronacherd1342312008-04-28 12:20:12 +02001288 if self.environment.finalize is not None:
1289 self.write('environment.finalize(')
1290 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001291 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001292 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001293 if frame.buffer is not None:
1294 self.write(', ')
1295 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001296 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001297 self.outdent()
1298 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001299
1300 # otherwise we create a format string as this is faster in that case
1301 else:
1302 format = []
1303 arguments = []
1304 for item in body:
1305 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001306 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001307 else:
1308 format.append('%s')
1309 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001310 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001311 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001312 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001313 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001314 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001315 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001316 close = 0
Armin Ronacher8346bd72010-03-14 19:43:47 +01001317 if frame.eval_ctx.volatile:
1318 self.write('(context.eval_ctx.autoescape and'
1319 ' escape or to_string)(')
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001320 close += 1
Armin Ronacher8346bd72010-03-14 19:43:47 +01001321 elif frame.eval_ctx.autoescape:
Armin Ronacherd1342312008-04-28 12:20:12 +02001322 self.write('escape(')
1323 close += 1
1324 if self.environment.finalize is not None:
1325 self.write('environment.finalize(')
1326 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001327 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001328 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001329 self.outdent()
1330 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001331
Armin Ronacher7fb38972008-04-11 13:54:28 +02001332 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001333 self.outdent()
1334
Armin Ronacher8efc5222008-04-08 14:47:40 +02001335 def visit_Assign(self, node, frame):
1336 self.newline(node)
1337 # toplevel assignments however go into the local namespace and
1338 # the current template's context. We create a copy of the frame
1339 # here and add a set so that the Name visitor can add the assigned
1340 # names here.
1341 if frame.toplevel:
1342 assignment_frame = frame.copy()
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001343 assignment_frame.toplevel_assignments = set()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001344 else:
1345 assignment_frame = frame
1346 self.visit(node.target, assignment_frame)
1347 self.write(' = ')
1348 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001349
1350 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001351 if frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001352 public_names = [x for x in assignment_frame.toplevel_assignments
Armin Ronacher903d1682008-05-23 00:51:58 +02001353 if not x.startswith('_')]
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001354 if len(assignment_frame.toplevel_assignments) == 1:
Armin Ronacherbd357722009-08-05 20:25:06 +02001355 name = next(iter(assignment_frame.toplevel_assignments))
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001356 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001357 else:
1358 self.writeline('context.vars.update({')
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001359 for idx, name in enumerate(assignment_frame.toplevel_assignments):
Armin Ronacher69e12db2008-05-12 09:00:03 +02001360 if idx:
1361 self.write(', ')
1362 self.write('%r: l_%s' % (name, name))
1363 self.write('})')
1364 if public_names:
1365 if len(public_names) == 1:
1366 self.writeline('context.exported_vars.add(%r)' %
1367 public_names[0])
1368 else:
1369 self.writeline('context.exported_vars.update((%s))' %
1370 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001371
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001372 # -- Expression Visitors
1373
Armin Ronachere791c2a2008-04-07 18:39:54 +02001374 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001375 if node.ctx == 'store' and frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001376 frame.toplevel_assignments.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001377 self.write('l_' + node.name)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001378 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001379
1380 def visit_Const(self, node, frame):
1381 val = node.value
1382 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001383 self.write(str(val))
1384 else:
1385 self.write(repr(val))
1386
Armin Ronacher5411ce72008-05-25 11:36:22 +02001387 def visit_TemplateData(self, node, frame):
Armin Ronacherffaa2e72010-05-29 20:57:16 +02001388 try:
1389 self.write(repr(node.as_const(frame.eval_ctx)))
1390 except nodes.Impossible:
1391 self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)'
1392 % node.data)
Armin Ronacher5411ce72008-05-25 11:36:22 +02001393
Armin Ronacher8efc5222008-04-08 14:47:40 +02001394 def visit_Tuple(self, node, frame):
1395 self.write('(')
1396 idx = -1
1397 for idx, item in enumerate(node.items):
1398 if idx:
1399 self.write(', ')
1400 self.visit(item, frame)
1401 self.write(idx == 0 and ',)' or ')')
1402
Armin Ronacher8edbe492008-04-10 20:43:43 +02001403 def visit_List(self, node, frame):
1404 self.write('[')
1405 for idx, item in enumerate(node.items):
1406 if idx:
1407 self.write(', ')
1408 self.visit(item, frame)
1409 self.write(']')
1410
1411 def visit_Dict(self, node, frame):
1412 self.write('{')
1413 for idx, item in enumerate(node.items):
1414 if idx:
1415 self.write(', ')
1416 self.visit(item.key, frame)
1417 self.write(': ')
1418 self.visit(item.value, frame)
1419 self.write('}')
1420
Armin Ronachera9195382010-11-29 13:21:57 +01001421 def binop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001422 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001423 if self.environment.sandboxed and \
1424 operator in self.environment.intercepted_binops:
1425 self.write('environment.call_binop(context, %r, ' % operator)
1426 self.visit(node.left, frame)
1427 self.write(', ')
1428 self.visit(node.right, frame)
1429 else:
1430 self.write('(')
1431 self.visit(node.left, frame)
1432 self.write(' %s ' % operator)
1433 self.visit(node.right, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001434 self.write(')')
1435 return visitor
1436
Armin Ronachera9195382010-11-29 13:21:57 +01001437 def uaop(operator, interceptable=True):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001438 def visitor(self, node, frame):
Armin Ronachera9195382010-11-29 13:21:57 +01001439 if self.environment.sandboxed and \
1440 operator in self.environment.intercepted_unops:
1441 self.write('environment.call_unop(context, %r, ' % operator)
1442 self.visit(node.node, frame)
1443 else:
1444 self.write('(' + operator)
1445 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001446 self.write(')')
1447 return visitor
1448
1449 visit_Add = binop('+')
1450 visit_Sub = binop('-')
1451 visit_Mul = binop('*')
1452 visit_Div = binop('/')
1453 visit_FloorDiv = binop('//')
1454 visit_Pow = binop('**')
1455 visit_Mod = binop('%')
Armin Ronachera9195382010-11-29 13:21:57 +01001456 visit_And = binop('and', interceptable=False)
1457 visit_Or = binop('or', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001458 visit_Pos = uaop('+')
1459 visit_Neg = uaop('-')
Armin Ronachera9195382010-11-29 13:21:57 +01001460 visit_Not = uaop('not ', interceptable=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001461 del binop, uaop
1462
Armin Ronacherd1342312008-04-28 12:20:12 +02001463 def visit_Concat(self, node, frame):
Armin Ronacher8346bd72010-03-14 19:43:47 +01001464 if frame.eval_ctx.volatile:
1465 func_name = '(context.eval_ctx.volatile and' \
1466 ' markup_join or unicode_join)'
1467 elif frame.eval_ctx.autoescape:
1468 func_name = 'markup_join'
1469 else:
1470 func_name = 'unicode_join'
1471 self.write('%s((' % func_name)
Armin Ronacherd1342312008-04-28 12:20:12 +02001472 for arg in node.nodes:
1473 self.visit(arg, frame)
1474 self.write(', ')
1475 self.write('))')
1476
Armin Ronachere791c2a2008-04-07 18:39:54 +02001477 def visit_Compare(self, node, frame):
1478 self.visit(node.expr, frame)
1479 for op in node.ops:
1480 self.visit(op, frame)
1481
1482 def visit_Operand(self, node, frame):
1483 self.write(' %s ' % operators[node.op])
1484 self.visit(node.expr, frame)
1485
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001486 def visit_Getattr(self, node, frame):
1487 self.write('environment.getattr(')
1488 self.visit(node.node, frame)
1489 self.write(', %r)' % node.attr)
1490
1491 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001492 # slices bypass the environment getitem method.
1493 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001494 self.visit(node.node, frame)
1495 self.write('[')
1496 self.visit(node.arg, frame)
1497 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001498 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001499 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001500 self.visit(node.node, frame)
1501 self.write(', ')
1502 self.visit(node.arg, frame)
1503 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001504
1505 def visit_Slice(self, node, frame):
1506 if node.start is not None:
1507 self.visit(node.start, frame)
1508 self.write(':')
1509 if node.stop is not None:
1510 self.visit(node.stop, frame)
1511 if node.step is not None:
1512 self.write(':')
1513 self.visit(node.step, frame)
1514
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001515 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001516 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001517 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001518 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001519 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001520 if getattr(func, 'contextfilter', False):
1521 self.write('context, ')
Armin Ronacher8346bd72010-03-14 19:43:47 +01001522 elif getattr(func, 'evalcontextfilter', False):
1523 self.write('context.eval_ctx, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001524 elif getattr(func, 'environmentfilter', False):
1525 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001526
1527 # if the filter node is None we are inside a filter block
1528 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001529 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001530 self.visit(node.node, frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001531 elif frame.eval_ctx.volatile:
1532 self.write('(context.eval_ctx.autoescape and'
1533 ' Markup(concat(%s)) or concat(%s))' %
1534 (frame.buffer, frame.buffer))
1535 elif frame.eval_ctx.autoescape:
Armin Ronacher3da90312008-05-23 16:37:28 +02001536 self.write('Markup(concat(%s))' % frame.buffer)
1537 else:
1538 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001539 self.signature(node, frame)
1540 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001541
1542 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001543 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001544 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001545 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001546 self.visit(node.node, frame)
1547 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001548 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001549
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001550 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001551 def write_expr2():
1552 if node.expr2 is not None:
1553 return self.visit(node.expr2, frame)
1554 self.write('environment.undefined(%r)' % ('the inline if-'
1555 'expression on %s evaluated to false and '
1556 'no else section was defined.' % self.position(node)))
1557
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001558 if not have_condexpr:
1559 self.write('((')
1560 self.visit(node.test, frame)
1561 self.write(') and (')
1562 self.visit(node.expr1, frame)
1563 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001564 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001565 self.write(',))[0]')
1566 else:
1567 self.write('(')
1568 self.visit(node.expr1, frame)
1569 self.write(' if ')
1570 self.visit(node.test, frame)
1571 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001572 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001573 self.write(')')
1574
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001575 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001576 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001577 self.write('environment.call(context, ')
1578 else:
1579 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001580 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001581 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001582 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001583 self.write(')')
1584
1585 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001586 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001587 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001588
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001589 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001590
1591 def visit_MarkSafe(self, node, frame):
1592 self.write('Markup(')
1593 self.visit(node.expr, frame)
1594 self.write(')')
1595
Armin Ronacher4da90342010-05-29 17:35:10 +02001596 def visit_MarkSafeIfAutoescape(self, node, frame):
1597 self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1598 self.visit(node.expr, frame)
1599 self.write(')')
1600
Armin Ronachered1e0d42008-05-18 20:25:28 +02001601 def visit_EnvironmentAttribute(self, node, frame):
1602 self.write('environment.' + node.name)
1603
1604 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001605 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001606
1607 def visit_ImportedName(self, node, frame):
1608 self.write(self.import_aliases[node.importname])
1609
1610 def visit_InternalName(self, node, frame):
1611 self.write(node.name)
1612
Armin Ronacher6df604e2008-05-23 22:18:38 +02001613 def visit_ContextReference(self, node, frame):
1614 self.write('context')
1615
Armin Ronachered1e0d42008-05-18 20:25:28 +02001616 def visit_Continue(self, node, frame):
1617 self.writeline('continue', node)
1618
1619 def visit_Break(self, node, frame):
1620 self.writeline('break', node)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001621
1622 def visit_Scope(self, node, frame):
1623 scope_frame = frame.inner()
1624 scope_frame.inspect(node.iter_child_nodes())
1625 aliases = self.push_scope(scope_frame)
1626 self.pull_locals(scope_frame)
1627 self.blockvisit(node.body, scope_frame)
1628 self.pop_scope(aliases, scope_frame)
Armin Ronacher8346bd72010-03-14 19:43:47 +01001629
1630 def visit_EvalContextModifier(self, node, frame):
1631 for keyword in node.options:
1632 self.writeline('context.eval_ctx.%s = ' % keyword.key)
1633 self.visit(keyword.value, frame)
1634 try:
1635 val = keyword.value.as_const(frame.eval_ctx)
1636 except nodes.Impossible:
Armin Ronacher744bb0a2010-03-15 00:26:05 +01001637 frame.eval_ctx.volatile = True
Armin Ronacher8346bd72010-03-14 19:43:47 +01001638 else:
1639 setattr(frame.eval_ctx, keyword.key, val)
1640
1641 def visit_ScopedEvalContextModifier(self, node, frame):
1642 old_ctx_name = self.temporary_identifier()
1643 safed_ctx = frame.eval_ctx.save()
1644 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1645 self.visit_EvalContextModifier(node, frame)
1646 for child in node.body:
1647 self.visit(child, frame)
1648 frame.eval_ctx.revert(safed_ctx)
1649 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)