blob: 33aadc3348df102593bddf0da9a1154e2f0e709f [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 Ronacherf1c421d2009-09-17 00:48:41 +0200268 def visit_If(self, node):
269 self.visit(node.test)
270
271 # remember all the names that are locally assigned in the body
272 old_locals = self.identifiers.declared_locally.copy()
273 for subnode in node.body:
274 self.visit(subnode)
275 body = self.identifiers.declared_locally - old_locals
276
277 # same for else.
278 self.identifiers.declared_locally = old_locals.copy()
279 for subnode in node.else_ or ():
280 self.visit(subnode)
281 else_ = self.identifiers.declared_locally - old_locals
282
283 # the differences between the two branches are also pulled as
284 # undeclared variables
285 self.identifiers.undeclared.update(body.symmetric_difference(else_))
286
287 # declared_locally is currently the set of all variables assigned
288 # in the else part, add the new vars from body as well. That means
289 # that undeclared variables if unbalanced are considered local.
290 self.identifiers.declared_locally.update(body)
291
Armin Ronacherc9705c22008-04-27 21:28:03 +0200292 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200293 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200294
Armin Ronacherc9705c22008-04-27 21:28:03 +0200295 def visit_Import(self, node):
296 self.generic_visit(node)
297 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200298
Armin Ronacherc9705c22008-04-27 21:28:03 +0200299 def visit_FromImport(self, node):
300 self.generic_visit(node)
301 for name in node.names:
302 if isinstance(name, tuple):
303 self.identifiers.declared_locally.add(name[1])
304 else:
305 self.identifiers.declared_locally.add(name)
306
307 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200308 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200309 self.visit(node.node)
310 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200311
Armin Ronacherc9705c22008-04-27 21:28:03 +0200312 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200313 """Visiting stops at for blocks. However the block sequence
314 is visited as part of the outer scope.
315 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200316 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200317
Armin Ronacherc9705c22008-04-27 21:28:03 +0200318 def visit_CallBlock(self, node):
319 for child in node.iter_child_nodes(exclude=('body',)):
320 self.visit(child)
321
322 def visit_FilterBlock(self, node):
323 self.visit(node.filter)
324
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100325 def visit_Scope(self, node):
326 """Stop visiting at scopes."""
327
Armin Ronacherc9705c22008-04-27 21:28:03 +0200328 def visit_Block(self, node):
329 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200330
331
Armin Ronacher75cfb862008-04-11 13:47:22 +0200332class CompilerExit(Exception):
333 """Raised if the compiler encountered a situation where it just
334 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200335 raises such an exception is not further processed.
336 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200337
338
Armin Ronachere791c2a2008-04-07 18:39:54 +0200339class CodeGenerator(NodeVisitor):
340
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200341 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200342 if stream is None:
343 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200344 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200345 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200346 self.filename = filename
347 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200348
Armin Ronacher023b5e92008-05-08 11:03:10 +0200349 # aliases for imports
350 self.import_aliases = {}
351
Armin Ronacherfed44b52008-04-13 19:42:53 +0200352 # a registry for all blocks. Because blocks are moved out
353 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200354 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200355
356 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200357 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200358
359 # some templates have a rootlevel extends. In this case we
360 # can safely assume that we're a child template and do some
361 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200362 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200363
Armin Ronacherba3757b2008-04-16 19:43:16 +0200364 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200365 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200366
Armin Ronacherb9e78752008-05-10 23:36:28 +0200367 # registry of all filters and tests (global, not block local)
368 self.tests = {}
369 self.filters = {}
370
Armin Ronacherba3757b2008-04-16 19:43:16 +0200371 # the debug information
372 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200373 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200374
Armin Ronacherfed44b52008-04-13 19:42:53 +0200375 # the number of new lines before the next write()
376 self._new_lines = 0
377
378 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200379 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200380
381 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200382 self._first_write = True
383
Armin Ronacherfed44b52008-04-13 19:42:53 +0200384 # used by the `temporary_identifier` method to get new
385 # unique, temporary identifier
386 self._last_identifier = 0
387
388 # the current indentation
389 self._indentation = 0
390
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200391 # -- Various compilation helpers
392
Armin Ronachere2244882008-05-19 09:25:57 +0200393 def fail(self, msg, lineno):
394 """Fail with a `TemplateAssertionError`."""
395 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
396
Armin Ronachere791c2a2008-04-07 18:39:54 +0200397 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200398 """Get a new unique identifier."""
399 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200400 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200401
Armin Ronachered1e0d42008-05-18 20:25:28 +0200402 def buffer(self, frame):
403 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200404 frame.buffer = self.temporary_identifier()
405 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200406
407 def return_buffer_contents(self, frame):
408 """Return the buffer contents of the frame."""
409 if self.environment.autoescape:
410 self.writeline('return Markup(concat(%s))' % frame.buffer)
411 else:
412 self.writeline('return concat(%s)' % frame.buffer)
413
Armin Ronachere791c2a2008-04-07 18:39:54 +0200414 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200415 """Indent by one."""
416 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200417
Armin Ronacher8efc5222008-04-08 14:47:40 +0200418 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200419 """Outdent by step."""
420 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200421
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200422 def start_write(self, frame, node=None):
423 """Yield or write into the frame buffer."""
424 if frame.buffer is None:
425 self.writeline('yield ', node)
426 else:
427 self.writeline('%s.append(' % frame.buffer, node)
428
429 def end_write(self, frame):
430 """End the writing process started by `start_write`."""
431 if frame.buffer is not None:
432 self.write(')')
433
434 def simple_write(self, s, frame, node=None):
435 """Simple shortcut for start_write + write + end_write."""
436 self.start_write(frame, node)
437 self.write(s)
438 self.end_write(frame)
439
Armin Ronacherf40c8842008-09-17 18:51:26 +0200440 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200441 """Visit a list of nodes as block in a frame. If the current frame
442 is no buffer a dummy ``if 0: yield None`` is written automatically
443 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200444 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200445 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200446 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200447 else:
448 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200449 try:
450 for node in nodes:
451 self.visit(node, frame)
452 except CompilerExit:
453 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200454
455 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200456 """Write a string into the output stream."""
457 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200458 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200459 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200460 self.code_lineno += self._new_lines
461 if self._write_debug_info is not None:
462 self.debug_info.append((self._write_debug_info,
463 self.code_lineno))
464 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200465 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200466 self.stream.write(' ' * self._indentation)
467 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200468 self.stream.write(x)
469
470 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200471 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200472 self.newline(node, extra)
473 self.write(x)
474
475 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200476 """Add one or more newlines before the next write."""
477 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200478 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200479 self._write_debug_info = node.lineno
480 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200481
Armin Ronacherfd310492008-05-25 00:16:51 +0200482 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200483 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200484 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200485 arguments may not include python keywords otherwise a syntax
486 error could occour. The extra keyword arguments should be given
487 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200488 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200489 # if any of the given keyword arguments is a python keyword
490 # we have to make sure that no invalid call is created.
491 kwarg_workaround = False
492 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200493 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200494 kwarg_workaround = True
495 break
496
Armin Ronacher8efc5222008-04-08 14:47:40 +0200497 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200498 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200499 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200500
501 if not kwarg_workaround:
502 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200503 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200504 self.visit(kwarg, frame)
505 if extra_kwargs is not None:
506 for key, value in extra_kwargs.iteritems():
Armin Ronacherfd310492008-05-25 00:16:51 +0200507 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200508 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200509 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200510 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200511
512 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200513 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200514 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200515 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200516 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200517 for kwarg in node.kwargs:
518 self.write('%r: ' % kwarg.key)
519 self.visit(kwarg.value, frame)
520 self.write(', ')
521 if extra_kwargs is not None:
522 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200523 self.write('%r: %s, ' % (key, value))
524 if node.dyn_kwargs is not None:
525 self.write('}, **')
526 self.visit(node.dyn_kwargs, frame)
527 self.write(')')
528 else:
529 self.write('}')
530
531 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200532 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200533 self.visit(node.dyn_kwargs, frame)
534
Armin Ronacherc9705c22008-04-27 21:28:03 +0200535 def pull_locals(self, frame):
536 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200537 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200538 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200539
540 def pull_dependencies(self, nodes):
541 """Pull all the dependencies."""
542 visitor = DependencyFinderVisitor()
543 for node in nodes:
544 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200545 for dependency in 'filters', 'tests':
546 mapping = getattr(self, dependency)
547 for name in getattr(visitor, dependency):
548 if name not in mapping:
549 mapping[name] = self.temporary_identifier()
550 self.writeline('%s = environment.%s[%r]' %
551 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200552
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100553 def unoptimize_scope(self, frame):
554 """Disable Python optimizations for the frame."""
555 # XXX: this is not that nice but it has no real overhead. It
556 # mainly works because python finds the locals before dead code
557 # is removed. If that breaks we have to add a dummy function
558 # that just accepts the arguments and does nothing.
559 if frame.identifiers.declared:
560 self.writeline('if 0: dummy(%s)' % ', '.join(
561 'l_' + name for name in frame.identifiers.declared))
562
Armin Ronacher673aa882008-10-04 18:06:57 +0200563 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200564 """This function returns all the shadowed variables in a dict
565 in the form name: alias and will write the required assignments
566 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200567
Armin Ronacher673aa882008-10-04 18:06:57 +0200568 This also predefines locally declared variables from the loop
569 body because under some circumstances it may be the case that
570
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100571 `extra_vars` is passed to `Frame.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200572 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200573 aliases = {}
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100574 for name in frame.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200575 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200576 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200577 to_declare = set()
578 for name in frame.identifiers.declared_locally:
579 if name not in aliases:
580 to_declare.add('l_' + name)
581 if to_declare:
582 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200583 return aliases
584
Armin Ronacher673aa882008-10-04 18:06:57 +0200585 def pop_scope(self, aliases, frame):
586 """Restore all aliases and delete unused variables."""
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200587 for name, alias in aliases.iteritems():
588 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200589 to_delete = set()
590 for name in frame.identifiers.declared_locally:
591 if name not in aliases:
592 to_delete.add('l_' + name)
593 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100594 # we cannot use the del statement here because enclosed
595 # scopes can trigger a SyntaxError:
596 # a = 42; b = lambda: a; del a
597 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200598
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200599 def function_scoping(self, node, frame, children=None,
600 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200601 """In Jinja a few statements require the help of anonymous
602 functions. Those are currently macros and call blocks and in
603 the future also recursive loops. As there is currently
604 technical limitation that doesn't allow reading and writing a
605 variable in a scope where the initial value is coming from an
606 outer scope, this function tries to fall back with a common
607 error message. Additionally the frame passed is modified so
608 that the argumetns are collected and callers are looked up.
609
610 This will return the modified frame.
611 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200612 # we have to iterate twice over it, make sure that works
613 if children is None:
614 children = node.iter_child_nodes()
615 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200616 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200617 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200618
619 # variables that are undeclared (accessed before declaration) and
620 # declared locally *and* part of an outside scope raise a template
621 # assertion error. Reason: we can't generate reasonable code from
Armin Ronacher02b42a82009-03-18 00:59:32 +0100622 # it without aliasing all the variables.
623 # this could be fixed in Python 3 where we have the nonlocal
624 # keyword or if we switch to bytecode generation
Armin Ronacher71082072008-04-12 14:19:36 +0200625 overriden_closure_vars = (
626 func_frame.identifiers.undeclared &
627 func_frame.identifiers.declared &
628 (func_frame.identifiers.declared_locally |
629 func_frame.identifiers.declared_parameter)
630 )
631 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200632 self.fail('It\'s not possible to set and access variables '
Armin Ronacherefcc0e52009-09-13 00:22:50 -0700633 'derived from an outer scope! (affects: %s)' %
Armin Ronachere2244882008-05-19 09:25:57 +0200634 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200635
636 # remove variables from a closure from the frame's undeclared
637 # identifiers.
638 func_frame.identifiers.undeclared -= (
639 func_frame.identifiers.undeclared &
640 func_frame.identifiers.declared
641 )
642
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200643 # no special variables for this scope, abort early
644 if not find_special:
645 return func_frame
646
Armin Ronacher963f97d2008-04-25 11:44:59 +0200647 func_frame.accesses_kwargs = False
648 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200649 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200650 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200651
Armin Ronacherc9705c22008-04-27 21:28:03 +0200652 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
653
654 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200655 func_frame.accesses_caller = True
656 func_frame.identifiers.add_special('caller')
657 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200658 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200659 func_frame.accesses_kwargs = True
660 func_frame.identifiers.add_special('kwargs')
661 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200662 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200663 func_frame.accesses_varargs = True
664 func_frame.identifiers.add_special('varargs')
665 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200666 return func_frame
667
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200668 def macro_body(self, node, frame, children=None):
669 """Dump the function def of a macro or call block."""
670 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100671 # macros are delayed, they never require output checks
672 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200673 args = frame.arguments
Armin Ronachereabf3dd2009-09-12 23:48:18 -0700674 # XXX: this is an ugly fix for the loop nesting bug
675 # (tests.test_old_bugs.test_loop_call_bug). This works around
676 # a identifier nesting problem we have in general. It's just more
677 # likely to happen in loops which is why we work around it. The
678 # real solution would be "nonlocal" all the identifiers that are
679 # leaking into a new python frame and might be used both unassigned
680 # and assigned.
681 if 'loop' in frame.identifiers.declared:
Armin Ronacherb4044392009-09-13 15:56:58 -0700682 args = args + ['l_loop=l_loop']
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200683 self.writeline('def macro(%s):' % ', '.join(args), node)
684 self.indent()
685 self.buffer(frame)
686 self.pull_locals(frame)
687 self.blockvisit(node.body, frame)
688 self.return_buffer_contents(frame)
689 self.outdent()
690 return frame
691
692 def macro_def(self, node, frame):
693 """Dump the macro definition for the def created by macro_body."""
694 arg_tuple = ', '.join(repr(x.name) for x in node.args)
695 name = getattr(node, 'name', None)
696 if len(node.args) == 1:
697 arg_tuple += ','
698 self.write('Macro(environment, macro, %r, (%s), (' %
699 (name, arg_tuple))
700 for arg in node.defaults:
701 self.visit(arg, frame)
702 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200703 self.write('), %r, %r, %r)' % (
704 bool(frame.accesses_kwargs),
705 bool(frame.accesses_varargs),
706 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200707 ))
708
Armin Ronacher547d0b62008-07-04 16:35:10 +0200709 def position(self, node):
710 """Return a human readable position for the node."""
711 rv = 'line %d' % node.lineno
712 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100713 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200714 return rv
715
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200716 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200717
718 def visit_Template(self, node, frame=None):
719 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200720 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200721 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200722 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8edbe492008-04-10 20:43:43 +0200723
Armin Ronacher75cfb862008-04-11 13:47:22 +0200724 # do we have an extends tag at all? If not, we can save some
725 # overhead by just not processing any inheritance code.
726 have_extends = node.find(nodes.Extends) is not None
727
Armin Ronacher8edbe492008-04-10 20:43:43 +0200728 # find all blocks
729 for block in node.find_all(nodes.Block):
730 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200731 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200732 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200733
Armin Ronacher023b5e92008-05-08 11:03:10 +0200734 # find all imports and import them
735 for import_ in node.find_all(nodes.ImportedName):
736 if import_.importname not in self.import_aliases:
737 imp = import_.importname
738 self.import_aliases[imp] = alias = self.temporary_identifier()
739 if '.' in imp:
740 module, obj = imp.rsplit('.', 1)
741 self.writeline('from %s import %s as %s' %
742 (module, obj, alias))
743 else:
744 self.writeline('import %s as %s' % (imp, alias))
745
746 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200747 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200748
Armin Ronacher8efc5222008-04-08 14:47:40 +0200749 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200750 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200751
752 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200753 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200754 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200755 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200756 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200757 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200758 if have_extends:
759 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200760 if 'self' in find_undeclared(node.body, ('self',)):
761 frame.identifiers.add_special('self')
762 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200763 self.pull_locals(frame)
764 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200765 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200766 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200767
Armin Ronacher8efc5222008-04-08 14:47:40 +0200768 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200769 if have_extends:
770 if not self.has_known_extends:
771 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200772 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200773 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200774 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200775 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200776 self.indent()
777 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200778 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200779
780 # at this point we now have the blocks collected and can visit them too.
781 for name, block in self.blocks.iteritems():
782 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200783 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200784 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200785 self.writeline('def block_%s(context, environment=environment):'
786 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200787 self.indent()
788 undeclared = find_undeclared(block.body, ('self', 'super'))
789 if 'self' in undeclared:
790 block_frame.identifiers.add_special('self')
791 self.writeline('l_self = TemplateReference(context)')
792 if 'super' in undeclared:
793 block_frame.identifiers.add_special('super')
794 self.writeline('l_super = context.super(%r, '
795 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200796 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200797 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200798 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200799 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200800
Armin Ronacher75cfb862008-04-11 13:47:22 +0200801 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200802 for x in self.blocks),
803 extra=1)
804
805 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200806 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
807 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200808
Armin Ronachere791c2a2008-04-07 18:39:54 +0200809 def visit_Block(self, node, frame):
810 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200811 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200812 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200813 # if we know that we are a child template, there is no need to
814 # check if we are one
815 if self.has_known_extends:
816 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200817 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200818 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200819 self.indent()
820 level += 1
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100821 if node.scoped:
822 context = 'context.derived(locals())'
823 else:
824 context = 'context'
825 self.writeline('for event in context.blocks[%r][0](%s):' % (
826 node.name, context), node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200827 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200828 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200829 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200830
831 def visit_Extends(self, node, frame):
832 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200833 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200834 self.fail('cannot use extend from a non top-level scope',
835 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200836
Armin Ronacher7fb38972008-04-11 13:54:28 +0200837 # if the number of extends statements in general is zero so
838 # far, we don't have to add a check if something extended
839 # the template before this one.
840 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200841
Armin Ronacher7fb38972008-04-11 13:54:28 +0200842 # if we have a known extends we just add a template runtime
843 # error into the generated code. We could catch that at compile
844 # time too, but i welcome it not to confuse users by throwing the
845 # same error at different times just "because we can".
846 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200847 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200848 self.indent()
849 self.writeline('raise TemplateRuntimeError(%r)' %
850 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200851 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200852
Armin Ronacher7fb38972008-04-11 13:54:28 +0200853 # if we have a known extends already we don't need that code here
854 # as we know that the template execution will end here.
855 if self.has_known_extends:
856 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200857
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200858 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200859 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200860 self.write(', %r)' % self.name)
861 self.writeline('for name, parent_block in parent_template.'
862 'blocks.iteritems():')
863 self.indent()
864 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200865 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200866 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200867
868 # if this extends statement was in the root level we can take
869 # advantage of that information and simplify the generated code
870 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200871 if frame.rootlevel:
872 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200873
Armin Ronacher7fb38972008-04-11 13:54:28 +0200874 # and now we have one more
875 self.extends_so_far += 1
876
Armin Ronacherf059ec12008-04-11 22:21:00 +0200877 def visit_Include(self, node, frame):
878 """Handles includes."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100879 if node.with_context:
880 self.unoptimize_scope(frame)
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100881 if node.ignore_missing:
882 self.writeline('try:')
883 self.indent()
884 self.writeline('template = environment.get_template(', node)
885 self.visit(node.template, frame)
886 self.write(', %r)' % self.name)
887 if node.ignore_missing:
888 self.outdent()
889 self.writeline('except TemplateNotFound:')
890 self.indent()
891 self.writeline('pass')
892 self.outdent()
893 self.writeline('else:')
894 self.indent()
895
Armin Ronacherea847c52008-05-02 20:04:32 +0200896 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200897 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200898 'template.new_context(context.parent, True, '
899 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200900 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100901 self.writeline('for event in template.module._body_stream:')
902
Armin Ronacherf059ec12008-04-11 22:21:00 +0200903 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200904 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200905 self.outdent()
906
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100907 if node.ignore_missing:
908 self.outdent()
909
Armin Ronacher0611e492008-04-25 23:44:14 +0200910 def visit_Import(self, node, frame):
911 """Visit regular imports."""
Armin Ronacher7887a8c2009-02-08 19:11:44 +0100912 if node.with_context:
913 self.unoptimize_scope(frame)
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200914 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200915 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200916 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200917 self.write('environment.get_template(')
918 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200919 self.write(', %r).' % self.name)
920 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200921 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200922 else:
923 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200924 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200925 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100926 frame.assigned_names.add(node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200927
928 def visit_FromImport(self, node, frame):
929 """Visit named imports."""
930 self.newline(node)
931 self.write('included_template = environment.get_template(')
932 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200933 self.write(', %r).' % self.name)
934 if node.with_context:
935 self.write('make_module(context.parent, True)')
936 else:
937 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200938
939 var_names = []
940 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200941 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200942 if isinstance(name, tuple):
943 name, alias = name
944 else:
945 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200946 self.writeline('l_%s = getattr(included_template, '
947 '%r, missing)' % (alias, name))
948 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200949 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200950 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +0200951 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200952 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +0200953 (alias, 'the template %%r (imported on %s) does '
954 'not export the requested name %s' % (
955 self.position(node),
956 repr(name)
957 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +0200958 self.outdent()
959 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +0200960 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +0200961 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +0200962 discarded_names.append(alias)
Armin Ronacher271a0eb2009-02-11 22:49:08 +0100963 frame.assigned_names.add(alias)
Armin Ronachera78d2762008-05-15 23:18:07 +0200964
965 if var_names:
966 if len(var_names) == 1:
967 name = var_names[0]
968 self.writeline('context.vars[%r] = l_%s' % (name, name))
969 else:
970 self.writeline('context.vars.update({%s})' % ', '.join(
971 '%r: l_%s' % (name, name) for name in var_names
972 ))
973 if discarded_names:
974 if len(discarded_names) == 1:
975 self.writeline('context.exported_vars.discard(%r)' %
976 discarded_names[0])
977 else:
978 self.writeline('context.exported_vars.difference_'
979 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200980
Armin Ronachere791c2a2008-04-07 18:39:54 +0200981 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200982 # when calculating the nodes for the inner frame we have to exclude
983 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200984 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200985 if node.recursive:
986 loop_frame = self.function_scoping(node, frame, children,
987 find_special=False)
988 else:
989 loop_frame = frame.inner()
990 loop_frame.inspect(children)
991
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200992 # try to figure out if we have an extended loop. An extended loop
993 # is necessary if the loop is in recursive mode if the special loop
994 # variable is accessed in the body.
995 extended_loop = node.recursive or 'loop' in \
996 find_undeclared(node.iter_child_nodes(
997 only=('body',)), ('loop',))
998
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200999 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +02001000 # variables at that point. Because loops can be nested but the loop
1001 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001002 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +02001003 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001004
1005 # otherwise we set up a buffer and add a function def
1006 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001007 self.writeline('def loop(reciter, loop_render_func):', node)
1008 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +02001009 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001010 aliases = {}
1011
Armin Ronacherff53c782008-08-13 18:55:50 +02001012 # make sure the loop variable is a special one and raise a template
1013 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +02001014 if extended_loop:
1015 loop_frame.identifiers.add_special('loop')
Armin Ronacherff53c782008-08-13 18:55:50 +02001016 for name in node.find_all(nodes.Name):
1017 if name.ctx == 'store' and name.name == 'loop':
1018 self.fail('Can\'t assign to special loop variable '
1019 'in for-loop target', name.lineno)
1020
Armin Ronacherc9705c22008-04-27 21:28:03 +02001021 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001022 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001023 iteration_indicator = self.temporary_identifier()
1024 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001025
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001026 # Create a fake parent loop if the else or test section of a
1027 # loop is accessing the special loop variable and no parent loop
1028 # exists.
1029 if 'loop' not in aliases and 'loop' in find_undeclared(
1030 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1031 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +02001032 ("'loop' is undefined. the filter section of a loop as well "
1033 "as the else block doesn't have access to the special 'loop'"
1034 " variable of the current loop. Because there is no parent "
1035 "loop it's undefined. Happened in loop on %s" %
1036 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001037
1038 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001039 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +02001040 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001041
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001042 # if we have an extened loop and a node test, we filter in the
1043 # "outer frame".
1044 if extended_loop and node.test is not None:
1045 self.write('(')
1046 self.visit(node.target, loop_frame)
1047 self.write(' for ')
1048 self.visit(node.target, loop_frame)
1049 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001050 if node.recursive:
1051 self.write('reciter')
1052 else:
1053 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001054 self.write(' if (')
1055 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001056 self.visit(node.test, test_frame)
1057 self.write('))')
1058
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001059 elif node.recursive:
1060 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001061 else:
1062 self.visit(node.iter, loop_frame)
1063
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001064 if node.recursive:
1065 self.write(', recurse=loop_render_func):')
1066 else:
1067 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001068
1069 # tests in not extended loops become a continue
1070 if not extended_loop and node.test is not None:
1071 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +02001072 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +02001073 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001074 self.write(':')
1075 self.indent()
1076 self.writeline('continue')
1077 self.outdent(2)
1078
Armin Ronacherc9705c22008-04-27 21:28:03 +02001079 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001080 self.blockvisit(node.body, loop_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001081 if node.else_:
1082 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001083 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001084
1085 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001086 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001087 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001088 self.blockvisit(node.else_, loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001089 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001090
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001091 # reset the aliases if there are any.
Armin Ronachercebd8382008-12-25 18:33:46 +01001092 if not node.recursive:
1093 self.pop_scope(aliases, loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001094
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001095 # if the node was recursive we have to return the buffer contents
1096 # and start the iteration code
1097 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001098 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001099 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001100 self.start_write(frame, node)
1101 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001102 self.visit(node.iter, frame)
1103 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001104 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001105
Armin Ronachere791c2a2008-04-07 18:39:54 +02001106 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001107 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001108 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001109 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001110 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001111 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001112 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001113 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001114 if node.else_:
1115 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001116 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001117 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001118 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001119
Armin Ronacher8efc5222008-04-08 14:47:40 +02001120 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001121 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001122 self.newline()
1123 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001124 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001125 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001126 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001127 self.write('l_%s = ' % node.name)
1128 self.macro_def(node, macro_frame)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001129 frame.assigned_names.add(node.name)
Armin Ronacher71082072008-04-12 14:19:36 +02001130
1131 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001132 children = node.iter_child_nodes(exclude=('call',))
1133 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001134 self.writeline('caller = ')
1135 self.macro_def(node, call_frame)
1136 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001137 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001138 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001139
1140 def visit_FilterBlock(self, node, frame):
1141 filter_frame = frame.inner()
1142 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacher673aa882008-10-04 18:06:57 +02001143 aliases = self.push_scope(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001144 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001145 self.buffer(filter_frame)
Armin Ronacherf40c8842008-09-17 18:51:26 +02001146 self.blockvisit(node.body, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001147 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001148 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001149 self.end_write(frame)
Armin Ronacher673aa882008-10-04 18:06:57 +02001150 self.pop_scope(aliases, filter_frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001151
Armin Ronachere791c2a2008-04-07 18:39:54 +02001152 def visit_ExprStmt(self, node, frame):
1153 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001154 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001155
1156 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001157 # if we have a known extends statement, we don't output anything
Armin Ronacher79668952008-09-23 22:52:46 +02001158 # if we are in a require_output_check section
1159 if self.has_known_extends and frame.require_output_check:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001160 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001161
Armin Ronacher665bfb82008-07-14 13:41:46 +02001162 if self.environment.finalize:
1163 finalize = lambda x: unicode(self.environment.finalize(x))
1164 else:
1165 finalize = unicode
1166
Armin Ronacher75cfb862008-04-11 13:47:22 +02001167 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001168
Armin Ronacher79668952008-09-23 22:52:46 +02001169 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001170 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001171 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001172 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001173 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001174 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001175
Armin Ronachere791c2a2008-04-07 18:39:54 +02001176 # try to evaluate as many chunks as possible into a static
1177 # string at compile time.
1178 body = []
1179 for child in node.nodes:
1180 try:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001181 const = child.as_const()
1182 except nodes.Impossible:
1183 body.append(child)
1184 continue
1185 try:
1186 if self.environment.autoescape:
1187 if hasattr(const, '__html__'):
1188 const = const.__html__()
1189 else:
1190 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001191 const = finalize(const)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001192 except:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001193 # if something goes wrong here we evaluate the node
1194 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001195 body.append(child)
1196 continue
1197 if body and isinstance(body[-1], list):
1198 body[-1].append(const)
1199 else:
1200 body.append([const])
1201
Armin Ronachered1e0d42008-05-18 20:25:28 +02001202 # if we have less than 3 nodes or a buffer we yield or extend/append
1203 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001204 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001205 # for one item we append, for more we extend
1206 if len(body) == 1:
1207 self.writeline('%s.append(' % frame.buffer)
1208 else:
1209 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001210 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001211 for item in body:
1212 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001213 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001214 if frame.buffer is None:
1215 self.writeline('yield ' + val)
1216 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001217 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001218 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001219 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001220 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001221 else:
1222 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001223 close = 1
1224 if self.environment.autoescape:
1225 self.write('escape(')
1226 else:
Armin Ronacherbd357722009-08-05 20:25:06 +02001227 self.write('to_string(')
Armin Ronacherd1342312008-04-28 12:20:12 +02001228 if self.environment.finalize is not None:
1229 self.write('environment.finalize(')
1230 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001231 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001232 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001233 if frame.buffer is not None:
1234 self.write(', ')
1235 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001236 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001237 self.outdent()
1238 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001239
1240 # otherwise we create a format string as this is faster in that case
1241 else:
1242 format = []
1243 arguments = []
1244 for item in body:
1245 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001246 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001247 else:
1248 format.append('%s')
1249 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001250 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001251 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001252 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001253 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001254 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001255 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001256 close = 0
1257 if self.environment.autoescape:
1258 self.write('escape(')
1259 close += 1
1260 if self.environment.finalize is not None:
1261 self.write('environment.finalize(')
1262 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001263 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001264 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001265 self.outdent()
1266 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001267
Armin Ronacher7fb38972008-04-11 13:54:28 +02001268 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001269 self.outdent()
1270
Armin Ronacher8efc5222008-04-08 14:47:40 +02001271 def visit_Assign(self, node, frame):
1272 self.newline(node)
1273 # toplevel assignments however go into the local namespace and
1274 # the current template's context. We create a copy of the frame
1275 # here and add a set so that the Name visitor can add the assigned
1276 # names here.
1277 if frame.toplevel:
1278 assignment_frame = frame.copy()
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001279 assignment_frame.toplevel_assignments = set()
Armin Ronacher8efc5222008-04-08 14:47:40 +02001280 else:
1281 assignment_frame = frame
1282 self.visit(node.target, assignment_frame)
1283 self.write(' = ')
1284 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001285
1286 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001287 if frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001288 public_names = [x for x in assignment_frame.toplevel_assignments
Armin Ronacher903d1682008-05-23 00:51:58 +02001289 if not x.startswith('_')]
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001290 if len(assignment_frame.toplevel_assignments) == 1:
Armin Ronacherbd357722009-08-05 20:25:06 +02001291 name = next(iter(assignment_frame.toplevel_assignments))
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001292 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001293 else:
1294 self.writeline('context.vars.update({')
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001295 for idx, name in enumerate(assignment_frame.toplevel_assignments):
Armin Ronacher69e12db2008-05-12 09:00:03 +02001296 if idx:
1297 self.write(', ')
1298 self.write('%r: l_%s' % (name, name))
1299 self.write('})')
1300 if public_names:
1301 if len(public_names) == 1:
1302 self.writeline('context.exported_vars.add(%r)' %
1303 public_names[0])
1304 else:
1305 self.writeline('context.exported_vars.update((%s))' %
1306 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001307
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001308 # -- Expression Visitors
1309
Armin Ronachere791c2a2008-04-07 18:39:54 +02001310 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001311 if node.ctx == 'store' and frame.toplevel:
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001312 frame.toplevel_assignments.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001313 self.write('l_' + node.name)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001314 frame.assigned_names.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001315
1316 def visit_Const(self, node, frame):
1317 val = node.value
1318 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001319 self.write(str(val))
1320 else:
1321 self.write(repr(val))
1322
Armin Ronacher5411ce72008-05-25 11:36:22 +02001323 def visit_TemplateData(self, node, frame):
1324 self.write(repr(node.as_const()))
1325
Armin Ronacher8efc5222008-04-08 14:47:40 +02001326 def visit_Tuple(self, node, frame):
1327 self.write('(')
1328 idx = -1
1329 for idx, item in enumerate(node.items):
1330 if idx:
1331 self.write(', ')
1332 self.visit(item, frame)
1333 self.write(idx == 0 and ',)' or ')')
1334
Armin Ronacher8edbe492008-04-10 20:43:43 +02001335 def visit_List(self, node, frame):
1336 self.write('[')
1337 for idx, item in enumerate(node.items):
1338 if idx:
1339 self.write(', ')
1340 self.visit(item, frame)
1341 self.write(']')
1342
1343 def visit_Dict(self, node, frame):
1344 self.write('{')
1345 for idx, item in enumerate(node.items):
1346 if idx:
1347 self.write(', ')
1348 self.visit(item.key, frame)
1349 self.write(': ')
1350 self.visit(item.value, frame)
1351 self.write('}')
1352
Armin Ronachere791c2a2008-04-07 18:39:54 +02001353 def binop(operator):
1354 def visitor(self, node, frame):
1355 self.write('(')
1356 self.visit(node.left, frame)
1357 self.write(' %s ' % operator)
1358 self.visit(node.right, frame)
1359 self.write(')')
1360 return visitor
1361
1362 def uaop(operator):
1363 def visitor(self, node, frame):
1364 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001365 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001366 self.write(')')
1367 return visitor
1368
1369 visit_Add = binop('+')
1370 visit_Sub = binop('-')
1371 visit_Mul = binop('*')
1372 visit_Div = binop('/')
1373 visit_FloorDiv = binop('//')
1374 visit_Pow = binop('**')
1375 visit_Mod = binop('%')
1376 visit_And = binop('and')
1377 visit_Or = binop('or')
1378 visit_Pos = uaop('+')
1379 visit_Neg = uaop('-')
1380 visit_Not = uaop('not ')
1381 del binop, uaop
1382
Armin Ronacherd1342312008-04-28 12:20:12 +02001383 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001384 self.write('%s((' % (self.environment.autoescape and
1385 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001386 for arg in node.nodes:
1387 self.visit(arg, frame)
1388 self.write(', ')
1389 self.write('))')
1390
Armin Ronachere791c2a2008-04-07 18:39:54 +02001391 def visit_Compare(self, node, frame):
1392 self.visit(node.expr, frame)
1393 for op in node.ops:
1394 self.visit(op, frame)
1395
1396 def visit_Operand(self, node, frame):
1397 self.write(' %s ' % operators[node.op])
1398 self.visit(node.expr, frame)
1399
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001400 def visit_Getattr(self, node, frame):
1401 self.write('environment.getattr(')
1402 self.visit(node.node, frame)
1403 self.write(', %r)' % node.attr)
1404
1405 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001406 # slices bypass the environment getitem method.
1407 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001408 self.visit(node.node, frame)
1409 self.write('[')
1410 self.visit(node.arg, frame)
1411 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001412 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001413 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001414 self.visit(node.node, frame)
1415 self.write(', ')
1416 self.visit(node.arg, frame)
1417 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001418
1419 def visit_Slice(self, node, frame):
1420 if node.start is not None:
1421 self.visit(node.start, frame)
1422 self.write(':')
1423 if node.stop is not None:
1424 self.visit(node.stop, frame)
1425 if node.step is not None:
1426 self.write(':')
1427 self.visit(node.step, frame)
1428
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001429 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001430 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001431 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001432 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001433 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001434 if getattr(func, 'contextfilter', False):
1435 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001436 elif getattr(func, 'environmentfilter', False):
1437 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001438
1439 # if the filter node is None we are inside a filter block
1440 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001441 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001442 self.visit(node.node, frame)
Armin Ronacher3da90312008-05-23 16:37:28 +02001443 elif self.environment.autoescape:
1444 self.write('Markup(concat(%s))' % frame.buffer)
1445 else:
1446 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001447 self.signature(node, frame)
1448 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001449
1450 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001451 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001452 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001453 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001454 self.visit(node.node, frame)
1455 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001456 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001457
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001458 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001459 def write_expr2():
1460 if node.expr2 is not None:
1461 return self.visit(node.expr2, frame)
1462 self.write('environment.undefined(%r)' % ('the inline if-'
1463 'expression on %s evaluated to false and '
1464 'no else section was defined.' % self.position(node)))
1465
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001466 if not have_condexpr:
1467 self.write('((')
1468 self.visit(node.test, frame)
1469 self.write(') and (')
1470 self.visit(node.expr1, frame)
1471 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001472 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001473 self.write(',))[0]')
1474 else:
1475 self.write('(')
1476 self.visit(node.expr1, frame)
1477 self.write(' if ')
1478 self.visit(node.test, frame)
1479 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001480 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001481 self.write(')')
1482
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001483 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001484 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001485 self.write('environment.call(context, ')
1486 else:
1487 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001488 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001489 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001490 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001491 self.write(')')
1492
1493 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001494 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001495 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001496
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001497 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001498
1499 def visit_MarkSafe(self, node, frame):
1500 self.write('Markup(')
1501 self.visit(node.expr, frame)
1502 self.write(')')
1503
1504 def visit_EnvironmentAttribute(self, node, frame):
1505 self.write('environment.' + node.name)
1506
1507 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001508 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001509
1510 def visit_ImportedName(self, node, frame):
1511 self.write(self.import_aliases[node.importname])
1512
1513 def visit_InternalName(self, node, frame):
1514 self.write(node.name)
1515
Armin Ronacher6df604e2008-05-23 22:18:38 +02001516 def visit_ContextReference(self, node, frame):
1517 self.write('context')
1518
Armin Ronachered1e0d42008-05-18 20:25:28 +02001519 def visit_Continue(self, node, frame):
1520 self.writeline('continue', node)
1521
1522 def visit_Break(self, node, frame):
1523 self.writeline('break', node)
Armin Ronacher271a0eb2009-02-11 22:49:08 +01001524
1525 def visit_Scope(self, node, frame):
1526 scope_frame = frame.inner()
1527 scope_frame.inspect(node.iter_child_nodes())
1528 aliases = self.push_scope(scope_frame)
1529 self.pull_locals(scope_frame)
1530 self.blockvisit(node.body, scope_frame)
1531 self.pop_scope(aliases, scope_frame)