blob: f0deeff5f30922abb823ab3f8f318550024b2892 [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 Ronacher62ccd1b2009-01-04 14:26:19 +01008 :copyright: (c) 2009 by the Jinja Team.
Armin Ronacherd7764372008-07-15 00:11:14 +02009 :license: BSD.
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 Ronachere791c2a2008-04-07 18:39:54 +020013from jinja2 import nodes
14from jinja2.visitor import NodeVisitor, NodeTransformer
15from jinja2.exceptions import TemplateAssertionError
Armin Ronacherbd357722009-08-05 20:25:06 +020016from jinja2.utils import Markup, concat, escape, is_python_keyword, next
Armin Ronachere791c2a2008-04-07 18:39:54 +020017
18
19operators = {
20 'eq': '==',
21 'ne': '!=',
22 'gt': '>',
23 'gteq': '>=',
24 'lt': '<',
25 'lteq': '<=',
26 'in': 'in',
27 'notin': 'not in'
28}
29
Armin Ronacher3d8b7842008-04-13 13:16:50 +020030try:
31 exec '(0 if 0 else 0)'
32except SyntaxError:
33 have_condexpr = False
34else:
35 have_condexpr = True
36
37
Armin Ronacher8e8d0712008-04-16 23:10:49 +020038def generate(node, environment, name, filename, stream=None):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020039 """Generate the python source for a node tree."""
Armin Ronacher023b5e92008-05-08 11:03:10 +020040 if not isinstance(node, nodes.Template):
41 raise TypeError('Can\'t compile non template nodes')
Armin Ronacher8e8d0712008-04-16 23:10:49 +020042 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020043 generator.visit(node)
44 if stream is None:
45 return generator.stream.getvalue()
46
47
Armin Ronacher4dfc9752008-04-09 15:03:29 +020048def has_safe_repr(value):
49 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020050 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020051 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020052 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher32a910f2008-04-26 23:21:03 +020053 xrange, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020054 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020055 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020056 for item in value:
57 if not has_safe_repr(item):
58 return False
59 return True
60 elif isinstance(value, dict):
61 for key, value in value.iteritems():
62 if not has_safe_repr(key):
63 return False
64 if not has_safe_repr(value):
65 return False
66 return True
67 return False
68
69
Armin Ronacherc9705c22008-04-27 21:28:03 +020070def find_undeclared(nodes, names):
71 """Check if the names passed are accessed undeclared. The return value
72 is a set of all the undeclared names from the sequence of names found.
73 """
74 visitor = UndeclaredNameVisitor(names)
75 try:
76 for node in nodes:
77 visitor.visit(node)
78 except VisitorExit:
79 pass
80 return visitor.undeclared
81
82
Armin Ronachere791c2a2008-04-07 18:39:54 +020083class Identifiers(object):
84 """Tracks the status of identifiers in frames."""
85
86 def __init__(self):
87 # variables that are known to be declared (probably from outer
88 # frames or because they are special for the frame)
89 self.declared = set()
90
Armin Ronacher10f3ba22008-04-18 11:30:37 +020091 # undeclared variables from outer scopes
92 self.outer_undeclared = set()
93
Armin Ronachere791c2a2008-04-07 18:39:54 +020094 # names that are accessed without being explicitly declared by
95 # this one or any of the outer scopes. Names can appear both in
96 # declared and undeclared.
97 self.undeclared = set()
98
99 # names that are declared locally
100 self.declared_locally = set()
101
102 # names that are declared by parameters
103 self.declared_parameter = set()
104
105 def add_special(self, name):
106 """Register a special name like `loop`."""
107 self.undeclared.discard(name)
108 self.declared.add(name)
109
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200110 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200111 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200112 if name in self.declared_locally or name in self.declared_parameter:
113 return True
114 if local_only:
115 return False
116 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200117
Armin Ronachere791c2a2008-04-07 18:39:54 +0200118
119class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200120 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200121
122 def __init__(self, parent=None):
123 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200124
Armin Ronacher75cfb862008-04-11 13:47:22 +0200125 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200126 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200127
Armin Ronacher75cfb862008-04-11 13:47:22 +0200128 # the root frame is basically just the outermost frame, so no if
129 # conditions. This information is used to optimize inheritance
130 # situations.
131 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200132
Armin Ronacher79668952008-09-23 22:52:46 +0200133 # in some dynamic inheritance situations the compiler needs to add
134 # write tests around output statements.
135 self.require_output_check = parent and parent.require_output_check
Armin Ronacherf40c8842008-09-17 18:51:26 +0200136
Armin Ronacherfed44b52008-04-13 19:42:53 +0200137 # inside some tags we are using a buffer rather than yield statements.
138 # this for example affects {% filter %} or {% macro %}. If a frame
139 # is buffered this variable points to the name of the list used as
140 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200141 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200142
Armin Ronacherfed44b52008-04-13 19:42:53 +0200143 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200144 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200145
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100146 # a set of actually assigned names
147 self.assigned_names = set()
148
Armin Ronacherfed44b52008-04-13 19:42:53 +0200149 # the parent of this frame
150 self.parent = parent
151
Armin Ronachere791c2a2008-04-07 18:39:54 +0200152 if parent is not None:
153 self.identifiers.declared.update(
154 parent.identifiers.declared |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200155 parent.identifiers.declared_parameter |
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100156 parent.assigned_names
Armin Ronachere791c2a2008-04-07 18:39:54 +0200157 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200158 self.identifiers.outer_undeclared.update(
159 parent.identifiers.undeclared -
160 self.identifiers.declared
161 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200162 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200163
Armin Ronacher8efc5222008-04-08 14:47:40 +0200164 def copy(self):
165 """Create a copy of the current one."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200166 rv = object.__new__(self.__class__)
167 rv.__dict__.update(self.__dict__)
168 rv.identifiers = object.__new__(self.identifiers.__class__)
169 rv.identifiers.__dict__.update(self.identifiers.__dict__)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200170 return rv
171
Armin Ronacherc9705c22008-04-27 21:28:03 +0200172 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200173 """Walk the node and check for identifiers. If the scope is hard (eg:
174 enforce on a python level) overrides from outer scopes are tracked
175 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200176 """
177 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200178 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200179 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200180
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100181 def find_shadowed(self, extra=()):
182 """Find all the shadowed names. extra is an iterable of variables
183 that may be defined with `add_special` which may occour scoped.
184 """
185 i = self.identifiers
186 return (i.declared | i.outer_undeclared) & \
187 (i.declared_locally | i.declared_parameter) | \
188 set(x for x in extra if i.is_declared(x))
189
Armin Ronachere791c2a2008-04-07 18:39:54 +0200190 def inner(self):
191 """Return an inner frame."""
192 return Frame(self)
193
Armin Ronacher75cfb862008-04-11 13:47:22 +0200194 def soft(self):
195 """Return a soft frame. A soft frame may not be modified as
196 standalone thing as it shares the resources with the frame it
197 was created of, but it's not a rootlevel frame any longer.
198 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200199 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200200 rv.rootlevel = False
201 return rv
202
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200203 __copy__ = copy
204
Armin Ronachere791c2a2008-04-07 18:39:54 +0200205
Armin Ronacherc9705c22008-04-27 21:28:03 +0200206class VisitorExit(RuntimeError):
207 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
208
209
210class DependencyFinderVisitor(NodeVisitor):
211 """A visitor that collects filter and test calls."""
212
213 def __init__(self):
214 self.filters = set()
215 self.tests = set()
216
217 def visit_Filter(self, node):
218 self.generic_visit(node)
219 self.filters.add(node.name)
220
221 def visit_Test(self, node):
222 self.generic_visit(node)
223 self.tests.add(node.name)
224
225 def visit_Block(self, node):
226 """Stop visiting at blocks."""
227
228
229class UndeclaredNameVisitor(NodeVisitor):
230 """A visitor that checks if a name is accessed without being
231 declared. This is different from the frame visitor as it will
232 not stop at closure frames.
233 """
234
235 def __init__(self, names):
236 self.names = set(names)
237 self.undeclared = set()
238
239 def visit_Name(self, node):
240 if node.ctx == 'load' and node.name in self.names:
241 self.undeclared.add(node.name)
242 if self.undeclared == self.names:
243 raise VisitorExit()
244 else:
245 self.names.discard(node.name)
246
247 def visit_Block(self, node):
248 """Stop visiting a blocks."""
249
250
Armin Ronachere791c2a2008-04-07 18:39:54 +0200251class FrameIdentifierVisitor(NodeVisitor):
252 """A visitor for `Frame.inspect`."""
253
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200254 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200255 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200256 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200257
Armin Ronacherc9705c22008-04-27 21:28:03 +0200258 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200259 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200260 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200261 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200262 elif node.ctx == 'param':
263 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200264 elif node.ctx == 'load' and not \
265 self.identifiers.is_declared(node.name, self.hard_scope):
266 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200267
Armin Ronacherc9705c22008-04-27 21:28:03 +0200268 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200269 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200270
Armin Ronacherc9705c22008-04-27 21:28:03 +0200271 def visit_Import(self, node):
272 self.generic_visit(node)
273 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200274
Armin Ronacherc9705c22008-04-27 21:28:03 +0200275 def visit_FromImport(self, node):
276 self.generic_visit(node)
277 for name in node.names:
278 if isinstance(name, tuple):
279 self.identifiers.declared_locally.add(name[1])
280 else:
281 self.identifiers.declared_locally.add(name)
282
283 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200284 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200285 self.visit(node.node)
286 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200287
Armin Ronacherc9705c22008-04-27 21:28:03 +0200288 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200289 """Visiting stops at for blocks. However the block sequence
290 is visited as part of the outer scope.
291 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200292 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200293
Armin Ronacherc9705c22008-04-27 21:28:03 +0200294 def visit_CallBlock(self, node):
295 for child in node.iter_child_nodes(exclude=('body',)):
296 self.visit(child)
297
298 def visit_FilterBlock(self, node):
299 self.visit(node.filter)
300
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100301 def visit_Scope(self, node):
302 """Stop visiting at scopes."""
303
Armin Ronacherc9705c22008-04-27 21:28:03 +0200304 def visit_Block(self, node):
305 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200306
307
Armin Ronacher75cfb862008-04-11 13:47:22 +0200308class CompilerExit(Exception):
309 """Raised if the compiler encountered a situation where it just
310 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200311 raises such an exception is not further processed.
312 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200313
314
Armin Ronachere791c2a2008-04-07 18:39:54 +0200315class CodeGenerator(NodeVisitor):
316
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200317 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200318 if stream is None:
319 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200320 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200321 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200322 self.filename = filename
323 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200324
Armin Ronacher023b5e92008-05-08 11:03:10 +0200325 # aliases for imports
326 self.import_aliases = {}
327
Armin Ronacherfed44b52008-04-13 19:42:53 +0200328 # a registry for all blocks. Because blocks are moved out
329 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200330 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200331
332 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200333 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200334
335 # some templates have a rootlevel extends. In this case we
336 # can safely assume that we're a child template and do some
337 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200338 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200339
Armin Ronacherba3757b2008-04-16 19:43:16 +0200340 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200341 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200342
Armin Ronacherb9e78752008-05-10 23:36:28 +0200343 # registry of all filters and tests (global, not block local)
344 self.tests = {}
345 self.filters = {}
346
Armin Ronacherba3757b2008-04-16 19:43:16 +0200347 # the debug information
348 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200349 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200350
Armin Ronacherfed44b52008-04-13 19:42:53 +0200351 # the number of new lines before the next write()
352 self._new_lines = 0
353
354 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200355 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200356
357 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200358 self._first_write = True
359
Armin Ronacherfed44b52008-04-13 19:42:53 +0200360 # used by the `temporary_identifier` method to get new
361 # unique, temporary identifier
362 self._last_identifier = 0
363
364 # the current indentation
365 self._indentation = 0
366
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200367 # -- Various compilation helpers
368
Armin Ronachere2244882008-05-19 09:25:57 +0200369 def fail(self, msg, lineno):
370 """Fail with a `TemplateAssertionError`."""
371 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
372
Armin Ronachere791c2a2008-04-07 18:39:54 +0200373 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200374 """Get a new unique identifier."""
375 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200376 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200377
Armin Ronachered1e0d42008-05-18 20:25:28 +0200378 def buffer(self, frame):
379 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200380 frame.buffer = self.temporary_identifier()
381 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200382
383 def return_buffer_contents(self, frame):
384 """Return the buffer contents of the frame."""
385 if self.environment.autoescape:
386 self.writeline('return Markup(concat(%s))' % frame.buffer)
387 else:
388 self.writeline('return concat(%s)' % frame.buffer)
389
Armin Ronachere791c2a2008-04-07 18:39:54 +0200390 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200391 """Indent by one."""
392 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200393
Armin Ronacher8efc5222008-04-08 14:47:40 +0200394 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200395 """Outdent by step."""
396 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200397
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200398 def start_write(self, frame, node=None):
399 """Yield or write into the frame buffer."""
400 if frame.buffer is None:
401 self.writeline('yield ', node)
402 else:
403 self.writeline('%s.append(' % frame.buffer, node)
404
405 def end_write(self, frame):
406 """End the writing process started by `start_write`."""
407 if frame.buffer is not None:
408 self.write(')')
409
410 def simple_write(self, s, frame, node=None):
411 """Simple shortcut for start_write + write + end_write."""
412 self.start_write(frame, node)
413 self.write(s)
414 self.end_write(frame)
415
Armin Ronacherf40c8842008-09-17 18:51:26 +0200416 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200417 """Visit a list of nodes as block in a frame. If the current frame
418 is no buffer a dummy ``if 0: yield None`` is written automatically
419 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200420 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200421 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200422 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200423 else:
424 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200425 try:
426 for node in nodes:
427 self.visit(node, frame)
428 except CompilerExit:
429 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200430
431 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200432 """Write a string into the output stream."""
433 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200434 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200435 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200436 self.code_lineno += self._new_lines
437 if self._write_debug_info is not None:
438 self.debug_info.append((self._write_debug_info,
439 self.code_lineno))
440 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200441 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200442 self.stream.write(' ' * self._indentation)
443 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200444 self.stream.write(x)
445
446 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200447 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200448 self.newline(node, extra)
449 self.write(x)
450
451 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200452 """Add one or more newlines before the next write."""
453 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200454 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200455 self._write_debug_info = node.lineno
456 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200457
Armin Ronacherfd310492008-05-25 00:16:51 +0200458 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200459 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200460 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200461 arguments may not include python keywords otherwise a syntax
462 error could occour. The extra keyword arguments should be given
463 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200464 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200465 # if any of the given keyword arguments is a python keyword
466 # we have to make sure that no invalid call is created.
467 kwarg_workaround = False
468 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200469 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200470 kwarg_workaround = True
471 break
472
Armin Ronacher8efc5222008-04-08 14:47:40 +0200473 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200474 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200475 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200476
477 if not kwarg_workaround:
478 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200479 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200480 self.visit(kwarg, frame)
481 if extra_kwargs is not None:
482 for key, value in extra_kwargs.iteritems():
Armin Ronacherfd310492008-05-25 00:16:51 +0200483 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200484 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200485 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200486 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200487
488 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200489 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200490 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200491 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200492 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200493 for kwarg in node.kwargs:
494 self.write('%r: ' % kwarg.key)
495 self.visit(kwarg.value, frame)
496 self.write(', ')
497 if extra_kwargs is not None:
498 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200499 self.write('%r: %s, ' % (key, value))
500 if node.dyn_kwargs is not None:
501 self.write('}, **')
502 self.visit(node.dyn_kwargs, frame)
503 self.write(')')
504 else:
505 self.write('}')
506
507 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200508 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200509 self.visit(node.dyn_kwargs, frame)
510
Armin Ronacherc9705c22008-04-27 21:28:03 +0200511 def pull_locals(self, frame):
512 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200513 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200514 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200515
516 def pull_dependencies(self, nodes):
517 """Pull all the dependencies."""
518 visitor = DependencyFinderVisitor()
519 for node in nodes:
520 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200521 for dependency in 'filters', 'tests':
522 mapping = getattr(self, dependency)
523 for name in getattr(visitor, dependency):
524 if name not in mapping:
525 mapping[name] = self.temporary_identifier()
526 self.writeline('%s = environment.%s[%r]' %
527 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200528
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100529 def unoptimize_scope(self, frame):
530 """Disable Python optimizations for the frame."""
531 # XXX: this is not that nice but it has no real overhead. It
532 # mainly works because python finds the locals before dead code
533 # is removed. If that breaks we have to add a dummy function
534 # that just accepts the arguments and does nothing.
535 if frame.identifiers.declared:
536 self.writeline('if 0: dummy(%s)' % ', '.join(
537 'l_' + name for name in frame.identifiers.declared))
538
Armin Ronacher673aa882008-10-04 18:06:57 +0200539 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200540 """This function returns all the shadowed variables in a dict
541 in the form name: alias and will write the required assignments
542 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200543
Armin Ronacher673aa882008-10-04 18:06:57 +0200544 This also predefines locally declared variables from the loop
545 body because under some circumstances it may be the case that
546
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100547 `extra_vars` is passed to `Frame.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200548 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200549 aliases = {}
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100550 for name in frame.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200551 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200552 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200553 to_declare = set()
554 for name in frame.identifiers.declared_locally:
555 if name not in aliases:
556 to_declare.add('l_' + name)
557 if to_declare:
558 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200559 return aliases
560
Armin Ronacher673aa882008-10-04 18:06:57 +0200561 def pop_scope(self, aliases, frame):
562 """Restore all aliases and delete unused variables."""
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200563 for name, alias in aliases.iteritems():
564 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200565 to_delete = set()
566 for name in frame.identifiers.declared_locally:
567 if name not in aliases:
568 to_delete.add('l_' + name)
569 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100570 # we cannot use the del statement here because enclosed
571 # scopes can trigger a SyntaxError:
572 # a = 42; b = lambda: a; del a
573 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200574
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200575 def function_scoping(self, node, frame, children=None,
576 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200577 """In Jinja a few statements require the help of anonymous
578 functions. Those are currently macros and call blocks and in
579 the future also recursive loops. As there is currently
580 technical limitation that doesn't allow reading and writing a
581 variable in a scope where the initial value is coming from an
582 outer scope, this function tries to fall back with a common
583 error message. Additionally the frame passed is modified so
584 that the argumetns are collected and callers are looked up.
585
586 This will return the modified frame.
587 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200588 # we have to iterate twice over it, make sure that works
589 if children is None:
590 children = node.iter_child_nodes()
591 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200592 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200593 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200594
595 # variables that are undeclared (accessed before declaration) and
596 # declared locally *and* part of an outside scope raise a template
597 # assertion error. Reason: we can't generate reasonable code from
Armin Ronacher02b42a82009-03-18 00:59:32 +0100598 # it without aliasing all the variables.
599 # this could be fixed in Python 3 where we have the nonlocal
600 # keyword or if we switch to bytecode generation
Armin Ronacher71082072008-04-12 14:19:36 +0200601 overriden_closure_vars = (
602 func_frame.identifiers.undeclared &
603 func_frame.identifiers.declared &
604 (func_frame.identifiers.declared_locally |
605 func_frame.identifiers.declared_parameter)
606 )
607 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200608 self.fail('It\'s not possible to set and access variables '
609 'derived from an outer scope! (affects: %s' %
610 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200611
612 # remove variables from a closure from the frame's undeclared
613 # identifiers.
614 func_frame.identifiers.undeclared -= (
615 func_frame.identifiers.undeclared &
616 func_frame.identifiers.declared
617 )
618
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200619 # no special variables for this scope, abort early
620 if not find_special:
621 return func_frame
622
Armin Ronacher963f97d2008-04-25 11:44:59 +0200623 func_frame.accesses_kwargs = False
624 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200625 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200626 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200627
Armin Ronacherc9705c22008-04-27 21:28:03 +0200628 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
629
630 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200631 func_frame.accesses_caller = True
632 func_frame.identifiers.add_special('caller')
633 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200634 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200635 func_frame.accesses_kwargs = True
636 func_frame.identifiers.add_special('kwargs')
637 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200638 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200639 func_frame.accesses_varargs = True
640 func_frame.identifiers.add_special('varargs')
641 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200642 return func_frame
643
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200644 def macro_body(self, node, frame, children=None):
645 """Dump the function def of a macro or call block."""
646 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100647 # macros are delayed, they never require output checks
648 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200649 args = frame.arguments
Armin Ronachereabf3dd2009-09-12 23:48:18 -0700650 # XXX: this is an ugly fix for the loop nesting bug
651 # (tests.test_old_bugs.test_loop_call_bug). This works around
652 # a identifier nesting problem we have in general. It's just more
653 # likely to happen in loops which is why we work around it. The
654 # real solution would be "nonlocal" all the identifiers that are
655 # leaking into a new python frame and might be used both unassigned
656 # and assigned.
657 if 'loop' in frame.identifiers.declared:
658 args.append('l_loop=l_loop')
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200659 self.writeline('def macro(%s):' % ', '.join(args), node)
660 self.indent()
661 self.buffer(frame)
662 self.pull_locals(frame)
663 self.blockvisit(node.body, frame)
664 self.return_buffer_contents(frame)
665 self.outdent()
666 return frame
667
668 def macro_def(self, node, frame):
669 """Dump the macro definition for the def created by macro_body."""
670 arg_tuple = ', '.join(repr(x.name) for x in node.args)
671 name = getattr(node, 'name', None)
672 if len(node.args) == 1:
673 arg_tuple += ','
674 self.write('Macro(environment, macro, %r, (%s), (' %
675 (name, arg_tuple))
676 for arg in node.defaults:
677 self.visit(arg, frame)
678 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200679 self.write('), %r, %r, %r)' % (
680 bool(frame.accesses_kwargs),
681 bool(frame.accesses_varargs),
682 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200683 ))
684
Armin Ronacher547d0b62008-07-04 16:35:10 +0200685 def position(self, node):
686 """Return a human readable position for the node."""
687 rv = 'line %d' % node.lineno
688 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100689 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200690 return rv
691
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200692 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200693
694 def visit_Template(self, node, frame=None):
695 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200696 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200697 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200698 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8edbe492008-04-10 20:43:43 +0200699
Armin Ronacher75cfb862008-04-11 13:47:22 +0200700 # do we have an extends tag at all? If not, we can save some
701 # overhead by just not processing any inheritance code.
702 have_extends = node.find(nodes.Extends) is not None
703
Armin Ronacher8edbe492008-04-10 20:43:43 +0200704 # find all blocks
705 for block in node.find_all(nodes.Block):
706 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200707 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200708 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200709
Armin Ronacher023b5e92008-05-08 11:03:10 +0200710 # find all imports and import them
711 for import_ in node.find_all(nodes.ImportedName):
712 if import_.importname not in self.import_aliases:
713 imp = import_.importname
714 self.import_aliases[imp] = alias = self.temporary_identifier()
715 if '.' in imp:
716 module, obj = imp.rsplit('.', 1)
717 self.writeline('from %s import %s as %s' %
718 (module, obj, alias))
719 else:
720 self.writeline('import %s as %s' % (imp, alias))
721
722 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200723 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200724
Armin Ronacher8efc5222008-04-08 14:47:40 +0200725 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200726 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200727
728 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200729 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200730 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200731 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200732 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200733 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200734 if have_extends:
735 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200736 if 'self' in find_undeclared(node.body, ('self',)):
737 frame.identifiers.add_special('self')
738 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200739 self.pull_locals(frame)
740 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200741 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200742 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200743
Armin Ronacher8efc5222008-04-08 14:47:40 +0200744 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200745 if have_extends:
746 if not self.has_known_extends:
747 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200748 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200749 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200750 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200751 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200752 self.indent()
753 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200754 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200755
756 # at this point we now have the blocks collected and can visit them too.
757 for name, block in self.blocks.iteritems():
758 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200759 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200760 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200761 self.writeline('def block_%s(context, environment=environment):'
762 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200763 self.indent()
764 undeclared = find_undeclared(block.body, ('self', 'super'))
765 if 'self' in undeclared:
766 block_frame.identifiers.add_special('self')
767 self.writeline('l_self = TemplateReference(context)')
768 if 'super' in undeclared:
769 block_frame.identifiers.add_special('super')
770 self.writeline('l_super = context.super(%r, '
771 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200772 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200773 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200774 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200775 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200776
Armin Ronacher75cfb862008-04-11 13:47:22 +0200777 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200778 for x in self.blocks),
779 extra=1)
780
781 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200782 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
783 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200784
Armin Ronachere791c2a2008-04-07 18:39:54 +0200785 def visit_Block(self, node, frame):
786 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200787 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200788 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200789 # if we know that we are a child template, there is no need to
790 # check if we are one
791 if self.has_known_extends:
792 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200793 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200794 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200795 self.indent()
796 level += 1
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100797 if node.scoped:
798 context = 'context.derived(locals())'
799 else:
800 context = 'context'
801 self.writeline('for event in context.blocks[%r][0](%s):' % (
802 node.name, context), node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200803 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200804 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200805 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200806
807 def visit_Extends(self, node, frame):
808 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200809 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200810 self.fail('cannot use extend from a non top-level scope',
811 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200812
Armin Ronacher7fb38972008-04-11 13:54:28 +0200813 # if the number of extends statements in general is zero so
814 # far, we don't have to add a check if something extended
815 # the template before this one.
816 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200817
Armin Ronacher7fb38972008-04-11 13:54:28 +0200818 # if we have a known extends we just add a template runtime
819 # error into the generated code. We could catch that at compile
820 # time too, but i welcome it not to confuse users by throwing the
821 # same error at different times just "because we can".
822 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200823 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200824 self.indent()
825 self.writeline('raise TemplateRuntimeError(%r)' %
826 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200827 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200828
Armin Ronacher7fb38972008-04-11 13:54:28 +0200829 # if we have a known extends already we don't need that code here
830 # as we know that the template execution will end here.
831 if self.has_known_extends:
832 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200833
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200834 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200835 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200836 self.write(', %r)' % self.name)
837 self.writeline('for name, parent_block in parent_template.'
838 'blocks.iteritems():')
839 self.indent()
840 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200841 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200842 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200843
844 # if this extends statement was in the root level we can take
845 # advantage of that information and simplify the generated code
846 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200847 if frame.rootlevel:
848 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200849
Armin Ronacher7fb38972008-04-11 13:54:28 +0200850 # and now we have one more
851 self.extends_so_far += 1
852
Armin Ronacherf059ec12008-04-11 22:21:00 +0200853 def visit_Include(self, node, frame):
854 """Handles includes."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100855 if node.with_context:
856 self.unoptimize_scope(frame)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100857 if node.ignore_missing:
858 self.writeline('try:')
859 self.indent()
860 self.writeline('template = environment.get_template(', node)
861 self.visit(node.template, frame)
862 self.write(', %r)' % self.name)
863 if node.ignore_missing:
864 self.outdent()
865 self.writeline('except TemplateNotFound:')
866 self.indent()
867 self.writeline('pass')
868 self.outdent()
869 self.writeline('else:')
870 self.indent()
871
Armin Ronacherea847c52008-05-02 20:04:32 +0200872 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200873 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200874 'template.new_context(context.parent, True, '
875 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200876 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100877 self.writeline('for event in template.module._body_stream:')
878
Armin Ronacherf059ec12008-04-11 22:21:00 +0200879 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200880 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200881 self.outdent()
882
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100883 if node.ignore_missing:
884 self.outdent()
885
Armin Ronacher0611e492008-04-25 23:44:14 +0200886 def visit_Import(self, node, frame):
887 """Visit regular imports."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100888 if node.with_context:
889 self.unoptimize_scope(frame)
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200890 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200891 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200892 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200893 self.write('environment.get_template(')
894 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200895 self.write(', %r).' % self.name)
896 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200897 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200898 else:
899 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200900 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200901 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100902 frame.assigned_names.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200903
904 def visit_FromImport(self, node, frame):
905 """Visit named imports."""
906 self.newline(node)
907 self.write('included_template = environment.get_template(')
908 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200909 self.write(', %r).' % self.name)
910 if node.with_context:
911 self.write('make_module(context.parent, True)')
912 else:
913 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200914
915 var_names = []
916 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200917 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200918 if isinstance(name, tuple):
919 name, alias = name
920 else:
921 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200922 self.writeline('l_%s = getattr(included_template, '
923 '%r, missing)' % (alias, name))
924 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200925 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200926 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +0200927 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200928 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +0200929 (alias, 'the template %%r (imported on %s) does '
930 'not export the requested name %s' % (
931 self.position(node),
932 repr(name)
933 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +0200934 self.outdent()
935 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +0200936 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +0200937 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +0200938 discarded_names.append(alias)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100939 frame.assigned_names.add(alias)
Armin Ronachera78d2762008-05-15 23:18:07 +0200940
941 if var_names:
942 if len(var_names) == 1:
943 name = var_names[0]
944 self.writeline('context.vars[%r] = l_%s' % (name, name))
945 else:
946 self.writeline('context.vars.update({%s})' % ', '.join(
947 '%r: l_%s' % (name, name) for name in var_names
948 ))
949 if discarded_names:
950 if len(discarded_names) == 1:
951 self.writeline('context.exported_vars.discard(%r)' %
952 discarded_names[0])
953 else:
954 self.writeline('context.exported_vars.difference_'
955 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200956
Armin Ronachere791c2a2008-04-07 18:39:54 +0200957 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200958 # when calculating the nodes for the inner frame we have to exclude
959 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200960 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200961 if node.recursive:
962 loop_frame = self.function_scoping(node, frame, children,
963 find_special=False)
964 else:
965 loop_frame = frame.inner()
966 loop_frame.inspect(children)
967
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200968 # try to figure out if we have an extended loop. An extended loop
969 # is necessary if the loop is in recursive mode if the special loop
970 # variable is accessed in the body.
971 extended_loop = node.recursive or 'loop' in \
972 find_undeclared(node.iter_child_nodes(
973 only=('body',)), ('loop',))
974
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200975 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +0200976 # variables at that point. Because loops can be nested but the loop
977 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200978 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +0200979 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200980
981 # otherwise we set up a buffer and add a function def
982 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200983 self.writeline('def loop(reciter, loop_render_func):', node)
984 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +0200985 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200986 aliases = {}
987
Armin Ronacherff53c782008-08-13 18:55:50 +0200988 # make sure the loop variable is a special one and raise a template
989 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +0200990 if extended_loop:
991 loop_frame.identifiers.add_special('loop')
Armin Ronacherff53c782008-08-13 18:55:50 +0200992 for name in node.find_all(nodes.Name):
993 if name.ctx == 'store' and name.name == 'loop':
994 self.fail('Can\'t assign to special loop variable '
995 'in for-loop target', name.lineno)
996
Armin Ronacherc9705c22008-04-27 21:28:03 +0200997 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200998 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200999 iteration_indicator = self.temporary_identifier()
1000 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001001
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001002 # Create a fake parent loop if the else or test section of a
1003 # loop is accessing the special loop variable and no parent loop
1004 # exists.
1005 if 'loop' not in aliases and 'loop' in find_undeclared(
1006 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1007 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001008 ("'loop' is undefined. the filter section of a loop as well "
1009 "as the else block doesn't have access to the special 'loop'"
1010 " variable of the current loop. Because there is no parent "
1011 "loop it's undefined. Happened in loop on %s" %
1012 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001013
1014 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001015 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +02001016 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001017
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001018 # if we have an extened loop and a node test, we filter in the
1019 # "outer frame".
1020 if extended_loop and node.test is not None:
1021 self.write('(')
1022 self.visit(node.target, loop_frame)
1023 self.write(' for ')
1024 self.visit(node.target, loop_frame)
1025 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001026 if node.recursive:
1027 self.write('reciter')
1028 else:
1029 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001030 self.write(' if (')
1031 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001032 self.visit(node.test, test_frame)
1033 self.write('))')
1034
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001035 elif node.recursive:
1036 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001037 else:
1038 self.visit(node.iter, loop_frame)
1039
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001040 if node.recursive:
1041 self.write(', recurse=loop_render_func):')
1042 else:
1043 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001044
1045 # tests in not extended loops become a continue
1046 if not extended_loop and node.test is not None:
1047 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +02001048 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +02001049 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001050 self.write(':')
1051 self.indent()
1052 self.writeline('continue')
1053 self.outdent(2)
1054
Armin Ronacherc9705c22008-04-27 21:28:03 +02001055 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001056 self.blockvisit(node.body, loop_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001057 if node.else_:
1058 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001059 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001060
1061 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001062 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001063 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001064 self.blockvisit(node.else_, loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001065 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001066
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001067 # reset the aliases if there are any.
Armin Ronachercebd8382008-12-25 18:33:46 +01001068 if not node.recursive:
1069 self.pop_scope(aliases, loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001070
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001071 # if the node was recursive we have to return the buffer contents
1072 # and start the iteration code
1073 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001074 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001075 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001076 self.start_write(frame, node)
1077 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001078 self.visit(node.iter, frame)
1079 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001080 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001081
Armin Ronachere791c2a2008-04-07 18:39:54 +02001082 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001083 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001084 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001085 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001086 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001087 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001088 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001089 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001090 if node.else_:
1091 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001092 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001093 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001094 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001095
Armin Ronacher8efc5222008-04-08 14:47:40 +02001096 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001097 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001098 self.newline()
1099 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001100 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001101 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001102 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001103 self.write('l_%s = ' % node.name)
1104 self.macro_def(node, macro_frame)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001105 frame.assigned_names.add(node.name)
Armin Ronacher71082072008-04-12 14:19:36 +02001106
1107 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001108 children = node.iter_child_nodes(exclude=('call',))
1109 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001110 self.writeline('caller = ')
1111 self.macro_def(node, call_frame)
1112 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001113 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001114 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001115
1116 def visit_FilterBlock(self, node, frame):
1117 filter_frame = frame.inner()
1118 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacher673aa882008-10-04 18:06:57 +02001119 aliases = self.push_scope(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001120 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001121 self.buffer(filter_frame)
Armin Ronacherf40c8842008-09-17 18:51:26 +02001122 self.blockvisit(node.body, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001123 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001124 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001125 self.end_write(frame)
Armin Ronacher673aa882008-10-04 18:06:57 +02001126 self.pop_scope(aliases, filter_frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001127
Armin Ronachere791c2a2008-04-07 18:39:54 +02001128 def visit_ExprStmt(self, node, frame):
1129 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001130 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001131
1132 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001133 # if we have a known extends statement, we don't output anything
Armin Ronacher79668952008-09-23 22:52:46 +02001134 # if we are in a require_output_check section
1135 if self.has_known_extends and frame.require_output_check:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001136 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001137
Armin Ronacher665bfb82008-07-14 13:41:46 +02001138 if self.environment.finalize:
1139 finalize = lambda x: unicode(self.environment.finalize(x))
1140 else:
1141 finalize = unicode
1142
Armin Ronacher75cfb862008-04-11 13:47:22 +02001143 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001144
Armin Ronacher79668952008-09-23 22:52:46 +02001145 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001146 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001147 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001148 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001149 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001150 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001151
Armin Ronachere791c2a2008-04-07 18:39:54 +02001152 # try to evaluate as many chunks as possible into a static
1153 # string at compile time.
1154 body = []
1155 for child in node.nodes:
1156 try:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001157 const = child.as_const()
1158 except nodes.Impossible:
1159 body.append(child)
1160 continue
1161 try:
1162 if self.environment.autoescape:
1163 if hasattr(const, '__html__'):
1164 const = const.__html__()
1165 else:
1166 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001167 const = finalize(const)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001168 except:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001169 # if something goes wrong here we evaluate the node
1170 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001171 body.append(child)
1172 continue
1173 if body and isinstance(body[-1], list):
1174 body[-1].append(const)
1175 else:
1176 body.append([const])
1177
Armin Ronachered1e0d42008-05-18 20:25:28 +02001178 # if we have less than 3 nodes or a buffer we yield or extend/append
1179 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001180 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001181 # for one item we append, for more we extend
1182 if len(body) == 1:
1183 self.writeline('%s.append(' % frame.buffer)
1184 else:
1185 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001186 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001187 for item in body:
1188 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001189 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001190 if frame.buffer is None:
1191 self.writeline('yield ' + val)
1192 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001193 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001194 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001195 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001196 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001197 else:
1198 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001199 close = 1
1200 if self.environment.autoescape:
1201 self.write('escape(')
1202 else:
Armin Ronacherbd357722009-08-05 20:25:06 +02001203 self.write('to_string(')
Armin Ronacherd1342312008-04-28 12:20:12 +02001204 if self.environment.finalize is not None:
1205 self.write('environment.finalize(')
1206 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001207 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001208 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001209 if frame.buffer is not None:
1210 self.write(', ')
1211 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001212 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001213 self.outdent()
1214 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001215
1216 # otherwise we create a format string as this is faster in that case
1217 else:
1218 format = []
1219 arguments = []
1220 for item in body:
1221 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001222 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001223 else:
1224 format.append('%s')
1225 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001226 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001227 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001228 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001229 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001230 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001231 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001232 close = 0
1233 if self.environment.autoescape:
1234 self.write('escape(')
1235 close += 1
1236 if self.environment.finalize is not None:
1237 self.write('environment.finalize(')
1238 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001239 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001240 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001241 self.outdent()
1242 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001243
Armin Ronacher7fb38972008-04-11 13:54:28 +02001244 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001245 self.outdent()
1246
Armin Ronacher8efc5222008-04-08 14:47:40 +02001247 def visit_Assign(self, node, frame):
1248 self.newline(node)
1249 # toplevel assignments however go into the local namespace and
1250 # the current template's context. We create a copy of the frame
1251 # here and add a set so that the Name visitor can add the assigned
1252 # names here.
1253 if frame.toplevel:
1254 assignment_frame = frame.copy()
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001255 assignment_frame.toplevel_assignments = set()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001256 else:
1257 assignment_frame = frame
1258 self.visit(node.target, assignment_frame)
1259 self.write(' = ')
1260 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001261
1262 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001263 if frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001264 public_names = [x for x in assignment_frame.toplevel_assignments
Armin Ronacher903d1682008-05-23 00:51:58 +02001265 if not x.startswith('_')]
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001266 if len(assignment_frame.toplevel_assignments) == 1:
Armin Ronacherbd357722009-08-05 20:25:06 +02001267 name = next(iter(assignment_frame.toplevel_assignments))
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001268 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001269 else:
1270 self.writeline('context.vars.update({')
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001271 for idx, name in enumerate(assignment_frame.toplevel_assignments):
Armin Ronacher69e12db2008-05-12 09:00:03 +02001272 if idx:
1273 self.write(', ')
1274 self.write('%r: l_%s' % (name, name))
1275 self.write('})')
1276 if public_names:
1277 if len(public_names) == 1:
1278 self.writeline('context.exported_vars.add(%r)' %
1279 public_names[0])
1280 else:
1281 self.writeline('context.exported_vars.update((%s))' %
1282 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001283
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001284 # -- Expression Visitors
1285
Armin Ronachere791c2a2008-04-07 18:39:54 +02001286 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001287 if node.ctx == 'store' and frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001288 frame.toplevel_assignments.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001289 self.write('l_' + node.name)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001290 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001291
1292 def visit_Const(self, node, frame):
1293 val = node.value
1294 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001295 self.write(str(val))
1296 else:
1297 self.write(repr(val))
1298
Armin Ronacher5411ce72008-05-25 11:36:22 +02001299 def visit_TemplateData(self, node, frame):
1300 self.write(repr(node.as_const()))
1301
Armin Ronacher8efc5222008-04-08 14:47:40 +02001302 def visit_Tuple(self, node, frame):
1303 self.write('(')
1304 idx = -1
1305 for idx, item in enumerate(node.items):
1306 if idx:
1307 self.write(', ')
1308 self.visit(item, frame)
1309 self.write(idx == 0 and ',)' or ')')
1310
Armin Ronacher8edbe492008-04-10 20:43:43 +02001311 def visit_List(self, node, frame):
1312 self.write('[')
1313 for idx, item in enumerate(node.items):
1314 if idx:
1315 self.write(', ')
1316 self.visit(item, frame)
1317 self.write(']')
1318
1319 def visit_Dict(self, node, frame):
1320 self.write('{')
1321 for idx, item in enumerate(node.items):
1322 if idx:
1323 self.write(', ')
1324 self.visit(item.key, frame)
1325 self.write(': ')
1326 self.visit(item.value, frame)
1327 self.write('}')
1328
Armin Ronachere791c2a2008-04-07 18:39:54 +02001329 def binop(operator):
1330 def visitor(self, node, frame):
1331 self.write('(')
1332 self.visit(node.left, frame)
1333 self.write(' %s ' % operator)
1334 self.visit(node.right, frame)
1335 self.write(')')
1336 return visitor
1337
1338 def uaop(operator):
1339 def visitor(self, node, frame):
1340 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001341 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001342 self.write(')')
1343 return visitor
1344
1345 visit_Add = binop('+')
1346 visit_Sub = binop('-')
1347 visit_Mul = binop('*')
1348 visit_Div = binop('/')
1349 visit_FloorDiv = binop('//')
1350 visit_Pow = binop('**')
1351 visit_Mod = binop('%')
1352 visit_And = binop('and')
1353 visit_Or = binop('or')
1354 visit_Pos = uaop('+')
1355 visit_Neg = uaop('-')
1356 visit_Not = uaop('not ')
1357 del binop, uaop
1358
Armin Ronacherd1342312008-04-28 12:20:12 +02001359 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001360 self.write('%s((' % (self.environment.autoescape and
1361 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001362 for arg in node.nodes:
1363 self.visit(arg, frame)
1364 self.write(', ')
1365 self.write('))')
1366
Armin Ronachere791c2a2008-04-07 18:39:54 +02001367 def visit_Compare(self, node, frame):
1368 self.visit(node.expr, frame)
1369 for op in node.ops:
1370 self.visit(op, frame)
1371
1372 def visit_Operand(self, node, frame):
1373 self.write(' %s ' % operators[node.op])
1374 self.visit(node.expr, frame)
1375
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001376 def visit_Getattr(self, node, frame):
1377 self.write('environment.getattr(')
1378 self.visit(node.node, frame)
1379 self.write(', %r)' % node.attr)
1380
1381 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001382 # slices bypass the environment getitem method.
1383 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001384 self.visit(node.node, frame)
1385 self.write('[')
1386 self.visit(node.arg, frame)
1387 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001388 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001389 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001390 self.visit(node.node, frame)
1391 self.write(', ')
1392 self.visit(node.arg, frame)
1393 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001394
1395 def visit_Slice(self, node, frame):
1396 if node.start is not None:
1397 self.visit(node.start, frame)
1398 self.write(':')
1399 if node.stop is not None:
1400 self.visit(node.stop, frame)
1401 if node.step is not None:
1402 self.write(':')
1403 self.visit(node.step, frame)
1404
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001405 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001406 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001407 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001408 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001409 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001410 if getattr(func, 'contextfilter', False):
1411 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001412 elif getattr(func, 'environmentfilter', False):
1413 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001414
1415 # if the filter node is None we are inside a filter block
1416 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001417 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001418 self.visit(node.node, frame)
Armin Ronacher3da90312008-05-23 16:37:28 +02001419 elif self.environment.autoescape:
1420 self.write('Markup(concat(%s))' % frame.buffer)
1421 else:
1422 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001423 self.signature(node, frame)
1424 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001425
1426 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001427 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001428 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001429 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001430 self.visit(node.node, frame)
1431 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001432 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001433
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001434 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001435 def write_expr2():
1436 if node.expr2 is not None:
1437 return self.visit(node.expr2, frame)
1438 self.write('environment.undefined(%r)' % ('the inline if-'
1439 'expression on %s evaluated to false and '
1440 'no else section was defined.' % self.position(node)))
1441
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001442 if not have_condexpr:
1443 self.write('((')
1444 self.visit(node.test, frame)
1445 self.write(') and (')
1446 self.visit(node.expr1, frame)
1447 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001448 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001449 self.write(',))[0]')
1450 else:
1451 self.write('(')
1452 self.visit(node.expr1, frame)
1453 self.write(' if ')
1454 self.visit(node.test, frame)
1455 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001456 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001457 self.write(')')
1458
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001459 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001460 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001461 self.write('environment.call(context, ')
1462 else:
1463 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001464 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001465 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001466 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001467 self.write(')')
1468
1469 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001470 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001471 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001472
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001473 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001474
1475 def visit_MarkSafe(self, node, frame):
1476 self.write('Markup(')
1477 self.visit(node.expr, frame)
1478 self.write(')')
1479
1480 def visit_EnvironmentAttribute(self, node, frame):
1481 self.write('environment.' + node.name)
1482
1483 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001484 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001485
1486 def visit_ImportedName(self, node, frame):
1487 self.write(self.import_aliases[node.importname])
1488
1489 def visit_InternalName(self, node, frame):
1490 self.write(node.name)
1491
Armin Ronacher6df604e2008-05-23 22:18:38 +02001492 def visit_ContextReference(self, node, frame):
1493 self.write('context')
1494
Armin Ronachered1e0d42008-05-18 20:25:28 +02001495 def visit_Continue(self, node, frame):
1496 self.writeline('continue', node)
1497
1498 def visit_Break(self, node, frame):
1499 self.writeline('break', node)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001500
1501 def visit_Scope(self, node, frame):
1502 scope_frame = frame.inner()
1503 scope_frame.inspect(node.iter_child_nodes())
1504 aliases = self.push_scope(scope_frame)
1505 self.pull_locals(scope_frame)
1506 self.blockvisit(node.body, scope_frame)
1507 self.pop_scope(aliases, scope_frame)