blob: ca25304220fe3e70d002b5a5f843417ce9fb695e [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
8 :copyright: Copyright 2008 by Armin Ronacher.
9 :license: GNU GPL.
10"""
Armin Ronacher8efc5222008-04-08 14:47:40 +020011from copy import copy
Armin Ronachere791c2a2008-04-07 18:39:54 +020012from random import randrange
Armin Ronachere791c2a2008-04-07 18:39:54 +020013from cStringIO import StringIO
14from jinja2 import nodes
15from jinja2.visitor import NodeVisitor, NodeTransformer
16from jinja2.exceptions import TemplateAssertionError
Armin Ronacher4dfc9752008-04-09 15:03:29 +020017from jinja2.runtime import StaticLoopContext
Armin Ronacher5236d8c2008-04-17 11:23:16 +020018from jinja2.utils import Markup
Armin Ronachere791c2a2008-04-07 18:39:54 +020019
20
21operators = {
22 'eq': '==',
23 'ne': '!=',
24 'gt': '>',
25 'gteq': '>=',
26 'lt': '<',
27 'lteq': '<=',
28 'in': 'in',
29 'notin': 'not in'
30}
31
32
Armin Ronacher3d8b7842008-04-13 13:16:50 +020033try:
34 exec '(0 if 0 else 0)'
35except SyntaxError:
36 have_condexpr = False
37else:
38 have_condexpr = True
39
40
Armin Ronacher8e8d0712008-04-16 23:10:49 +020041def generate(node, environment, name, filename, stream=None):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020042 """Generate the python source for a node tree."""
Armin Ronacher8e8d0712008-04-16 23:10:49 +020043 generator = CodeGenerator(environment, name, filename, stream)
Armin Ronachere791c2a2008-04-07 18:39:54 +020044 generator.visit(node)
45 if stream is None:
46 return generator.stream.getvalue()
47
48
Armin Ronacher4dfc9752008-04-09 15:03:29 +020049def has_safe_repr(value):
50 """Does the node have a safe representation?"""
Armin Ronacherd55ab532008-04-09 16:13:39 +020051 if value is None or value is NotImplemented or value is Ellipsis:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020052 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020053 if isinstance(value, (bool, int, long, float, complex, basestring,
Armin Ronacher5236d8c2008-04-17 11:23:16 +020054 xrange, StaticLoopContext, Markup)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020055 return True
Armin Ronacherd55ab532008-04-09 16:13:39 +020056 if isinstance(value, (tuple, list, set, frozenset)):
Armin Ronacher4dfc9752008-04-09 15:03:29 +020057 for item in value:
58 if not has_safe_repr(item):
59 return False
60 return True
61 elif isinstance(value, dict):
62 for key, value in value.iteritems():
63 if not has_safe_repr(key):
64 return False
65 if not has_safe_repr(value):
66 return False
67 return True
68 return False
69
70
Armin Ronachere791c2a2008-04-07 18:39:54 +020071class Identifiers(object):
72 """Tracks the status of identifiers in frames."""
73
74 def __init__(self):
75 # variables that are known to be declared (probably from outer
76 # frames or because they are special for the frame)
77 self.declared = set()
78
79 # names that are accessed without being explicitly declared by
80 # this one or any of the outer scopes. Names can appear both in
81 # declared and undeclared.
82 self.undeclared = set()
83
84 # names that are declared locally
85 self.declared_locally = set()
86
87 # names that are declared by parameters
88 self.declared_parameter = set()
89
Armin Ronacherf059ec12008-04-11 22:21:00 +020090 # filters/tests that are referenced
Armin Ronacherd4c64f72008-04-11 17:15:29 +020091 self.filters = set()
Armin Ronacherf059ec12008-04-11 22:21:00 +020092 self.tests = set()
Christoph Hack65642a52008-04-08 14:46:56 +020093
Armin Ronachere791c2a2008-04-07 18:39:54 +020094 def add_special(self, name):
95 """Register a special name like `loop`."""
96 self.undeclared.discard(name)
97 self.declared.add(name)
98
Armin Ronacher4f62a9f2008-04-08 18:09:13 +020099 def is_declared(self, name, local_only=False):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200100 """Check if a name is declared in this or an outer scope."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200101 if name in self.declared_locally or name in self.declared_parameter:
102 return True
103 if local_only:
104 return False
105 return name in self.declared
Armin Ronachere791c2a2008-04-07 18:39:54 +0200106
107 def find_shadowed(self):
108 """Find all the shadowed names."""
109 return self.declared & (self.declared_locally | self.declared_parameter)
110
111
112class Frame(object):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200113 """Holds compile time information for us."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200114
115 def __init__(self, parent=None):
116 self.identifiers = Identifiers()
Armin Ronacherfed44b52008-04-13 19:42:53 +0200117
Armin Ronacher75cfb862008-04-11 13:47:22 +0200118 # a toplevel frame is the root + soft frames such as if conditions.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200119 self.toplevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200120
Armin Ronacher75cfb862008-04-11 13:47:22 +0200121 # the root frame is basically just the outermost frame, so no if
122 # conditions. This information is used to optimize inheritance
123 # situations.
124 self.rootlevel = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200125
126 # inside some tags we are using a buffer rather than yield statements.
127 # this for example affects {% filter %} or {% macro %}. If a frame
128 # is buffered this variable points to the name of the list used as
129 # buffer.
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200130 self.buffer = None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200131
132 # if a frame has name_overrides, all read access to a name in this
133 # dict is redirected to a string expression.
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200134 self.name_overrides = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200135
136 # the name of the block we're in, otherwise None.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200137 self.block = parent and parent.block or None
Armin Ronacherfed44b52008-04-13 19:42:53 +0200138
139 # the parent of this frame
140 self.parent = parent
141
Armin Ronachere791c2a2008-04-07 18:39:54 +0200142 if parent is not None:
143 self.identifiers.declared.update(
144 parent.identifiers.declared |
Armin Ronachere791c2a2008-04-07 18:39:54 +0200145 parent.identifiers.declared_locally |
146 parent.identifiers.declared_parameter
147 )
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200148 self.buffer = parent.buffer
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200149 self.name_overrides = parent.name_overrides.copy()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200150
Armin Ronacher8efc5222008-04-08 14:47:40 +0200151 def copy(self):
152 """Create a copy of the current one."""
153 rv = copy(self)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200154 rv.identifiers = copy(self.identifiers)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200155 rv.name_overrides = self.name_overrides.copy()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200156 return rv
157
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200158 def inspect(self, nodes, hard_scope=False):
159 """Walk the node and check for identifiers. If the scope
160 is hard (eg: enforce on a python level) overrides from outer
161 scopes are tracked differently.
162 """
163 visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200164 for node in nodes:
165 visitor.visit(node)
166
167 def inner(self):
168 """Return an inner frame."""
169 return Frame(self)
170
Armin Ronacher75cfb862008-04-11 13:47:22 +0200171 def soft(self):
172 """Return a soft frame. A soft frame may not be modified as
173 standalone thing as it shares the resources with the frame it
174 was created of, but it's not a rootlevel frame any longer.
175 """
176 rv = copy(self)
177 rv.rootlevel = False
178 return rv
179
Armin Ronachere791c2a2008-04-07 18:39:54 +0200180
181class FrameIdentifierVisitor(NodeVisitor):
182 """A visitor for `Frame.inspect`."""
183
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200184 def __init__(self, identifiers, hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200185 self.identifiers = identifiers
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200186 self.hard_scope = hard_scope
Armin Ronachere791c2a2008-04-07 18:39:54 +0200187
188 def visit_Name(self, node):
189 """All assignments to names go through this function."""
190 if node.ctx in ('store', 'param'):
191 self.identifiers.declared_locally.add(node.name)
192 elif node.ctx == 'load':
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200193 if not self.identifiers.is_declared(node.name, self.hard_scope):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200194 self.identifiers.undeclared.add(node.name)
195
Armin Ronacherd55ab532008-04-09 16:13:39 +0200196 def visit_Filter(self, node):
Armin Ronacher449167d2008-04-11 17:55:05 +0200197 self.generic_visit(node)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200198 self.identifiers.filters.add(node.name)
199
200 def visit_Test(self, node):
201 self.generic_visit(node)
202 self.identifiers.tests.add(node.name)
Christoph Hack65642a52008-04-08 14:46:56 +0200203
Armin Ronachere791c2a2008-04-07 18:39:54 +0200204 def visit_Macro(self, node):
205 """Macros set local."""
206 self.identifiers.declared_locally.add(node.name)
207
Armin Ronacherf059ec12008-04-11 22:21:00 +0200208 def visit_Include(self, node):
209 """Some includes set local."""
210 self.generic_visit(node)
211 if node.target is not None:
212 self.identifiers.declared_locally.add(node.target)
213
Armin Ronacherebe55aa2008-04-10 20:51:23 +0200214 def visit_Assign(self, node):
215 """Visit assignments in the correct order."""
216 self.visit(node.node)
217 self.visit(node.target)
218
Armin Ronachere791c2a2008-04-07 18:39:54 +0200219 # stop traversing at instructions that have their own scope.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200220 visit_Block = visit_CallBlock = visit_FilterBlock = \
Armin Ronachere791c2a2008-04-07 18:39:54 +0200221 visit_For = lambda s, n: None
222
223
Armin Ronacher75cfb862008-04-11 13:47:22 +0200224class CompilerExit(Exception):
225 """Raised if the compiler encountered a situation where it just
226 doesn't make sense to further process the code. Any block that
227 raises such an exception is not further processed."""
228
229
Armin Ronachere791c2a2008-04-07 18:39:54 +0200230class CodeGenerator(NodeVisitor):
231
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200232 def __init__(self, environment, name, filename, stream=None):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200233 if stream is None:
234 stream = StringIO()
Christoph Hack65642a52008-04-08 14:46:56 +0200235 self.environment = environment
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200236 self.name = name
Armin Ronachere791c2a2008-04-07 18:39:54 +0200237 self.filename = filename
238 self.stream = stream
Armin Ronacherfed44b52008-04-13 19:42:53 +0200239
240 # a registry for all blocks. Because blocks are moved out
241 # into the global python scope they are registered here
Armin Ronachere791c2a2008-04-07 18:39:54 +0200242 self.blocks = {}
Armin Ronacherfed44b52008-04-13 19:42:53 +0200243
244 # the number of extends statements so far
Armin Ronacher7fb38972008-04-11 13:54:28 +0200245 self.extends_so_far = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200246
247 # some templates have a rootlevel extends. In this case we
248 # can safely assume that we're a child template and do some
249 # more optimizations.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200250 self.has_known_extends = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200251
Armin Ronacherba3757b2008-04-16 19:43:16 +0200252 # the current line number
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200253 self.code_lineno = 1
Armin Ronacherba3757b2008-04-16 19:43:16 +0200254
255 # the debug information
256 self.debug_info = []
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200257 self._write_debug_info = None
Armin Ronacherba3757b2008-04-16 19:43:16 +0200258
Armin Ronacherfed44b52008-04-13 19:42:53 +0200259 # the number of new lines before the next write()
260 self._new_lines = 0
261
262 # the line number of the last written statement
Armin Ronachere791c2a2008-04-07 18:39:54 +0200263 self._last_line = 0
Armin Ronacherfed44b52008-04-13 19:42:53 +0200264
265 # true if nothing was written so far.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200266 self._first_write = True
267
Armin Ronacherfed44b52008-04-13 19:42:53 +0200268 # used by the `temporary_identifier` method to get new
269 # unique, temporary identifier
270 self._last_identifier = 0
271
272 # the current indentation
273 self._indentation = 0
274
Armin Ronachere791c2a2008-04-07 18:39:54 +0200275 def temporary_identifier(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200276 """Get a new unique identifier."""
277 self._last_identifier += 1
278 return 't%d' % self._last_identifier
Armin Ronachere791c2a2008-04-07 18:39:54 +0200279
280 def indent(self):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200281 """Indent by one."""
282 self._indentation += 1
Armin Ronachere791c2a2008-04-07 18:39:54 +0200283
Armin Ronacher8efc5222008-04-08 14:47:40 +0200284 def outdent(self, step=1):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200285 """Outdent by step."""
286 self._indentation -= step
Armin Ronachere791c2a2008-04-07 18:39:54 +0200287
Armin Ronacher625215e2008-04-13 16:31:08 +0200288 def blockvisit(self, nodes, frame, indent=True, force_generator=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200289 """Visit a list of nodes as block in a frame. Per default the
290 code is indented, but this can be disabled by setting the indent
291 parameter to False. If the current frame is no buffer a dummy
292 ``if 0: yield None`` is written automatically unless the
293 force_generator parameter is set to False.
294 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200295 if indent:
296 self.indent()
297 if frame.buffer is None and force_generator:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200298 self.writeline('if 0: yield None')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200299 try:
300 for node in nodes:
301 self.visit(node, frame)
302 except CompilerExit:
303 pass
Armin Ronacher625215e2008-04-13 16:31:08 +0200304 if indent:
305 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200306
307 def write(self, x):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200308 """Write a string into the output stream."""
309 if self._new_lines:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200310 if not self._first_write:
Armin Ronacherfed44b52008-04-13 19:42:53 +0200311 self.stream.write('\n' * self._new_lines)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200312 self.code_lineno += self._new_lines
313 if self._write_debug_info is not None:
314 self.debug_info.append((self._write_debug_info,
315 self.code_lineno))
316 self._write_debug_info = None
Armin Ronachere791c2a2008-04-07 18:39:54 +0200317 self._first_write = False
Armin Ronacherfed44b52008-04-13 19:42:53 +0200318 self.stream.write(' ' * self._indentation)
319 self._new_lines = 0
Armin Ronachere791c2a2008-04-07 18:39:54 +0200320 self.stream.write(x)
321
322 def writeline(self, x, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200323 """Combination of newline and write."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200324 self.newline(node, extra)
325 self.write(x)
326
327 def newline(self, node=None, extra=0):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200328 """Add one or more newlines before the next write."""
329 self._new_lines = max(self._new_lines, 1 + extra)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200330 if node is not None and node.lineno != self._last_line:
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200331 self._write_debug_info = node.lineno
332 self._last_line = node.lineno
Armin Ronachere791c2a2008-04-07 18:39:54 +0200333
Armin Ronacher71082072008-04-12 14:19:36 +0200334 def signature(self, node, frame, have_comma=True, extra_kwargs=None):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200335 """Writes a function call to the stream for the current node.
336 Per default it will write a leading comma but this can be
337 disabled by setting have_comma to False. If extra_kwargs is
338 given it must be a string that represents a single keyword
339 argument call that is inserted at the end of the regular
340 keyword argument calls.
341 """
Armin Ronacher8efc5222008-04-08 14:47:40 +0200342 have_comma = have_comma and [True] or []
343 def touch_comma():
344 if have_comma:
345 self.write(', ')
346 else:
347 have_comma.append(True)
348
349 for arg in node.args:
350 touch_comma()
351 self.visit(arg, frame)
352 for kwarg in node.kwargs:
353 touch_comma()
354 self.visit(kwarg, frame)
Armin Ronacher71082072008-04-12 14:19:36 +0200355 if extra_kwargs is not None:
356 touch_comma()
357 self.write(extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200358 if node.dyn_args:
359 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200360 self.write('*')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200361 self.visit(node.dyn_args, frame)
362 if node.dyn_kwargs:
363 touch_comma()
Armin Ronacher71082072008-04-12 14:19:36 +0200364 self.write('**')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200365 self.visit(node.dyn_kwargs, frame)
366
Armin Ronacher625215e2008-04-13 16:31:08 +0200367 def pull_locals(self, frame, indent=True):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200368 """Pull all the references identifiers into the local scope.
369 This affects regular names, filters and tests. If indent is
370 set to False, no automatic indentation will take place.
371 """
Armin Ronacher625215e2008-04-13 16:31:08 +0200372 if indent:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200373 self.indent()
374 for name in frame.identifiers.undeclared:
375 self.writeline('l_%s = context[%r]' % (name, name))
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200376 for name in frame.identifiers.filters:
377 self.writeline('f_%s = environment.filters[%r]' % (name, name))
Armin Ronacherf059ec12008-04-11 22:21:00 +0200378 for name in frame.identifiers.tests:
379 self.writeline('t_%s = environment.tests[%r]' % (name, name))
Armin Ronacher625215e2008-04-13 16:31:08 +0200380 if indent:
Armin Ronachere791c2a2008-04-07 18:39:54 +0200381 self.outdent()
382
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200383 def collect_shadowed(self, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200384 """This function returns all the shadowed variables in a dict
385 in the form name: alias and will write the required assignments
386 into the current scope. No indentation takes place.
387 """
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200388 # make sure we "backup" overridden, local identifiers
389 # TODO: we should probably optimize this and check if the
390 # identifier is in use afterwards.
391 aliases = {}
392 for name in frame.identifiers.find_shadowed():
393 aliases[name] = ident = self.temporary_identifier()
394 self.writeline('%s = l_%s' % (ident, name))
395 return aliases
396
Armin Ronacher71082072008-04-12 14:19:36 +0200397 def function_scoping(self, node, frame):
Armin Ronacherfed44b52008-04-13 19:42:53 +0200398 """In Jinja a few statements require the help of anonymous
399 functions. Those are currently macros and call blocks and in
400 the future also recursive loops. As there is currently
401 technical limitation that doesn't allow reading and writing a
402 variable in a scope where the initial value is coming from an
403 outer scope, this function tries to fall back with a common
404 error message. Additionally the frame passed is modified so
405 that the argumetns are collected and callers are looked up.
406
407 This will return the modified frame.
408 """
Armin Ronacher71082072008-04-12 14:19:36 +0200409 func_frame = frame.inner()
410 func_frame.inspect(node.iter_child_nodes(), hard_scope=True)
411
412 # variables that are undeclared (accessed before declaration) and
413 # declared locally *and* part of an outside scope raise a template
414 # assertion error. Reason: we can't generate reasonable code from
415 # it without aliasing all the variables. XXX: alias them ^^
416 overriden_closure_vars = (
417 func_frame.identifiers.undeclared &
418 func_frame.identifiers.declared &
419 (func_frame.identifiers.declared_locally |
420 func_frame.identifiers.declared_parameter)
421 )
422 if overriden_closure_vars:
423 vars = ', '.join(sorted(overriden_closure_vars))
424 raise TemplateAssertionError('It\'s not possible to set and '
425 'access variables derived from '
426 'an outer scope! (affects: %s' %
427 vars, node.lineno, self.filename)
428
429 # remove variables from a closure from the frame's undeclared
430 # identifiers.
431 func_frame.identifiers.undeclared -= (
432 func_frame.identifiers.undeclared &
433 func_frame.identifiers.declared
434 )
435
436 func_frame.accesses_arguments = False
437 func_frame.accesses_caller = False
438 func_frame.arguments = args = ['l_' + x.name for x in node.args]
439
440 if 'arguments' in func_frame.identifiers.undeclared:
441 func_frame.accesses_arguments = True
442 func_frame.identifiers.add_special('arguments')
443 args.append('l_arguments')
444 if 'caller' in func_frame.identifiers.undeclared:
445 func_frame.accesses_caller = True
446 func_frame.identifiers.add_special('caller')
447 args.append('l_caller')
448 return func_frame
449
Armin Ronachere791c2a2008-04-07 18:39:54 +0200450 # -- Visitors
451
452 def visit_Template(self, node, frame=None):
453 assert frame is None, 'no root frame allowed'
454 self.writeline('from jinja2.runtime import *')
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200455 self.writeline('name = %r' % self.name)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200456
Armin Ronacher75cfb862008-04-11 13:47:22 +0200457 # do we have an extends tag at all? If not, we can save some
458 # overhead by just not processing any inheritance code.
459 have_extends = node.find(nodes.Extends) is not None
460
Armin Ronacher8edbe492008-04-10 20:43:43 +0200461 # find all blocks
462 for block in node.find_all(nodes.Block):
463 if block.name in self.blocks:
464 raise TemplateAssertionError('block %r defined twice' %
465 block.name, block.lineno,
466 self.filename)
467 self.blocks[block.name] = block
Armin Ronachere791c2a2008-04-07 18:39:54 +0200468
Armin Ronacher8efc5222008-04-08 14:47:40 +0200469 # generate the root render function.
Armin Ronacherf059ec12008-04-11 22:21:00 +0200470 self.writeline('def root(globals, environment=environment'
471 ', standalone=False):', extra=1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200472 self.indent()
Armin Ronacherc63243e2008-04-14 22:53:58 +0200473 self.writeline('context = TemplateContext(environment, globals, %r, '
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200474 'blocks, standalone)' % self.name)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200475 if have_extends:
476 self.writeline('parent_root = None')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200477 self.outdent()
Armin Ronacher75cfb862008-04-11 13:47:22 +0200478
479 # process the root
Armin Ronachere791c2a2008-04-07 18:39:54 +0200480 frame = Frame()
481 frame.inspect(node.body)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200482 frame.toplevel = frame.rootlevel = True
Armin Ronacherf059ec12008-04-11 22:21:00 +0200483 self.indent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200484 self.pull_locals(frame, indent=False)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200485 self.writeline('yield context')
Armin Ronacher625215e2008-04-13 16:31:08 +0200486 self.blockvisit(node.body, frame, indent=False)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200487 self.outdent()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200488
Armin Ronacher8efc5222008-04-08 14:47:40 +0200489 # make sure that the parent root is called.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200490 if have_extends:
491 if not self.has_known_extends:
492 self.indent()
493 self.writeline('if parent_root is not None:')
494 self.indent()
Armin Ronacherf059ec12008-04-11 22:21:00 +0200495 self.writeline('stream = parent_root(context)')
496 self.writeline('stream.next()')
497 self.writeline('for event in stream:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200498 self.indent()
499 self.writeline('yield event')
Armin Ronacher7a52df82008-04-11 13:58:22 +0200500 self.outdent(1 + self.has_known_extends)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200501
502 # at this point we now have the blocks collected and can visit them too.
503 for name, block in self.blocks.iteritems():
504 block_frame = Frame()
505 block_frame.inspect(block.body)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200506 block_frame.block = name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200507 block_frame.identifiers.add_special('super')
508 block_frame.name_overrides['super'] = 'context.super(%r)' % name
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200509 self.writeline('def block_%s(context, environment=environment):'
510 % name, block, 1)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200511 self.pull_locals(block_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200512 self.blockvisit(block.body, block_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200513
Armin Ronacher75cfb862008-04-11 13:47:22 +0200514 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
Armin Ronacherba3757b2008-04-16 19:43:16 +0200515 for x in self.blocks),
516 extra=1)
517
518 # add a function that returns the debug info
519 self.writeline('def get_debug_info():', extra=1)
520 self.indent()
521 self.writeline('return %r' % self.debug_info)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200522
Armin Ronachere791c2a2008-04-07 18:39:54 +0200523 def visit_Block(self, node, frame):
524 """Call a block and register it for the template."""
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200525 level = 1
Armin Ronacher75cfb862008-04-11 13:47:22 +0200526 if frame.toplevel:
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200527 # if we know that we are a child template, there is no need to
528 # check if we are one
529 if self.has_known_extends:
530 return
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200531 if self.extends_so_far > 0:
532 self.writeline('if parent_root is None:')
533 self.indent()
534 level += 1
535 self.writeline('for event in context.blocks[%r][-1](context):' % node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200536 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200537 if frame.buffer is None:
538 self.writeline('yield event')
539 else:
540 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200541 self.outdent(level)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200542
543 def visit_Extends(self, node, frame):
544 """Calls the extender."""
Armin Ronacher8efc5222008-04-08 14:47:40 +0200545 if not frame.toplevel:
546 raise TemplateAssertionError('cannot use extend from a non '
547 'top-level scope', node.lineno,
548 self.filename)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200549
Armin Ronacher7fb38972008-04-11 13:54:28 +0200550 # if the number of extends statements in general is zero so
551 # far, we don't have to add a check if something extended
552 # the template before this one.
553 if self.extends_so_far > 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200554
Armin Ronacher7fb38972008-04-11 13:54:28 +0200555 # if we have a known extends we just add a template runtime
556 # error into the generated code. We could catch that at compile
557 # time too, but i welcome it not to confuse users by throwing the
558 # same error at different times just "because we can".
559 if not self.has_known_extends:
560 self.writeline('if parent_root is not None:')
561 self.indent()
562 self.writeline('raise TemplateRuntimeError(%r)' %
563 'extended multiple times')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200564
Armin Ronacher7fb38972008-04-11 13:54:28 +0200565 # if we have a known extends already we don't need that code here
566 # as we know that the template execution will end here.
567 if self.has_known_extends:
568 raise CompilerExit()
569 self.outdent()
570
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200571 self.writeline('parent_root = environment.get_template(', node, 1)
Armin Ronacher8efc5222008-04-08 14:47:40 +0200572 self.visit(node.template, frame)
Armin Ronacher41ef36f2008-04-11 19:55:08 +0200573 self.write(', %r).root_render_func' % self.filename)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200574
575 # if this extends statement was in the root level we can take
576 # advantage of that information and simplify the generated code
577 # in the top level from this point onwards
578 self.has_known_extends = True
Armin Ronachere791c2a2008-04-07 18:39:54 +0200579
Armin Ronacher7fb38972008-04-11 13:54:28 +0200580 # and now we have one more
581 self.extends_so_far += 1
582
Armin Ronacherf059ec12008-04-11 22:21:00 +0200583 def visit_Include(self, node, frame):
584 """Handles includes."""
585 # simpled include is include into a variable. This kind of
586 # include works the same on every level, so we handle it first.
587 if node.target is not None:
588 self.writeline('l_%s = ' % node.target, node)
589 if frame.toplevel:
590 self.write('context[%r] = ' % node.target)
591 self.write('IncludedTemplate(environment, context, ')
592 self.visit(node.template, frame)
593 self.write(')')
594 return
595
596 self.writeline('included_stream = environment.get_template(', node)
597 self.visit(node.template, frame)
598 self.write(').root_render_func(context, standalone=True)')
599 self.writeline('included_context = included_stream.next()')
600 self.writeline('for event in included_stream:')
601 self.indent()
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200602 if frame.buffer is None:
603 self.writeline('yield event')
604 else:
605 self.writeline('%s.append(event)' % frame.buffer)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200606 self.outdent()
607
608 # if we have a toplevel include the exported variables are copied
609 # into the current context without exporting them. context.udpate
610 # does *not* mark the variables as exported
611 if frame.toplevel:
612 self.writeline('context.update(included_context.get_exported())')
613
Armin Ronachere791c2a2008-04-07 18:39:54 +0200614 def visit_For(self, node, frame):
615 loop_frame = frame.inner()
616 loop_frame.inspect(node.iter_child_nodes())
Armin Ronachere791c2a2008-04-07 18:39:54 +0200617 extended_loop = bool(node.else_) or \
618 'loop' in loop_frame.identifiers.undeclared
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200619 if extended_loop:
620 loop_frame.identifiers.add_special('loop')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200621
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200622 aliases = self.collect_shadowed(loop_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200623 self.pull_locals(loop_frame, indent=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200624 if node.else_:
625 self.writeline('l_loop = None')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200626
627 self.newline(node)
628 self.writeline('for ')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200629 self.visit(node.target, loop_frame)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200630 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200631
632 # the expression pointing to the parent loop. We make the
633 # undefined a bit more debug friendly at the same time.
634 parent_loop = 'loop' in aliases and aliases['loop'] \
Armin Ronacherc63243e2008-04-14 22:53:58 +0200635 or "environment.undefined('loop', extra=%r)" % \
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200636 'the filter section of a loop as well as the ' \
637 'else block doesn\'t have access to the special ' \
638 "'loop' variable of the current loop. Because " \
639 'there is no parent loop it\'s undefined.'
640
641 # if we have an extened loop and a node test, we filter in the
642 # "outer frame".
643 if extended_loop and node.test is not None:
644 self.write('(')
645 self.visit(node.target, loop_frame)
646 self.write(' for ')
647 self.visit(node.target, loop_frame)
648 self.write(' in ')
649 self.visit(node.iter, loop_frame)
650 self.write(' if (')
651 test_frame = loop_frame.copy()
652 test_frame.name_overrides['loop'] = parent_loop
653 self.visit(node.test, test_frame)
654 self.write('))')
655
656 else:
657 self.visit(node.iter, loop_frame)
658
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200659 if 'loop' in aliases:
660 self.write(', ' + aliases['loop'])
Armin Ronachere791c2a2008-04-07 18:39:54 +0200661 self.write(extended_loop and '):' or ':')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200662
663 # tests in not extended loops become a continue
664 if not extended_loop and node.test is not None:
665 self.indent()
666 self.writeline('if ')
667 self.visit(node.test)
668 self.write(':')
669 self.indent()
670 self.writeline('continue')
671 self.outdent(2)
672
Armin Ronacher625215e2008-04-13 16:31:08 +0200673 self.blockvisit(node.body, loop_frame, force_generator=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200674
675 if node.else_:
676 self.writeline('if l_loop is None:')
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200677 self.indent()
678 self.writeline('l_loop = ' + parent_loop)
679 self.outdent()
Armin Ronacher625215e2008-04-13 16:31:08 +0200680 self.blockvisit(node.else_, loop_frame, force_generator=False)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200681
Armin Ronacherd4c64f72008-04-11 17:15:29 +0200682 # reset the aliases if there are any.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200683 for name, alias in aliases.iteritems():
Armin Ronacher8efc5222008-04-08 14:47:40 +0200684 self.writeline('l_%s = %s' % (name, alias))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200685
686 def visit_If(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200687 if_frame = frame.soft()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200688 self.writeline('if ', node)
Armin Ronacher75cfb862008-04-11 13:47:22 +0200689 self.visit(node.test, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200690 self.write(':')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200691 self.blockvisit(node.body, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200692 if node.else_:
693 self.writeline('else:')
Armin Ronacher75cfb862008-04-11 13:47:22 +0200694 self.blockvisit(node.else_, if_frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200695
Armin Ronacher8efc5222008-04-08 14:47:40 +0200696 def visit_Macro(self, node, frame):
Armin Ronacher71082072008-04-12 14:19:36 +0200697 macro_frame = self.function_scoping(node, frame)
698 args = macro_frame.arguments
Armin Ronacher8efc5222008-04-08 14:47:40 +0200699 self.writeline('def macro(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200700 macro_frame.buffer = buf = self.temporary_identifier()
701 self.indent()
702 self.pull_locals(macro_frame, indent=False)
703 self.writeline('%s = []' % buf)
704 self.blockvisit(node.body, macro_frame, indent=False)
Armin Ronacher5236d8c2008-04-17 11:23:16 +0200705 self.writeline("return Markup(u''.join(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200706 self.outdent()
Armin Ronacher8efc5222008-04-08 14:47:40 +0200707 self.newline()
708 if frame.toplevel:
709 self.write('context[%r] = ' % node.name)
710 arg_tuple = ', '.join(repr(x.name) for x in node.args)
711 if len(node.args) == 1:
712 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200713 self.write('l_%s = Macro(environment, macro, %r, (%s), (' %
714 (node.name, node.name, arg_tuple))
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200715 for arg in node.defaults:
Armin Ronacher625215e2008-04-13 16:31:08 +0200716 self.visit(arg, macro_frame)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200717 self.write(', ')
Armin Ronacher00d5d212008-04-13 01:10:18 +0200718 self.write('), %s, %s)' % (
719 macro_frame.accesses_arguments and '1' or '0',
720 macro_frame.accesses_caller and '1' or '0'
Armin Ronacher71082072008-04-12 14:19:36 +0200721 ))
722
723 def visit_CallBlock(self, node, frame):
724 call_frame = self.function_scoping(node, frame)
725 args = call_frame.arguments
726 self.writeline('def call(%s):' % ', '.join(args), node)
Armin Ronacher625215e2008-04-13 16:31:08 +0200727 call_frame.buffer = buf = self.temporary_identifier()
728 self.indent()
729 self.pull_locals(call_frame, indent=False)
730 self.writeline('%s = []' % buf)
731 self.blockvisit(node.body, call_frame, indent=False)
Armin Ronacher5236d8c2008-04-17 11:23:16 +0200732 self.writeline("return Markup(u''.join(%s))" % buf)
Armin Ronacher625215e2008-04-13 16:31:08 +0200733 self.outdent()
Armin Ronacher71082072008-04-12 14:19:36 +0200734 arg_tuple = ', '.join(repr(x.name) for x in node.args)
735 if len(node.args) == 1:
736 arg_tuple += ','
Armin Ronacherc63243e2008-04-14 22:53:58 +0200737 self.writeline('caller = Macro(environment, call, None, (%s), (' %
738 arg_tuple)
Armin Ronacher71082072008-04-12 14:19:36 +0200739 for arg in node.defaults:
740 self.visit(arg)
741 self.write(', ')
Armin Ronacher00d5d212008-04-13 01:10:18 +0200742 self.write('), %s, 0)' % (call_frame.accesses_arguments and '1' or '0'))
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200743 if frame.buffer is None:
744 self.writeline('yield ', node)
745 else:
746 self.writeline('%s.append(' % frame.buffer, node)
Armin Ronacher71082072008-04-12 14:19:36 +0200747 self.visit_Call(node.call, call_frame, extra_kwargs='caller=caller')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200748 if frame.buffer is not None:
749 self.write(')')
750
751 def visit_FilterBlock(self, node, frame):
752 filter_frame = frame.inner()
753 filter_frame.inspect(node.iter_child_nodes())
754
755 aliases = self.collect_shadowed(filter_frame)
Armin Ronacher625215e2008-04-13 16:31:08 +0200756 self.pull_locals(filter_frame, indent=False)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200757 filter_frame.buffer = buf = self.temporary_identifier()
758
759 self.writeline('%s = []' % buf, node)
760 for child in node.body:
761 self.visit(child, filter_frame)
762
763 if frame.buffer is None:
764 self.writeline('yield ', node)
765 else:
766 self.writeline('%s.append(' % frame.buffer, node)
767 self.visit_Filter(node.filter, filter_frame, "u''.join(%s)" % buf)
768 if frame.buffer is not None:
769 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200770
Armin Ronachere791c2a2008-04-07 18:39:54 +0200771 def visit_ExprStmt(self, node, frame):
772 self.newline(node)
773 self.visit(node, frame)
774
775 def visit_Output(self, node, frame):
Armin Ronacher75cfb862008-04-11 13:47:22 +0200776 # if we have a known extends statement, we don't output anything
Armin Ronacher7a52df82008-04-11 13:58:22 +0200777 if self.has_known_extends and frame.toplevel:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200778 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200779
Armin Ronacher75cfb862008-04-11 13:47:22 +0200780 self.newline(node)
Armin Ronacher8edbe492008-04-10 20:43:43 +0200781 if self.environment.finalize is unicode:
782 finalizer = 'unicode'
Armin Ronacherf059ec12008-04-11 22:21:00 +0200783 have_finalizer = False
Armin Ronacher8edbe492008-04-10 20:43:43 +0200784 else:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200785 finalizer = 'environment.finalize'
786 have_finalizer = True
Armin Ronacher8edbe492008-04-10 20:43:43 +0200787
Armin Ronacher7fb38972008-04-11 13:54:28 +0200788 # if we are in the toplevel scope and there was already an extends
789 # statement we have to add a check that disables our yield(s) here
790 # so that they don't appear in the output.
791 outdent_later = False
792 if frame.toplevel and self.extends_so_far != 0:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200793 self.writeline('if parent_root is None:')
794 self.indent()
Armin Ronacher7fb38972008-04-11 13:54:28 +0200795 outdent_later = True
Armin Ronacher75cfb862008-04-11 13:47:22 +0200796
Armin Ronachere791c2a2008-04-07 18:39:54 +0200797 # try to evaluate as many chunks as possible into a static
798 # string at compile time.
799 body = []
800 for child in node.nodes:
801 try:
802 const = unicode(child.as_const())
803 except:
804 body.append(child)
805 continue
806 if body and isinstance(body[-1], list):
807 body[-1].append(const)
808 else:
809 body.append([const])
810
811 # if we have less than 3 nodes we just yield them
812 if len(body) < 3:
813 for item in body:
814 if isinstance(item, list):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200815 val = repr(u''.join(item))
816 if frame.buffer is None:
817 self.writeline('yield ' + val)
818 else:
819 self.writeline('%s.append(%s)' % (frame.buffer, val))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200820 else:
821 self.newline(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200822 if frame.buffer is None:
823 self.write('yield ')
824 else:
825 self.write('%s.append(' % frame.buffer)
826 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200827 self.visit(item, frame)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200828 self.write(')' * (1 + (frame.buffer is not None)))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200829
830 # otherwise we create a format string as this is faster in that case
831 else:
832 format = []
833 arguments = []
834 for item in body:
835 if isinstance(item, list):
836 format.append(u''.join(item).replace('%', '%%'))
837 else:
838 format.append('%s')
839 arguments.append(item)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200840 if frame.buffer is None:
841 self.writeline('yield ')
842 else:
843 self.writeline('%s.append(' % frame.buffer)
844 self.write(repr(u''.join(format)) + ' % (')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200845 idx = -1
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200846 self.indent()
847 for argument in arguments:
848 self.newline(argument)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200849 if have_finalizer:
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200850 self.write(finalizer + '(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200851 self.visit(argument, frame)
Armin Ronacherf059ec12008-04-11 22:21:00 +0200852 if have_finalizer:
Armin Ronacher8edbe492008-04-10 20:43:43 +0200853 self.write(')')
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200854 self.write(',')
855 self.outdent()
856 self.writeline(')')
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200857 if frame.buffer is not None:
858 self.write(')')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200859
Armin Ronacher7fb38972008-04-11 13:54:28 +0200860 if outdent_later:
Armin Ronacher75cfb862008-04-11 13:47:22 +0200861 self.outdent()
862
Armin Ronacher8efc5222008-04-08 14:47:40 +0200863 def visit_Assign(self, node, frame):
864 self.newline(node)
865 # toplevel assignments however go into the local namespace and
866 # the current template's context. We create a copy of the frame
867 # here and add a set so that the Name visitor can add the assigned
868 # names here.
869 if frame.toplevel:
870 assignment_frame = frame.copy()
871 assignment_frame.assigned_names = set()
872 else:
873 assignment_frame = frame
874 self.visit(node.target, assignment_frame)
875 self.write(' = ')
876 self.visit(node.node, frame)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200877
878 # make sure toplevel assignments are added to the context.
Armin Ronacher8efc5222008-04-08 14:47:40 +0200879 if frame.toplevel:
880 for name in assignment_frame.assigned_names:
881 self.writeline('context[%r] = l_%s' % (name, name))
882
Armin Ronachere791c2a2008-04-07 18:39:54 +0200883 def visit_Name(self, node, frame):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200884 if node.ctx == 'store':
885 if frame.toplevel:
886 frame.assigned_names.add(node.name)
887 frame.name_overrides.pop(node.name, None)
888 elif node.ctx == 'load':
889 if node.name in frame.name_overrides:
890 self.write(frame.name_overrides[node.name])
891 return
Armin Ronachere791c2a2008-04-07 18:39:54 +0200892 self.write('l_' + node.name)
893
894 def visit_Const(self, node, frame):
895 val = node.value
896 if isinstance(val, float):
897 # XXX: add checks for infinity and nan
898 self.write(str(val))
899 else:
900 self.write(repr(val))
901
Armin Ronacher8efc5222008-04-08 14:47:40 +0200902 def visit_Tuple(self, node, frame):
903 self.write('(')
904 idx = -1
905 for idx, item in enumerate(node.items):
906 if idx:
907 self.write(', ')
908 self.visit(item, frame)
909 self.write(idx == 0 and ',)' or ')')
910
Armin Ronacher8edbe492008-04-10 20:43:43 +0200911 def visit_List(self, node, frame):
912 self.write('[')
913 for idx, item in enumerate(node.items):
914 if idx:
915 self.write(', ')
916 self.visit(item, frame)
917 self.write(']')
918
919 def visit_Dict(self, node, frame):
920 self.write('{')
921 for idx, item in enumerate(node.items):
922 if idx:
923 self.write(', ')
924 self.visit(item.key, frame)
925 self.write(': ')
926 self.visit(item.value, frame)
927 self.write('}')
928
Armin Ronachere791c2a2008-04-07 18:39:54 +0200929 def binop(operator):
930 def visitor(self, node, frame):
931 self.write('(')
932 self.visit(node.left, frame)
933 self.write(' %s ' % operator)
934 self.visit(node.right, frame)
935 self.write(')')
936 return visitor
937
938 def uaop(operator):
939 def visitor(self, node, frame):
940 self.write('(' + operator)
941 self.visit(node.node)
942 self.write(')')
943 return visitor
944
945 visit_Add = binop('+')
946 visit_Sub = binop('-')
947 visit_Mul = binop('*')
948 visit_Div = binop('/')
949 visit_FloorDiv = binop('//')
950 visit_Pow = binop('**')
951 visit_Mod = binop('%')
952 visit_And = binop('and')
953 visit_Or = binop('or')
954 visit_Pos = uaop('+')
955 visit_Neg = uaop('-')
956 visit_Not = uaop('not ')
957 del binop, uaop
958
959 def visit_Compare(self, node, frame):
960 self.visit(node.expr, frame)
961 for op in node.ops:
962 self.visit(op, frame)
963
964 def visit_Operand(self, node, frame):
965 self.write(' %s ' % operators[node.op])
966 self.visit(node.expr, frame)
967
968 def visit_Subscript(self, node, frame):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200969 if isinstance(node.arg, nodes.Slice):
970 self.visit(node.node, frame)
971 self.write('[')
972 self.visit(node.arg, frame)
973 self.write(']')
974 return
975 try:
976 const = node.arg.as_const()
977 have_const = True
978 except nodes.Impossible:
979 have_const = False
980 if have_const:
981 if isinstance(const, (int, long, float)):
982 self.visit(node.node, frame)
983 self.write('[%s]' % const)
984 return
Armin Ronacherc63243e2008-04-14 22:53:58 +0200985 self.write('environment.subscribe(')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200986 self.visit(node.node, frame)
987 self.write(', ')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200988 if have_const:
989 self.write(repr(const))
990 else:
991 self.visit(node.arg, frame)
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200992 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +0200993
994 def visit_Slice(self, node, frame):
995 if node.start is not None:
996 self.visit(node.start, frame)
997 self.write(':')
998 if node.stop is not None:
999 self.visit(node.stop, frame)
1000 if node.step is not None:
1001 self.write(':')
1002 self.visit(node.step, frame)
1003
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001004 def visit_Filter(self, node, frame, initial=None):
Armin Ronacherd4c64f72008-04-11 17:15:29 +02001005 self.write('f_%s(' % node.name)
Christoph Hack80909862008-04-14 01:35:10 +02001006 func = self.environment.filters.get(node.name)
1007 if getattr(func, 'contextfilter', False):
1008 self.write('context, ')
Armin Ronacher9a027f42008-04-17 11:13:40 +02001009 elif getattr(func, 'environmentfilter', False):
1010 self.write('environment, ')
Christoph Hack80909862008-04-14 01:35:10 +02001011 if isinstance(node.node, nodes.Filter):
1012 self.visit_Filter(node.node, frame, initial)
1013 elif node.node is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001014 self.write(initial)
1015 else:
Armin Ronacherfa865fb2008-04-12 22:11:53 +02001016 self.visit(node.node, frame)
Armin Ronacherd55ab532008-04-09 16:13:39 +02001017 self.signature(node, frame)
1018 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001019
1020 def visit_Test(self, node, frame):
Armin Ronacherf059ec12008-04-11 22:21:00 +02001021 self.write('t_%s(' % node.name)
1022 func = self.environment.tests.get(node.name)
1023 if getattr(func, 'contexttest', False):
1024 self.write('context, ')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001025 self.visit(node.node, frame)
1026 self.signature(node, frame)
Armin Ronachere791c2a2008-04-07 18:39:54 +02001027 self.write(')')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001028
Armin Ronacher3d8b7842008-04-13 13:16:50 +02001029 def visit_CondExpr(self, node, frame):
1030 if not have_condexpr:
1031 self.write('((')
1032 self.visit(node.test, frame)
1033 self.write(') and (')
1034 self.visit(node.expr1, frame)
1035 self.write(',) or (')
1036 self.visit(node.expr2, frame)
1037 self.write(',))[0]')
1038 else:
1039 self.write('(')
1040 self.visit(node.expr1, frame)
1041 self.write(' if ')
1042 self.visit(node.test, frame)
1043 self.write(' else ')
1044 self.visit(node.expr2, frame)
1045 self.write(')')
1046
Armin Ronacher71082072008-04-12 14:19:36 +02001047 def visit_Call(self, node, frame, extra_kwargs=None):
Armin Ronacherc63243e2008-04-14 22:53:58 +02001048 if self.environment.sandboxed:
1049 self.write('environment.call(')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001050 self.visit(node.node, frame)
Armin Ronacherc63243e2008-04-14 22:53:58 +02001051 self.write(self.environment.sandboxed and ', ' or '(')
Armin Ronacher71082072008-04-12 14:19:36 +02001052 self.signature(node, frame, False, extra_kwargs)
Armin Ronacher8efc5222008-04-08 14:47:40 +02001053 self.write(')')
1054
1055 def visit_Keyword(self, node, frame):
Armin Ronacher2e9396b2008-04-16 14:21:57 +02001056 self.write(node.key + '=')
Armin Ronacher8efc5222008-04-08 14:47:40 +02001057 self.visit(node.value, frame)