blob: 8d605c725b675307ac85e93b885b9e2d056aaab1 [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 Ronacher9a0078d2008-08-13 18:24:17 +020016from jinja2.utils import Markup, concat, escape, is_python_keyword
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 Ronacherff53c782008-08-13 18:55:50 +0200118 def find_shadowed(self, extra=()):
119 """Find all the shadowed names. extra is an iterable of variables
120 that may be defined with `add_special` which may occour scoped.
121 """
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200122 return (self.declared | self.outer_undeclared) & \
Armin Ronacherff53c782008-08-13 18:55:50 +0200123 (self.declared_locally | self.declared_parameter) | \
124 set(x for x in extra if self.is_declared(x))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200125
126
127class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200128 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200129
130 def __init__(self, parent=None):
131 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200132
Armin Ronacher75cfb862008-04-11 13:47:22 +0200133 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200134 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200135
Armin Ronacher75cfb862008-04-11 13:47:22 +0200136 # the root frame is basically just the outermost frame, so no if
137 # conditions. This information is used to optimize inheritance
138 # situations.
139 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200140
Armin Ronacher79668952008-09-23 22:52:46 +0200141 # in some dynamic inheritance situations the compiler needs to add
142 # write tests around output statements.
143 self.require_output_check = parent and parent.require_output_check
Armin Ronacherf40c8842008-09-17 18:51:26 +0200144
Armin Ronacherfed44b52008-04-13 19:42:53 +0200145 # inside some tags we are using a buffer rather than yield statements.
146 # this for example affects {% filter %} or {% macro %}. If a frame
147 # is buffered this variable points to the name of the list used as
148 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200149 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200150
Armin Ronacherfed44b52008-04-13 19:42:53 +0200151 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200152 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200153
154 # the parent of this frame
155 self.parent = parent
156
Armin Ronachere791c2a2008-04-07 18:39:54 +0200157 if parent is not None:
158 self.identifiers.declared.update(
159 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200160 parent.identifiers.declared_locally |
Armin Ronacherb3a1fcf2008-05-15 11:04:14 +0200161 parent.identifiers.declared_parameter |
162 parent.identifiers.undeclared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200163 )
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200164 self.identifiers.outer_undeclared.update(
165 parent.identifiers.undeclared -
166 self.identifiers.declared
167 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200168 self.buffer = parent.buffer
Armin Ronachere791c2a2008-04-07 18:39:54 +0200169
Armin Ronacher8efc5222008-04-08 14:47:40 +0200170 def copy(self):
171 """Create a copy of the current one."""
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200172 rv = object.__new__(self.__class__)
173 rv.__dict__.update(self.__dict__)
174 rv.identifiers = object.__new__(self.identifiers.__class__)
175 rv.identifiers.__dict__.update(self.identifiers.__dict__)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200176 return rv
177
Armin Ronacherc9705c22008-04-27 21:28:03 +0200178 def inspect(self, nodes, hard_scope=False):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200179 """Walk the node and check for identifiers. If the scope is hard (eg:
180 enforce on a python level) overrides from outer scopes are tracked
181 differently.
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200182 """
183 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200184 for node in nodes:
Armin Ronacherc9705c22008-04-27 21:28:03 +0200185 visitor.visit(node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200186
187 def inner(self):
188 """Return an inner frame."""
189 return Frame(self)
190
Armin Ronacher75cfb862008-04-11 13:47:22 +0200191 def soft(self):
192 """Return a soft frame. A soft frame may not be modified as
193 standalone thing as it shares the resources with the frame it
194 was created of, but it's not a rootlevel frame any longer.
195 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200196 rv = self.copy()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200197 rv.rootlevel = False
198 return rv
199
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200200 __copy__ = copy
201
Armin Ronachere791c2a2008-04-07 18:39:54 +0200202
Armin Ronacherc9705c22008-04-27 21:28:03 +0200203class VisitorExit(RuntimeError):
204 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
205
206
207class DependencyFinderVisitor(NodeVisitor):
208 """A visitor that collects filter and test calls."""
209
210 def __init__(self):
211 self.filters = set()
212 self.tests = set()
213
214 def visit_Filter(self, node):
215 self.generic_visit(node)
216 self.filters.add(node.name)
217
218 def visit_Test(self, node):
219 self.generic_visit(node)
220 self.tests.add(node.name)
221
222 def visit_Block(self, node):
223 """Stop visiting at blocks."""
224
225
226class UndeclaredNameVisitor(NodeVisitor):
227 """A visitor that checks if a name is accessed without being
228 declared. This is different from the frame visitor as it will
229 not stop at closure frames.
230 """
231
232 def __init__(self, names):
233 self.names = set(names)
234 self.undeclared = set()
235
236 def visit_Name(self, node):
237 if node.ctx == 'load' and node.name in self.names:
238 self.undeclared.add(node.name)
239 if self.undeclared == self.names:
240 raise VisitorExit()
241 else:
242 self.names.discard(node.name)
243
244 def visit_Block(self, node):
245 """Stop visiting a blocks."""
246
247
Armin Ronachere791c2a2008-04-07 18:39:54 +0200248class FrameIdentifierVisitor(NodeVisitor):
249 """A visitor for `Frame.inspect`."""
250
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200251 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200252 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200253 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200254
Armin Ronacherc9705c22008-04-27 21:28:03 +0200255 def visit_Name(self, node):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200256 """All assignments to names go through this function."""
Armin Ronachere9411b42008-05-15 16:22:07 +0200257 if node.ctx == 'store':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200258 self.identifiers.declared_locally.add(node.name)
Armin Ronachere9411b42008-05-15 16:22:07 +0200259 elif node.ctx == 'param':
260 self.identifiers.declared_parameter.add(node.name)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200261 elif node.ctx == 'load' and not \
262 self.identifiers.is_declared(node.name, self.hard_scope):
263 self.identifiers.undeclared.add(node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200264
Armin Ronacherc9705c22008-04-27 21:28:03 +0200265 def visit_Macro(self, node):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200266 self.identifiers.declared_locally.add(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +0200267
Armin Ronacherc9705c22008-04-27 21:28:03 +0200268 def visit_Import(self, node):
269 self.generic_visit(node)
270 self.identifiers.declared_locally.add(node.target)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200271
Armin Ronacherc9705c22008-04-27 21:28:03 +0200272 def visit_FromImport(self, node):
273 self.generic_visit(node)
274 for name in node.names:
275 if isinstance(name, tuple):
276 self.identifiers.declared_locally.add(name[1])
277 else:
278 self.identifiers.declared_locally.add(name)
279
280 def visit_Assign(self, node):
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200281 """Visit assignments in the correct order."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200282 self.visit(node.node)
283 self.visit(node.target)
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200284
Armin Ronacherc9705c22008-04-27 21:28:03 +0200285 def visit_For(self, node):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200286 """Visiting stops at for blocks. However the block sequence
287 is visited as part of the outer scope.
288 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200289 self.visit(node.iter)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200290
Armin Ronacherc9705c22008-04-27 21:28:03 +0200291 def visit_CallBlock(self, node):
292 for child in node.iter_child_nodes(exclude=('body',)):
293 self.visit(child)
294
295 def visit_FilterBlock(self, node):
296 self.visit(node.filter)
297
298 def visit_Block(self, node):
299 """Stop visiting at blocks."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200300
301
Armin Ronacher75cfb862008-04-11 13:47:22 +0200302class CompilerExit(Exception):
303 """Raised if the compiler encountered a situation where it just
304 doesn't make sense to further process the code. Any block that
Armin Ronacher0611e492008-04-25 23:44:14 +0200305 raises such an exception is not further processed.
306 """
Armin Ronacher75cfb862008-04-11 13:47:22 +0200307
308
Armin Ronachere791c2a2008-04-07 18:39:54 +0200309class CodeGenerator(NodeVisitor):
310
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200311 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200312 if stream is None:
313 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200314 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200315 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200316 self.filename = filename
317 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200318
Armin Ronacher023b5e92008-05-08 11:03:10 +0200319 # aliases for imports
320 self.import_aliases = {}
321
Armin Ronacherfed44b52008-04-13 19:42:53 +0200322 # a registry for all blocks. Because blocks are moved out
323 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200324 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200325
326 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200327 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200328
329 # some templates have a rootlevel extends. In this case we
330 # can safely assume that we're a child template and do some
331 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200332 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200333
Armin Ronacherba3757b2008-04-16 19:43:16 +0200334 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200335 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200336
Armin Ronacherb9e78752008-05-10 23:36:28 +0200337 # registry of all filters and tests (global, not block local)
338 self.tests = {}
339 self.filters = {}
340
Armin Ronacherba3757b2008-04-16 19:43:16 +0200341 # the debug information
342 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200343 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200344
Armin Ronacherfed44b52008-04-13 19:42:53 +0200345 # the number of new lines before the next write()
346 self._new_lines = 0
347
348 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200349 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200350
351 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200352 self._first_write = True
353
Armin Ronacherfed44b52008-04-13 19:42:53 +0200354 # used by the `temporary_identifier` method to get new
355 # unique, temporary identifier
356 self._last_identifier = 0
357
358 # the current indentation
359 self._indentation = 0
360
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200361 # -- Various compilation helpers
362
Armin Ronachere2244882008-05-19 09:25:57 +0200363 def fail(self, msg, lineno):
364 """Fail with a `TemplateAssertionError`."""
365 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
366
Armin Ronachere791c2a2008-04-07 18:39:54 +0200367 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200368 """Get a new unique identifier."""
369 self._last_identifier += 1
Armin Ronacher8a1d27f2008-05-19 08:37:19 +0200370 return 't_%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200371
Armin Ronachered1e0d42008-05-18 20:25:28 +0200372 def buffer(self, frame):
373 """Enable buffering for the frame from that point onwards."""
Armin Ronachere2244882008-05-19 09:25:57 +0200374 frame.buffer = self.temporary_identifier()
375 self.writeline('%s = []' % frame.buffer)
Armin Ronachered1e0d42008-05-18 20:25:28 +0200376
377 def return_buffer_contents(self, frame):
378 """Return the buffer contents of the frame."""
379 if self.environment.autoescape:
380 self.writeline('return Markup(concat(%s))' % frame.buffer)
381 else:
382 self.writeline('return concat(%s)' % frame.buffer)
383
Armin Ronachere791c2a2008-04-07 18:39:54 +0200384 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200385 """Indent by one."""
386 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200387
Armin Ronacher8efc5222008-04-08 14:47:40 +0200388 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200389 """Outdent by step."""
390 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200391
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200392 def start_write(self, frame, node=None):
393 """Yield or write into the frame buffer."""
394 if frame.buffer is None:
395 self.writeline('yield ', node)
396 else:
397 self.writeline('%s.append(' % frame.buffer, node)
398
399 def end_write(self, frame):
400 """End the writing process started by `start_write`."""
401 if frame.buffer is not None:
402 self.write(')')
403
404 def simple_write(self, s, frame, node=None):
405 """Simple shortcut for start_write + write + end_write."""
406 self.start_write(frame, node)
407 self.write(s)
408 self.end_write(frame)
409
Armin Ronacherf40c8842008-09-17 18:51:26 +0200410 def blockvisit(self, nodes, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200411 """Visit a list of nodes as block in a frame. If the current frame
412 is no buffer a dummy ``if 0: yield None`` is written automatically
413 unless the force_generator parameter is set to False.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200414 """
Armin Ronacherf40c8842008-09-17 18:51:26 +0200415 if frame.buffer is None:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200416 self.writeline('if 0: yield None')
Armin Ronacherf40c8842008-09-17 18:51:26 +0200417 else:
418 self.writeline('pass')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200419 try:
420 for node in nodes:
421 self.visit(node, frame)
422 except CompilerExit:
423 pass
Armin Ronachere791c2a2008-04-07 18:39:54 +0200424
425 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200426 """Write a string into the output stream."""
427 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200428 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200429 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200430 self.code_lineno += self._new_lines
431 if self._write_debug_info is not None:
432 self.debug_info.append((self._write_debug_info,
433 self.code_lineno))
434 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200435 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200436 self.stream.write(' ' * self._indentation)
437 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200438 self.stream.write(x)
439
440 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200441 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200442 self.newline(node, extra)
443 self.write(x)
444
445 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200446 """Add one or more newlines before the next write."""
447 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200448 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200449 self._write_debug_info = node.lineno
450 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200451
Armin Ronacherfd310492008-05-25 00:16:51 +0200452 def signature(self, node, frame, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200453 """Writes a function call to the stream for the current node.
Armin Ronacherfd310492008-05-25 00:16:51 +0200454 A leading comma is added automatically. The extra keyword
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200455 arguments may not include python keywords otherwise a syntax
456 error could occour. The extra keyword arguments should be given
457 as python dict.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200458 """
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200459 # if any of the given keyword arguments is a python keyword
460 # we have to make sure that no invalid call is created.
461 kwarg_workaround = False
462 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200463 if is_python_keyword(kwarg):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200464 kwarg_workaround = True
465 break
466
Armin Ronacher8efc5222008-04-08 14:47:40 +0200467 for arg in node.args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200468 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200469 self.visit(arg, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200470
471 if not kwarg_workaround:
472 for kwarg in node.kwargs:
Armin Ronacherfd310492008-05-25 00:16:51 +0200473 self.write(', ')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200474 self.visit(kwarg, frame)
475 if extra_kwargs is not None:
476 for key, value in extra_kwargs.iteritems():
Armin Ronacherfd310492008-05-25 00:16:51 +0200477 self.write(', %s=%s' % (key, value))
Armin Ronacher8efc5222008-04-08 14:47:40 +0200478 if node.dyn_args:
Armin Ronacherfd310492008-05-25 00:16:51 +0200479 self.write(', *')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200480 self.visit(node.dyn_args, frame)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200481
482 if kwarg_workaround:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200483 if node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200484 self.write(', **dict({')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200485 else:
Armin Ronacherfd310492008-05-25 00:16:51 +0200486 self.write(', **{')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200487 for kwarg in node.kwargs:
488 self.write('%r: ' % kwarg.key)
489 self.visit(kwarg.value, frame)
490 self.write(', ')
491 if extra_kwargs is not None:
492 for key, value in extra_kwargs.iteritems():
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200493 self.write('%r: %s, ' % (key, value))
494 if node.dyn_kwargs is not None:
495 self.write('}, **')
496 self.visit(node.dyn_kwargs, frame)
497 self.write(')')
498 else:
499 self.write('}')
500
501 elif node.dyn_kwargs is not None:
Armin Ronacherfd310492008-05-25 00:16:51 +0200502 self.write(', **')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200503 self.visit(node.dyn_kwargs, frame)
504
Armin Ronacherc9705c22008-04-27 21:28:03 +0200505 def pull_locals(self, frame):
506 """Pull all the references identifiers into the local scope."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200507 for name in frame.identifiers.undeclared:
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200508 self.writeline('l_%s = context.resolve(%r)' % (name, name))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200509
510 def pull_dependencies(self, nodes):
511 """Pull all the dependencies."""
512 visitor = DependencyFinderVisitor()
513 for node in nodes:
514 visitor.visit(node)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200515 for dependency in 'filters', 'tests':
516 mapping = getattr(self, dependency)
517 for name in getattr(visitor, dependency):
518 if name not in mapping:
519 mapping[name] = self.temporary_identifier()
520 self.writeline('%s = environment.%s[%r]' %
521 (mapping[name], dependency, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200522
Armin Ronacher673aa882008-10-04 18:06:57 +0200523 def push_scope(self, frame, extra_vars=()):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200524 """This function returns all the shadowed variables in a dict
525 in the form name: alias and will write the required assignments
526 into the current scope. No indentation takes place.
Armin Ronacherff53c782008-08-13 18:55:50 +0200527
Armin Ronacher673aa882008-10-04 18:06:57 +0200528 This also predefines locally declared variables from the loop
529 body because under some circumstances it may be the case that
530
Armin Ronacherff53c782008-08-13 18:55:50 +0200531 `extra_vars` is passed to `Identifiers.find_shadowed`.
Armin Ronacherfed44b52008-04-13 19:42:53 +0200532 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200533 aliases = {}
Armin Ronacherff53c782008-08-13 18:55:50 +0200534 for name in frame.identifiers.find_shadowed(extra_vars):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200535 aliases[name] = ident = self.temporary_identifier()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200536 self.writeline('%s = l_%s' % (ident, name))
Armin Ronacher673aa882008-10-04 18:06:57 +0200537 to_declare = set()
538 for name in frame.identifiers.declared_locally:
539 if name not in aliases:
540 to_declare.add('l_' + name)
541 if to_declare:
542 self.writeline(' = '.join(to_declare) + ' = missing')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200543 return aliases
544
Armin Ronacher673aa882008-10-04 18:06:57 +0200545 def pop_scope(self, aliases, frame):
546 """Restore all aliases and delete unused variables."""
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200547 for name, alias in aliases.iteritems():
548 self.writeline('l_%s = %s' % (name, alias))
Armin Ronacher673aa882008-10-04 18:06:57 +0200549 to_delete = set()
550 for name in frame.identifiers.declared_locally:
551 if name not in aliases:
552 to_delete.add('l_' + name)
553 if to_delete:
Armin Ronacher330fbc02009-02-04 19:13:58 +0100554 # we cannot use the del statement here because enclosed
555 # scopes can trigger a SyntaxError:
556 # a = 42; b = lambda: a; del a
557 self.writeline(' = '.join(to_delete) + ' = missing')
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200558
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200559 def function_scoping(self, node, frame, children=None,
560 find_special=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200561 """In Jinja a few statements require the help of anonymous
562 functions. Those are currently macros and call blocks and in
563 the future also recursive loops. As there is currently
564 technical limitation that doesn't allow reading and writing a
565 variable in a scope where the initial value is coming from an
566 outer scope, this function tries to fall back with a common
567 error message. Additionally the frame passed is modified so
568 that the argumetns are collected and callers are looked up.
569
570 This will return the modified frame.
571 """
Armin Ronacherc9705c22008-04-27 21:28:03 +0200572 # we have to iterate twice over it, make sure that works
573 if children is None:
574 children = node.iter_child_nodes()
575 children = list(children)
Armin Ronacher71082072008-04-12 14:19:36 +0200576 func_frame = frame.inner()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200577 func_frame.inspect(children, hard_scope=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200578
579 # variables that are undeclared (accessed before declaration) and
580 # declared locally *and* part of an outside scope raise a template
581 # assertion error. Reason: we can't generate reasonable code from
582 # it without aliasing all the variables. XXX: alias them ^^
583 overriden_closure_vars = (
584 func_frame.identifiers.undeclared &
585 func_frame.identifiers.declared &
586 (func_frame.identifiers.declared_locally |
587 func_frame.identifiers.declared_parameter)
588 )
589 if overriden_closure_vars:
Armin Ronachere2244882008-05-19 09:25:57 +0200590 self.fail('It\'s not possible to set and access variables '
591 'derived from an outer scope! (affects: %s' %
592 ', '.join(sorted(overriden_closure_vars)), node.lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200593
594 # remove variables from a closure from the frame's undeclared
595 # identifiers.
596 func_frame.identifiers.undeclared -= (
597 func_frame.identifiers.undeclared &
598 func_frame.identifiers.declared
599 )
600
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200601 # no special variables for this scope, abort early
602 if not find_special:
603 return func_frame
604
Armin Ronacher963f97d2008-04-25 11:44:59 +0200605 func_frame.accesses_kwargs = False
606 func_frame.accesses_varargs = False
Armin Ronacher71082072008-04-12 14:19:36 +0200607 func_frame.accesses_caller = False
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200608 func_frame.arguments = args = ['l_' + x.name for x in node.args]
Armin Ronacher71082072008-04-12 14:19:36 +0200609
Armin Ronacherc9705c22008-04-27 21:28:03 +0200610 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
611
612 if 'caller' in undeclared:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200613 func_frame.accesses_caller = True
614 func_frame.identifiers.add_special('caller')
615 args.append('l_caller')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200616 if 'kwargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200617 func_frame.accesses_kwargs = True
618 func_frame.identifiers.add_special('kwargs')
619 args.append('l_kwargs')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200620 if 'varargs' in undeclared:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200621 func_frame.accesses_varargs = True
622 func_frame.identifiers.add_special('varargs')
623 args.append('l_varargs')
Armin Ronacher71082072008-04-12 14:19:36 +0200624 return func_frame
625
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200626 def macro_body(self, node, frame, children=None):
627 """Dump the function def of a macro or call block."""
628 frame = self.function_scoping(node, frame, children)
Armin Ronachere308bf22008-10-30 19:18:45 +0100629 # macros are delayed, they never require output checks
630 frame.require_output_check = False
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200631 args = frame.arguments
632 self.writeline('def macro(%s):' % ', '.join(args), node)
633 self.indent()
634 self.buffer(frame)
635 self.pull_locals(frame)
636 self.blockvisit(node.body, frame)
637 self.return_buffer_contents(frame)
638 self.outdent()
639 return frame
640
641 def macro_def(self, node, frame):
642 """Dump the macro definition for the def created by macro_body."""
643 arg_tuple = ', '.join(repr(x.name) for x in node.args)
644 name = getattr(node, 'name', None)
645 if len(node.args) == 1:
646 arg_tuple += ','
647 self.write('Macro(environment, macro, %r, (%s), (' %
648 (name, arg_tuple))
649 for arg in node.defaults:
650 self.visit(arg, frame)
651 self.write(', ')
Armin Ronacher903d1682008-05-23 00:51:58 +0200652 self.write('), %r, %r, %r)' % (
653 bool(frame.accesses_kwargs),
654 bool(frame.accesses_varargs),
655 bool(frame.accesses_caller)
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200656 ))
657
Armin Ronacher547d0b62008-07-04 16:35:10 +0200658 def position(self, node):
659 """Return a human readable position for the node."""
660 rv = 'line %d' % node.lineno
661 if self.name is not None:
Armin Ronachercebd8382008-12-25 18:33:46 +0100662 rv += ' in ' + repr(self.name)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200663 return rv
664
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200665 # -- Statement Visitors
Armin Ronachere791c2a2008-04-07 18:39:54 +0200666
667 def visit_Template(self, node, frame=None):
668 assert frame is None, 'no root frame allowed'
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200669 from jinja2.runtime import __all__ as exported
Armin Ronacher709f6e52008-04-28 18:18:16 +0200670 self.writeline('from __future__ import division')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200671 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
Armin Ronacher8edbe492008-04-10 20:43:43 +0200672
Armin Ronacher75cfb862008-04-11 13:47:22 +0200673 # do we have an extends tag at all? If not, we can save some
674 # overhead by just not processing any inheritance code.
675 have_extends = node.find(nodes.Extends) is not None
676
Armin Ronacher8edbe492008-04-10 20:43:43 +0200677 # find all blocks
678 for block in node.find_all(nodes.Block):
679 if block.name in self.blocks:
Armin Ronachere2244882008-05-19 09:25:57 +0200680 self.fail('block %r defined twice' % block.name, block.lineno)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200681 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200682
Armin Ronacher023b5e92008-05-08 11:03:10 +0200683 # find all imports and import them
684 for import_ in node.find_all(nodes.ImportedName):
685 if import_.importname not in self.import_aliases:
686 imp = import_.importname
687 self.import_aliases[imp] = alias = self.temporary_identifier()
688 if '.' in imp:
689 module, obj = imp.rsplit('.', 1)
690 self.writeline('from %s import %s as %s' %
691 (module, obj, alias))
692 else:
693 self.writeline('import %s as %s' % (imp, alias))
694
695 # add the load name
Armin Ronacherdc02b642008-05-15 22:47:27 +0200696 self.writeline('name = %r' % self.name)
Armin Ronacher023b5e92008-05-08 11:03:10 +0200697
Armin Ronacher8efc5222008-04-08 14:47:40 +0200698 # generate the root render function.
Armin Ronacher32a910f2008-04-26 23:21:03 +0200699 self.writeline('def root(context, environment=environment):', extra=1)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200700
701 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200702 frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200703 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200704 frame.toplevel = frame.rootlevel = True
Armin Ronacher79668952008-09-23 22:52:46 +0200705 frame.require_output_check = have_extends and not self.has_known_extends
Armin Ronacherf059ec12008-04-11 22:21:00 +0200706 self.indent()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200707 if have_extends:
708 self.writeline('parent_template = None')
Armin Ronacherc9705c22008-04-27 21:28:03 +0200709 if 'self' in find_undeclared(node.body, ('self',)):
710 frame.identifiers.add_special('self')
711 self.writeline('l_self = TemplateReference(context)')
Armin Ronacher6df604e2008-05-23 22:18:38 +0200712 self.pull_locals(frame)
713 self.pull_dependencies(node.body)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200714 self.blockvisit(node.body, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200715 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200716
Armin Ronacher8efc5222008-04-08 14:47:40 +0200717 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200718 if have_extends:
719 if not self.has_known_extends:
720 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200721 self.writeline('if parent_template is not None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200722 self.indent()
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200723 self.writeline('for event in parent_template.'
Armin Ronacher5411ce72008-05-25 11:36:22 +0200724 'root_render_func(context):')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200725 self.indent()
726 self.writeline('yield event')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200727 self.outdent(2 + (not self.has_known_extends))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200728
729 # at this point we now have the blocks collected and can visit them too.
730 for name, block in self.blocks.iteritems():
731 block_frame = Frame()
Armin Ronacherc9705c22008-04-27 21:28:03 +0200732 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200733 block_frame.block = name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200734 self.writeline('def block_%s(context, environment=environment):'
735 % name, block, 1)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200736 self.indent()
737 undeclared = find_undeclared(block.body, ('self', 'super'))
738 if 'self' in undeclared:
739 block_frame.identifiers.add_special('self')
740 self.writeline('l_self = TemplateReference(context)')
741 if 'super' in undeclared:
742 block_frame.identifiers.add_special('super')
743 self.writeline('l_super = context.super(%r, '
744 'block_%s)' % (name, name))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200745 self.pull_locals(block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200746 self.pull_dependencies(block.body)
Armin Ronacher625215e2008-04-13 16:31:08 +0200747 self.blockvisit(block.body, block_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200748 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200749
Armin Ronacher75cfb862008-04-11 13:47:22 +0200750 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200751 for x in self.blocks),
752 extra=1)
753
754 # add a function that returns the debug info
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200755 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
756 in self.debug_info))
Armin Ronacher75cfb862008-04-11 13:47:22 +0200757
Armin Ronachere791c2a2008-04-07 18:39:54 +0200758 def visit_Block(self, node, frame):
759 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200760 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200761 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200762 # if we know that we are a child template, there is no need to
763 # check if we are one
764 if self.has_known_extends:
765 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200766 if self.extends_so_far > 0:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200767 self.writeline('if parent_template is None:')
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200768 self.indent()
769 level += 1
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200770 self.writeline('for event in context.blocks[%r][0](context):' %
Armin Ronacherc9705c22008-04-27 21:28:03 +0200771 node.name, node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200772 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200773 self.simple_write('event', frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200774 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200775
776 def visit_Extends(self, node, frame):
777 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200778 if not frame.toplevel:
Armin Ronachere2244882008-05-19 09:25:57 +0200779 self.fail('cannot use extend from a non top-level scope',
780 node.lineno)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200781
Armin Ronacher7fb38972008-04-11 13:54:28 +0200782 # if the number of extends statements in general is zero so
783 # far, we don't have to add a check if something extended
784 # the template before this one.
785 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200786
Armin Ronacher7fb38972008-04-11 13:54:28 +0200787 # if we have a known extends we just add a template runtime
788 # error into the generated code. We could catch that at compile
789 # time too, but i welcome it not to confuse users by throwing the
790 # same error at different times just "because we can".
791 if not self.has_known_extends:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200792 self.writeline('if parent_template is not None:')
Armin Ronacher7fb38972008-04-11 13:54:28 +0200793 self.indent()
794 self.writeline('raise TemplateRuntimeError(%r)' %
795 'extended multiple times')
Armin Ronacher79668952008-09-23 22:52:46 +0200796 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200797
Armin Ronacher7fb38972008-04-11 13:54:28 +0200798 # if we have a known extends already we don't need that code here
799 # as we know that the template execution will end here.
800 if self.has_known_extends:
801 raise CompilerExit()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200802
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200803 self.writeline('parent_template = environment.get_template(', node)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200804 self.visit(node.template, frame)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200805 self.write(', %r)' % self.name)
806 self.writeline('for name, parent_block in parent_template.'
807 'blocks.iteritems():')
808 self.indent()
809 self.writeline('context.blocks.setdefault(name, []).'
Armin Ronacher83fbc0f2008-05-15 12:22:28 +0200810 'append(parent_block)')
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200811 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200812
813 # if this extends statement was in the root level we can take
814 # advantage of that information and simplify the generated code
815 # in the top level from this point onwards
Armin Ronacher27069d72008-05-11 19:48:12 +0200816 if frame.rootlevel:
817 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200818
Armin Ronacher7fb38972008-04-11 13:54:28 +0200819 # and now we have one more
820 self.extends_so_far += 1
821
Armin Ronacherf059ec12008-04-11 22:21:00 +0200822 def visit_Include(self, node, frame):
823 """Handles includes."""
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100824 if node.ignore_missing:
825 self.writeline('try:')
826 self.indent()
827 self.writeline('template = environment.get_template(', node)
828 self.visit(node.template, frame)
829 self.write(', %r)' % self.name)
830 if node.ignore_missing:
831 self.outdent()
832 self.writeline('except TemplateNotFound:')
833 self.indent()
834 self.writeline('pass')
835 self.outdent()
836 self.writeline('else:')
837 self.indent()
838
Armin Ronacherea847c52008-05-02 20:04:32 +0200839 if node.with_context:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200840 self.writeline('for event in template.root_render_func('
Armin Ronacher673aa882008-10-04 18:06:57 +0200841 'template.new_context(context.parent, True, '
842 'locals())):')
Armin Ronacherea847c52008-05-02 20:04:32 +0200843 else:
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100844 self.writeline('for event in template.module._body_stream:')
845
Armin Ronacherf059ec12008-04-11 22:21:00 +0200846 self.indent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +0200847 self.simple_write('event', frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200848 self.outdent()
849
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100850 if node.ignore_missing:
851 self.outdent()
852
Armin Ronacher0611e492008-04-25 23:44:14 +0200853 def visit_Import(self, node, frame):
854 """Visit regular imports."""
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200855 self.writeline('l_%s = ' % node.target, node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200856 if frame.toplevel:
Armin Ronacher53042292008-04-26 18:30:19 +0200857 self.write('context.vars[%r] = ' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200858 self.write('environment.get_template(')
859 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200860 self.write(', %r).' % self.name)
861 if node.with_context:
Armin Ronacher673aa882008-10-04 18:06:57 +0200862 self.write('make_module(context.parent, True, locals())')
Armin Ronacherea847c52008-05-02 20:04:32 +0200863 else:
864 self.write('module')
Armin Ronacher903d1682008-05-23 00:51:58 +0200865 if frame.toplevel and not node.target.startswith('_'):
Armin Ronacher53042292008-04-26 18:30:19 +0200866 self.writeline('context.exported_vars.discard(%r)' % node.target)
Armin Ronacher0611e492008-04-25 23:44:14 +0200867
868 def visit_FromImport(self, node, frame):
869 """Visit named imports."""
870 self.newline(node)
871 self.write('included_template = environment.get_template(')
872 self.visit(node.template, frame)
Armin Ronacherea847c52008-05-02 20:04:32 +0200873 self.write(', %r).' % self.name)
874 if node.with_context:
875 self.write('make_module(context.parent, True)')
876 else:
877 self.write('module')
Armin Ronachera78d2762008-05-15 23:18:07 +0200878
879 var_names = []
880 discarded_names = []
Armin Ronacher0611e492008-04-25 23:44:14 +0200881 for name in node.names:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200882 if isinstance(name, tuple):
883 name, alias = name
884 else:
885 alias = name
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200886 self.writeline('l_%s = getattr(included_template, '
887 '%r, missing)' % (alias, name))
888 self.writeline('if l_%s is missing:' % alias)
Armin Ronacher0611e492008-04-25 23:44:14 +0200889 self.indent()
Armin Ronacherd1ff8582008-05-11 00:30:43 +0200890 self.writeline('l_%s = environment.undefined(%r %% '
Armin Ronacherdc02b642008-05-15 22:47:27 +0200891 'included_template.__name__, '
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200892 'name=%r)' %
Armin Ronacher547d0b62008-07-04 16:35:10 +0200893 (alias, 'the template %%r (imported on %s) does '
894 'not export the requested name %s' % (
895 self.position(node),
896 repr(name)
897 ), name))
Armin Ronacher0611e492008-04-25 23:44:14 +0200898 self.outdent()
899 if frame.toplevel:
Armin Ronachera78d2762008-05-15 23:18:07 +0200900 var_names.append(alias)
Armin Ronacher903d1682008-05-23 00:51:58 +0200901 if not alias.startswith('_'):
Armin Ronachera78d2762008-05-15 23:18:07 +0200902 discarded_names.append(alias)
903
904 if var_names:
905 if len(var_names) == 1:
906 name = var_names[0]
907 self.writeline('context.vars[%r] = l_%s' % (name, name))
908 else:
909 self.writeline('context.vars.update({%s})' % ', '.join(
910 '%r: l_%s' % (name, name) for name in var_names
911 ))
912 if discarded_names:
913 if len(discarded_names) == 1:
914 self.writeline('context.exported_vars.discard(%r)' %
915 discarded_names[0])
916 else:
917 self.writeline('context.exported_vars.difference_'
918 'update((%s))' % ', '.join(map(repr, discarded_names)))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200919
Armin Ronachere791c2a2008-04-07 18:39:54 +0200920 def visit_For(self, node, frame):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200921 # when calculating the nodes for the inner frame we have to exclude
922 # the iterator contents from it
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200923 children = node.iter_child_nodes(exclude=('iter',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200924 if node.recursive:
925 loop_frame = self.function_scoping(node, frame, children,
926 find_special=False)
927 else:
928 loop_frame = frame.inner()
929 loop_frame.inspect(children)
930
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200931 # try to figure out if we have an extended loop. An extended loop
932 # is necessary if the loop is in recursive mode if the special loop
933 # variable is accessed in the body.
934 extended_loop = node.recursive or 'loop' in \
935 find_undeclared(node.iter_child_nodes(
936 only=('body',)), ('loop',))
937
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200938 # if we don't have an recursive loop we have to find the shadowed
Armin Ronacherff53c782008-08-13 18:55:50 +0200939 # variables at that point. Because loops can be nested but the loop
940 # variable is a special one we have to enforce aliasing for it.
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200941 if not node.recursive:
Armin Ronacher673aa882008-10-04 18:06:57 +0200942 aliases = self.push_scope(loop_frame, ('loop',))
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200943
944 # otherwise we set up a buffer and add a function def
945 else:
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200946 self.writeline('def loop(reciter, loop_render_func):', node)
947 self.indent()
Armin Ronachered1e0d42008-05-18 20:25:28 +0200948 self.buffer(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200949 aliases = {}
950
Armin Ronacherff53c782008-08-13 18:55:50 +0200951 # make sure the loop variable is a special one and raise a template
952 # assertion error if a loop tries to write to loop
Armin Ronacher833a3b52008-08-14 12:31:12 +0200953 if extended_loop:
954 loop_frame.identifiers.add_special('loop')
Armin Ronacherff53c782008-08-13 18:55:50 +0200955 for name in node.find_all(nodes.Name):
956 if name.ctx == 'store' and name.name == 'loop':
957 self.fail('Can\'t assign to special loop variable '
958 'in for-loop target', name.lineno)
959
Armin Ronacherc9705c22008-04-27 21:28:03 +0200960 self.pull_locals(loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200961 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200962 iteration_indicator = self.temporary_identifier()
963 self.writeline('%s = 1' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200964
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200965 # Create a fake parent loop if the else or test section of a
966 # loop is accessing the special loop variable and no parent loop
967 # exists.
968 if 'loop' not in aliases and 'loop' in find_undeclared(
969 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
970 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
Armin Ronacher547d0b62008-07-04 16:35:10 +0200971 ("'loop' is undefined. the filter section of a loop as well "
972 "as the else block doesn't have access to the special 'loop'"
973 " variable of the current loop. Because there is no parent "
974 "loop it's undefined. Happened in loop on %s" %
975 self.position(node)))
Armin Ronacher105f0dc2008-05-23 16:12:47 +0200976
977 self.writeline('for ', node)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200978 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200979 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200980
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200981 # if we have an extened loop and a node test, we filter in the
982 # "outer frame".
983 if extended_loop and node.test is not None:
984 self.write('(')
985 self.visit(node.target, loop_frame)
986 self.write(' for ')
987 self.visit(node.target, loop_frame)
988 self.write(' in ')
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200989 if node.recursive:
990 self.write('reciter')
991 else:
992 self.visit(node.iter, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200993 self.write(' if (')
994 test_frame = loop_frame.copy()
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200995 self.visit(node.test, test_frame)
996 self.write('))')
997
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200998 elif node.recursive:
999 self.write('reciter')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001000 else:
1001 self.visit(node.iter, loop_frame)
1002
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001003 if node.recursive:
1004 self.write(', recurse=loop_render_func):')
1005 else:
1006 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001007
1008 # tests in not extended loops become a continue
1009 if not extended_loop and node.test is not None:
1010 self.indent()
Armin Ronacher47a506f2008-05-06 12:17:23 +02001011 self.writeline('if not ')
Armin Ronacher32a910f2008-04-26 23:21:03 +02001012 self.visit(node.test, loop_frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001013 self.write(':')
1014 self.indent()
1015 self.writeline('continue')
1016 self.outdent(2)
1017
Armin Ronacherc9705c22008-04-27 21:28:03 +02001018 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001019 self.blockvisit(node.body, loop_frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001020 if node.else_:
1021 self.writeline('%s = 0' % iteration_indicator)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001022 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001023
1024 if node.else_:
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001025 self.writeline('if %s:' % iteration_indicator)
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001026 self.indent()
Armin Ronacherf40c8842008-09-17 18:51:26 +02001027 self.blockvisit(node.else_, loop_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001028 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001029
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001030 # reset the aliases if there are any.
Armin Ronachercebd8382008-12-25 18:33:46 +01001031 if not node.recursive:
1032 self.pop_scope(aliases, loop_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001033
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001034 # if the node was recursive we have to return the buffer contents
1035 # and start the iteration code
1036 if node.recursive:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001037 self.return_buffer_contents(loop_frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001038 self.outdent()
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001039 self.start_write(frame, node)
1040 self.write('loop(')
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001041 self.visit(node.iter, frame)
1042 self.write(', loop)')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001043 self.end_write(frame)
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001044
Armin Ronachere791c2a2008-04-07 18:39:54 +02001045 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001046 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001047 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +02001048 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001049 self.write(':')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001050 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001051 self.blockvisit(node.body, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001052 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001053 if node.else_:
1054 self.writeline('else:')
Armin Ronacherc9705c22008-04-27 21:28:03 +02001055 self.indent()
Armin Ronacher75cfb862008-04-11 13:47:22 +02001056 self.blockvisit(node.else_, if_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001057 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001058
Armin Ronacher8efc5222008-04-08 14:47:40 +02001059 def visit_Macro(self, node, frame):
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001060 macro_frame = self.macro_body(node, frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001061 self.newline()
1062 if frame.toplevel:
Armin Ronacher903d1682008-05-23 00:51:58 +02001063 if not node.name.startswith('_'):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001064 self.write('context.exported_vars.add(%r)' % node.name)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001065 self.writeline('context.vars[%r] = ' % node.name)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001066 self.write('l_%s = ' % node.name)
1067 self.macro_def(node, macro_frame)
Armin Ronacher71082072008-04-12 14:19:36 +02001068
1069 def visit_CallBlock(self, node, frame):
Armin Ronacher3da90312008-05-23 16:37:28 +02001070 children = node.iter_child_nodes(exclude=('call',))
1071 call_frame = self.macro_body(node, frame, children)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001072 self.writeline('caller = ')
1073 self.macro_def(node, call_frame)
1074 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001075 self.visit_Call(node.call, call_frame, forward_caller=True)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001076 self.end_write(frame)
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001077
1078 def visit_FilterBlock(self, node, frame):
1079 filter_frame = frame.inner()
1080 filter_frame.inspect(node.iter_child_nodes())
Armin Ronacher673aa882008-10-04 18:06:57 +02001081 aliases = self.push_scope(filter_frame)
Armin Ronacherc9705c22008-04-27 21:28:03 +02001082 self.pull_locals(filter_frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001083 self.buffer(filter_frame)
Armin Ronacherf40c8842008-09-17 18:51:26 +02001084 self.blockvisit(node.body, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001085 self.start_write(frame, node)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001086 self.visit_Filter(node.filter, filter_frame)
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001087 self.end_write(frame)
Armin Ronacher673aa882008-10-04 18:06:57 +02001088 self.pop_scope(aliases, filter_frame)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001089
Armin Ronachere791c2a2008-04-07 18:39:54 +02001090 def visit_ExprStmt(self, node, frame):
1091 self.newline(node)
Armin Ronacher6ce170c2008-04-25 12:32:36 +02001092 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001093
1094 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +02001095 # if we have a known extends statement, we don't output anything
Armin Ronacher79668952008-09-23 22:52:46 +02001096 # if we are in a require_output_check section
1097 if self.has_known_extends and frame.require_output_check:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001098 return
Armin Ronachere791c2a2008-04-07 18:39:54 +02001099
Armin Ronacher665bfb82008-07-14 13:41:46 +02001100 if self.environment.finalize:
1101 finalize = lambda x: unicode(self.environment.finalize(x))
1102 else:
1103 finalize = unicode
1104
Armin Ronacher75cfb862008-04-11 13:47:22 +02001105 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +02001106
Armin Ronacher79668952008-09-23 22:52:46 +02001107 # if we are inside a frame that requires output checking, we do so
Armin Ronacher7fb38972008-04-11 13:54:28 +02001108 outdent_later = False
Armin Ronacher79668952008-09-23 22:52:46 +02001109 if frame.require_output_check:
Armin Ronacher203bfcb2008-04-24 21:54:44 +02001110 self.writeline('if parent_template is None:')
Armin Ronacher75cfb862008-04-11 13:47:22 +02001111 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +02001112 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +02001113
Armin Ronachere791c2a2008-04-07 18:39:54 +02001114 # try to evaluate as many chunks as possible into a static
1115 # string at compile time.
1116 body = []
1117 for child in node.nodes:
1118 try:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001119 const = child.as_const()
1120 except nodes.Impossible:
1121 body.append(child)
1122 continue
1123 try:
1124 if self.environment.autoescape:
1125 if hasattr(const, '__html__'):
1126 const = const.__html__()
1127 else:
1128 const = escape(const)
Armin Ronacher665bfb82008-07-14 13:41:46 +02001129 const = finalize(const)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001130 except:
Armin Ronacher9cf95912008-05-24 19:54:43 +02001131 # if something goes wrong here we evaluate the node
1132 # at runtime for easier debugging
Armin Ronachere791c2a2008-04-07 18:39:54 +02001133 body.append(child)
1134 continue
1135 if body and isinstance(body[-1], list):
1136 body[-1].append(const)
1137 else:
1138 body.append([const])
1139
Armin Ronachered1e0d42008-05-18 20:25:28 +02001140 # if we have less than 3 nodes or a buffer we yield or extend/append
1141 if len(body) < 3 or frame.buffer is not None:
Armin Ronacher32a910f2008-04-26 23:21:03 +02001142 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001143 # for one item we append, for more we extend
1144 if len(body) == 1:
1145 self.writeline('%s.append(' % frame.buffer)
1146 else:
1147 self.writeline('%s.extend((' % frame.buffer)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001148 self.indent()
Armin Ronachere791c2a2008-04-07 18:39:54 +02001149 for item in body:
1150 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001151 val = repr(concat(item))
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001152 if frame.buffer is None:
1153 self.writeline('yield ' + val)
1154 else:
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001155 self.writeline(val + ', ')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001156 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001157 if frame.buffer is None:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001158 self.writeline('yield ', item)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001159 else:
1160 self.newline(item)
Armin Ronacherd1342312008-04-28 12:20:12 +02001161 close = 1
1162 if self.environment.autoescape:
1163 self.write('escape(')
1164 else:
1165 self.write('unicode(')
1166 if self.environment.finalize is not None:
1167 self.write('environment.finalize(')
1168 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001169 self.visit(item, frame)
Armin Ronacherd1342312008-04-28 12:20:12 +02001170 self.write(')' * close)
Armin Ronacher32a910f2008-04-26 23:21:03 +02001171 if frame.buffer is not None:
1172 self.write(', ')
1173 if frame.buffer is not None:
Armin Ronacher1e1e8902008-05-11 23:21:16 +02001174 # close the open parentheses
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001175 self.outdent()
1176 self.writeline(len(body) == 1 and ')' or '))')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001177
1178 # otherwise we create a format string as this is faster in that case
1179 else:
1180 format = []
1181 arguments = []
1182 for item in body:
1183 if isinstance(item, list):
Armin Ronacherde6bf712008-04-26 01:44:14 +02001184 format.append(concat(item).replace('%', '%%'))
Armin Ronachere791c2a2008-04-07 18:39:54 +02001185 else:
1186 format.append('%s')
1187 arguments.append(item)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001188 self.writeline('yield ')
Armin Ronacherde6bf712008-04-26 01:44:14 +02001189 self.write(repr(concat(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001190 idx = -1
Armin Ronachera7f016d2008-05-16 00:22:40 +02001191 self.indent()
Armin Ronacher8e8d0712008-04-16 23:10:49 +02001192 for argument in arguments:
Armin Ronachered1e0d42008-05-18 20:25:28 +02001193 self.newline(argument)
Armin Ronacherd1342312008-04-28 12:20:12 +02001194 close = 0
1195 if self.environment.autoescape:
1196 self.write('escape(')
1197 close += 1
1198 if self.environment.finalize is not None:
1199 self.write('environment.finalize(')
1200 close += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +02001201 self.visit(argument, frame)
Armin Ronacher1f627ff2008-05-15 13:23:26 +02001202 self.write(')' * close + ', ')
Armin Ronachera7f016d2008-05-16 00:22:40 +02001203 self.outdent()
1204 self.writeline(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +02001205
Armin Ronacher7fb38972008-04-11 13:54:28 +02001206 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +02001207 self.outdent()
1208
Armin Ronacher8efc5222008-04-08 14:47:40 +02001209 def visit_Assign(self, node, frame):
1210 self.newline(node)
1211 # toplevel assignments however go into the local namespace and
1212 # the current template's context. We create a copy of the frame
1213 # here and add a set so that the Name visitor can add the assigned
1214 # names here.
1215 if frame.toplevel:
1216 assignment_frame = frame.copy()
1217 assignment_frame.assigned_names = set()
1218 else:
1219 assignment_frame = frame
1220 self.visit(node.target, assignment_frame)
1221 self.write(' = ')
1222 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +02001223
1224 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +02001225 if frame.toplevel:
Armin Ronacher69e12db2008-05-12 09:00:03 +02001226 public_names = [x for x in assignment_frame.assigned_names
Armin Ronacher903d1682008-05-23 00:51:58 +02001227 if not x.startswith('_')]
Armin Ronacher69e12db2008-05-12 09:00:03 +02001228 if len(assignment_frame.assigned_names) == 1:
1229 name = iter(assignment_frame.assigned_names).next()
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001230 self.writeline('context.vars[%r] = l_%s' % (name, name))
Armin Ronacher69e12db2008-05-12 09:00:03 +02001231 else:
1232 self.writeline('context.vars.update({')
1233 for idx, name in enumerate(assignment_frame.assigned_names):
1234 if idx:
1235 self.write(', ')
1236 self.write('%r: l_%s' % (name, name))
1237 self.write('})')
1238 if public_names:
1239 if len(public_names) == 1:
1240 self.writeline('context.exported_vars.add(%r)' %
1241 public_names[0])
1242 else:
1243 self.writeline('context.exported_vars.update((%s))' %
1244 ', '.join(map(repr, public_names)))
Armin Ronacher8efc5222008-04-08 14:47:40 +02001245
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001246 # -- Expression Visitors
1247
Armin Ronachere791c2a2008-04-07 18:39:54 +02001248 def visit_Name(self, node, frame):
Armin Ronacherc9705c22008-04-27 21:28:03 +02001249 if node.ctx == 'store' and frame.toplevel:
1250 frame.assigned_names.add(node.name)
Armin Ronacherd1ff8582008-05-11 00:30:43 +02001251 self.write('l_' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001252
1253 def visit_Const(self, node, frame):
1254 val = node.value
1255 if isinstance(val, float):
Armin Ronachere791c2a2008-04-07 18:39:54 +02001256 self.write(str(val))
1257 else:
1258 self.write(repr(val))
1259
Armin Ronacher5411ce72008-05-25 11:36:22 +02001260 def visit_TemplateData(self, node, frame):
1261 self.write(repr(node.as_const()))
1262
Armin Ronacher8efc5222008-04-08 14:47:40 +02001263 def visit_Tuple(self, node, frame):
1264 self.write('(')
1265 idx = -1
1266 for idx, item in enumerate(node.items):
1267 if idx:
1268 self.write(', ')
1269 self.visit(item, frame)
1270 self.write(idx == 0 and ',)' or ')')
1271
Armin Ronacher8edbe492008-04-10 20:43:43 +02001272 def visit_List(self, node, frame):
1273 self.write('[')
1274 for idx, item in enumerate(node.items):
1275 if idx:
1276 self.write(', ')
1277 self.visit(item, frame)
1278 self.write(']')
1279
1280 def visit_Dict(self, node, frame):
1281 self.write('{')
1282 for idx, item in enumerate(node.items):
1283 if idx:
1284 self.write(', ')
1285 self.visit(item.key, frame)
1286 self.write(': ')
1287 self.visit(item.value, frame)
1288 self.write('}')
1289
Armin Ronachere791c2a2008-04-07 18:39:54 +02001290 def binop(operator):
1291 def visitor(self, node, frame):
1292 self.write('(')
1293 self.visit(node.left, frame)
1294 self.write(' %s ' % operator)
1295 self.visit(node.right, frame)
1296 self.write(')')
1297 return visitor
1298
1299 def uaop(operator):
1300 def visitor(self, node, frame):
1301 self.write('(' + operator)
Armin Ronacher9a822052008-04-17 18:44:07 +02001302 self.visit(node.node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001303 self.write(')')
1304 return visitor
1305
1306 visit_Add = binop('+')
1307 visit_Sub = binop('-')
1308 visit_Mul = binop('*')
1309 visit_Div = binop('/')
1310 visit_FloorDiv = binop('//')
1311 visit_Pow = binop('**')
1312 visit_Mod = binop('%')
1313 visit_And = binop('and')
1314 visit_Or = binop('or')
1315 visit_Pos = uaop('+')
1316 visit_Neg = uaop('-')
1317 visit_Not = uaop('not ')
1318 del binop, uaop
1319
Armin Ronacherd1342312008-04-28 12:20:12 +02001320 def visit_Concat(self, node, frame):
Armin Ronacherfdf95302008-05-11 22:20:51 +02001321 self.write('%s((' % (self.environment.autoescape and
1322 'markup_join' or 'unicode_join'))
Armin Ronacherd1342312008-04-28 12:20:12 +02001323 for arg in node.nodes:
1324 self.visit(arg, frame)
1325 self.write(', ')
1326 self.write('))')
1327
Armin Ronachere791c2a2008-04-07 18:39:54 +02001328 def visit_Compare(self, node, frame):
1329 self.visit(node.expr, frame)
1330 for op in node.ops:
1331 self.visit(op, frame)
1332
1333 def visit_Operand(self, node, frame):
1334 self.write(' %s ' % operators[node.op])
1335 self.visit(node.expr, frame)
1336
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001337 def visit_Getattr(self, node, frame):
1338 self.write('environment.getattr(')
1339 self.visit(node.node, frame)
1340 self.write(', %r)' % node.attr)
1341
1342 def visit_Getitem(self, node, frame):
Armin Ronacher5c3c4702008-09-12 23:12:49 +02001343 # slices bypass the environment getitem method.
1344 if isinstance(node.arg, nodes.Slice):
Armin Ronacher8efc5222008-04-08 14:47:40 +02001345 self.visit(node.node, frame)
1346 self.write('[')
1347 self.visit(node.arg, frame)
1348 self.write(']')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001349 else:
Armin Ronacher6dc6f292008-06-12 08:50:07 +02001350 self.write('environment.getitem(')
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001351 self.visit(node.node, frame)
1352 self.write(', ')
1353 self.visit(node.arg, frame)
1354 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001355
1356 def visit_Slice(self, node, frame):
1357 if node.start is not None:
1358 self.visit(node.start, frame)
1359 self.write(':')
1360 if node.stop is not None:
1361 self.visit(node.stop, frame)
1362 if node.step is not None:
1363 self.write(':')
1364 self.visit(node.step, frame)
1365
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001366 def visit_Filter(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001367 self.write(self.filters[node.name] + '(')
Christoph Hack80909862008-04-14 01:35:10 +02001368 func = self.environment.filters.get(node.name)
Armin Ronacher0611e492008-04-25 23:44:14 +02001369 if func is None:
Armin Ronachere2244882008-05-19 09:25:57 +02001370 self.fail('no filter named %r' % node.name, node.lineno)
Christoph Hack80909862008-04-14 01:35:10 +02001371 if getattr(func, 'contextfilter', False):
1372 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001373 elif getattr(func, 'environmentfilter', False):
1374 self.write('environment, ')
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001375
1376 # if the filter node is None we are inside a filter block
1377 # and want to write to the current buffer
Armin Ronacher3da90312008-05-23 16:37:28 +02001378 if node.node is not None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001379 self.visit(node.node, frame)
Armin Ronacher3da90312008-05-23 16:37:28 +02001380 elif self.environment.autoescape:
1381 self.write('Markup(concat(%s))' % frame.buffer)
1382 else:
1383 self.write('concat(%s)' % frame.buffer)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001384 self.signature(node, frame)
1385 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001386
1387 def visit_Test(self, node, frame):
Armin Ronacherb9e78752008-05-10 23:36:28 +02001388 self.write(self.tests[node.name] + '(')
Armin Ronacher0611e492008-04-25 23:44:14 +02001389 if node.name not in self.environment.tests:
Armin Ronachere2244882008-05-19 09:25:57 +02001390 self.fail('no test named %r' % node.name, node.lineno)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001391 self.visit(node.node, frame)
1392 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001393 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001394
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001395 def visit_CondExpr(self, node, frame):
Armin Ronacher547d0b62008-07-04 16:35:10 +02001396 def write_expr2():
1397 if node.expr2 is not None:
1398 return self.visit(node.expr2, frame)
1399 self.write('environment.undefined(%r)' % ('the inline if-'
1400 'expression on %s evaluated to false and '
1401 'no else section was defined.' % self.position(node)))
1402
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001403 if not have_condexpr:
1404 self.write('((')
1405 self.visit(node.test, frame)
1406 self.write(') and (')
1407 self.visit(node.expr1, frame)
1408 self.write(',) or (')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001409 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001410 self.write(',))[0]')
1411 else:
1412 self.write('(')
1413 self.visit(node.expr1, frame)
1414 self.write(' if ')
1415 self.visit(node.test, frame)
1416 self.write(' else ')
Armin Ronacher547d0b62008-07-04 16:35:10 +02001417 write_expr2()
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001418 self.write(')')
1419
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001420 def visit_Call(self, node, frame, forward_caller=False):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001421 if self.environment.sandboxed:
Armin Ronacherfd310492008-05-25 00:16:51 +02001422 self.write('environment.call(context, ')
1423 else:
1424 self.write('context.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001425 self.visit(node.node, frame)
Armin Ronacher105f0dc2008-05-23 16:12:47 +02001426 extra_kwargs = forward_caller and {'caller': 'caller'} or None
Armin Ronacherfd310492008-05-25 00:16:51 +02001427 self.signature(node, frame, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001428 self.write(')')
1429
1430 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001431 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001432 self.visit(node.value, frame)
Armin Ronachered1e0d42008-05-18 20:25:28 +02001433
Armin Ronachera2eb77d2008-05-22 20:28:21 +02001434 # -- Unused nodes for extensions
Armin Ronachered1e0d42008-05-18 20:25:28 +02001435
1436 def visit_MarkSafe(self, node, frame):
1437 self.write('Markup(')
1438 self.visit(node.expr, frame)
1439 self.write(')')
1440
1441 def visit_EnvironmentAttribute(self, node, frame):
1442 self.write('environment.' + node.name)
1443
1444 def visit_ExtensionAttribute(self, node, frame):
Armin Ronacher6df604e2008-05-23 22:18:38 +02001445 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
Armin Ronachered1e0d42008-05-18 20:25:28 +02001446
1447 def visit_ImportedName(self, node, frame):
1448 self.write(self.import_aliases[node.importname])
1449
1450 def visit_InternalName(self, node, frame):
1451 self.write(node.name)
1452
Armin Ronacher6df604e2008-05-23 22:18:38 +02001453 def visit_ContextReference(self, node, frame):
1454 self.write('context')
1455
Armin Ronachered1e0d42008-05-18 20:25:28 +02001456 def visit_Continue(self, node, frame):
1457 self.writeline('continue', node)
1458
1459 def visit_Break(self, node, frame):
1460 self.writeline('break', node)