comparison venv/lib/python2.7/site-packages/jinja2/compiler.py @ 0:d67268158946 draft

planemo upload commit a3f181f5f126803c654b3a66dd4e83a48f7e203b
author bcclaywell
date Mon, 12 Oct 2015 17:43:33 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:d67268158946
1 # -*- coding: utf-8 -*-
2 """
3 jinja2.compiler
4 ~~~~~~~~~~~~~~~
5
6 Compiles nodes into python code.
7
8 :copyright: (c) 2010 by the Jinja Team.
9 :license: BSD, see LICENSE for more details.
10 """
11 from itertools import chain
12 from copy import deepcopy
13 from keyword import iskeyword as is_python_keyword
14 from jinja2 import nodes
15 from jinja2.nodes import EvalContext
16 from jinja2.visitor import NodeVisitor
17 from jinja2.exceptions import TemplateAssertionError
18 from jinja2.utils import Markup, concat, escape
19 from jinja2._compat import range_type, text_type, string_types, \
20 iteritems, NativeStringIO, imap
21
22
23 operators = {
24 'eq': '==',
25 'ne': '!=',
26 'gt': '>',
27 'gteq': '>=',
28 'lt': '<',
29 'lteq': '<=',
30 'in': 'in',
31 'notin': 'not in'
32 }
33
34 # what method to iterate over items do we want to use for dict iteration
35 # in generated code? on 2.x let's go with iteritems, on 3.x with items
36 if hasattr(dict, 'iteritems'):
37 dict_item_iter = 'iteritems'
38 else:
39 dict_item_iter = 'items'
40
41
42 # does if 0: dummy(x) get us x into the scope?
43 def unoptimize_before_dead_code():
44 x = 42
45 def f():
46 if 0: dummy(x)
47 return f
48
49 # The getattr is necessary for pypy which does not set this attribute if
50 # no closure is on the function
51 unoptimize_before_dead_code = bool(
52 getattr(unoptimize_before_dead_code(), '__closure__', None))
53
54
55 def generate(node, environment, name, filename, stream=None,
56 defer_init=False):
57 """Generate the python source for a node tree."""
58 if not isinstance(node, nodes.Template):
59 raise TypeError('Can\'t compile non template nodes')
60 generator = environment.code_generator_class(environment, name, filename,
61 stream, defer_init)
62 generator.visit(node)
63 if stream is None:
64 return generator.stream.getvalue()
65
66
67 def has_safe_repr(value):
68 """Does the node have a safe representation?"""
69 if value is None or value is NotImplemented or value is Ellipsis:
70 return True
71 if isinstance(value, (bool, int, float, complex, range_type,
72 Markup) + string_types):
73 return True
74 if isinstance(value, (tuple, list, set, frozenset)):
75 for item in value:
76 if not has_safe_repr(item):
77 return False
78 return True
79 elif isinstance(value, dict):
80 for key, value in iteritems(value):
81 if not has_safe_repr(key):
82 return False
83 if not has_safe_repr(value):
84 return False
85 return True
86 return False
87
88
89 def find_undeclared(nodes, names):
90 """Check if the names passed are accessed undeclared. The return value
91 is a set of all the undeclared names from the sequence of names found.
92 """
93 visitor = UndeclaredNameVisitor(names)
94 try:
95 for node in nodes:
96 visitor.visit(node)
97 except VisitorExit:
98 pass
99 return visitor.undeclared
100
101
102 class Identifiers(object):
103 """Tracks the status of identifiers in frames."""
104
105 def __init__(self):
106 # variables that are known to be declared (probably from outer
107 # frames or because they are special for the frame)
108 self.declared = set()
109
110 # undeclared variables from outer scopes
111 self.outer_undeclared = set()
112
113 # names that are accessed without being explicitly declared by
114 # this one or any of the outer scopes. Names can appear both in
115 # declared and undeclared.
116 self.undeclared = set()
117
118 # names that are declared locally
119 self.declared_locally = set()
120
121 # names that are declared by parameters
122 self.declared_parameter = set()
123
124 def add_special(self, name):
125 """Register a special name like `loop`."""
126 self.undeclared.discard(name)
127 self.declared.add(name)
128
129 def is_declared(self, name):
130 """Check if a name is declared in this or an outer scope."""
131 if name in self.declared_locally or name in self.declared_parameter:
132 return True
133 return name in self.declared
134
135 def copy(self):
136 return deepcopy(self)
137
138
139 class Frame(object):
140 """Holds compile time information for us."""
141
142 def __init__(self, eval_ctx, parent=None):
143 self.eval_ctx = eval_ctx
144 self.identifiers = Identifiers()
145
146 # a toplevel frame is the root + soft frames such as if conditions.
147 self.toplevel = False
148
149 # the root frame is basically just the outermost frame, so no if
150 # conditions. This information is used to optimize inheritance
151 # situations.
152 self.rootlevel = False
153
154 # in some dynamic inheritance situations the compiler needs to add
155 # write tests around output statements.
156 self.require_output_check = parent and parent.require_output_check
157
158 # inside some tags we are using a buffer rather than yield statements.
159 # this for example affects {% filter %} or {% macro %}. If a frame
160 # is buffered this variable points to the name of the list used as
161 # buffer.
162 self.buffer = None
163
164 # the name of the block we're in, otherwise None.
165 self.block = parent and parent.block or None
166
167 # a set of actually assigned names
168 self.assigned_names = set()
169
170 # the parent of this frame
171 self.parent = parent
172
173 if parent is not None:
174 self.identifiers.declared.update(
175 parent.identifiers.declared |
176 parent.identifiers.declared_parameter |
177 parent.assigned_names
178 )
179 self.identifiers.outer_undeclared.update(
180 parent.identifiers.undeclared -
181 self.identifiers.declared
182 )
183 self.buffer = parent.buffer
184
185 def copy(self):
186 """Create a copy of the current one."""
187 rv = object.__new__(self.__class__)
188 rv.__dict__.update(self.__dict__)
189 rv.identifiers = object.__new__(self.identifiers.__class__)
190 rv.identifiers.__dict__.update(self.identifiers.__dict__)
191 return rv
192
193 def inspect(self, nodes):
194 """Walk the node and check for identifiers. If the scope is hard (eg:
195 enforce on a python level) overrides from outer scopes are tracked
196 differently.
197 """
198 visitor = FrameIdentifierVisitor(self.identifiers)
199 for node in nodes:
200 visitor.visit(node)
201
202 def find_shadowed(self, extra=()):
203 """Find all the shadowed names. extra is an iterable of variables
204 that may be defined with `add_special` which may occour scoped.
205 """
206 i = self.identifiers
207 return (i.declared | i.outer_undeclared) & \
208 (i.declared_locally | i.declared_parameter) | \
209 set(x for x in extra if i.is_declared(x))
210
211 def inner(self):
212 """Return an inner frame."""
213 return Frame(self.eval_ctx, self)
214
215 def soft(self):
216 """Return a soft frame. A soft frame may not be modified as
217 standalone thing as it shares the resources with the frame it
218 was created of, but it's not a rootlevel frame any longer.
219 """
220 rv = self.copy()
221 rv.rootlevel = False
222 return rv
223
224 __copy__ = copy
225
226
227 class VisitorExit(RuntimeError):
228 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
229
230
231 class DependencyFinderVisitor(NodeVisitor):
232 """A visitor that collects filter and test calls."""
233
234 def __init__(self):
235 self.filters = set()
236 self.tests = set()
237
238 def visit_Filter(self, node):
239 self.generic_visit(node)
240 self.filters.add(node.name)
241
242 def visit_Test(self, node):
243 self.generic_visit(node)
244 self.tests.add(node.name)
245
246 def visit_Block(self, node):
247 """Stop visiting at blocks."""
248
249
250 class UndeclaredNameVisitor(NodeVisitor):
251 """A visitor that checks if a name is accessed without being
252 declared. This is different from the frame visitor as it will
253 not stop at closure frames.
254 """
255
256 def __init__(self, names):
257 self.names = set(names)
258 self.undeclared = set()
259
260 def visit_Name(self, node):
261 if node.ctx == 'load' and node.name in self.names:
262 self.undeclared.add(node.name)
263 if self.undeclared == self.names:
264 raise VisitorExit()
265 else:
266 self.names.discard(node.name)
267
268 def visit_Block(self, node):
269 """Stop visiting a blocks."""
270
271
272 class FrameIdentifierVisitor(NodeVisitor):
273 """A visitor for `Frame.inspect`."""
274
275 def __init__(self, identifiers):
276 self.identifiers = identifiers
277
278 def visit_Name(self, node):
279 """All assignments to names go through this function."""
280 if node.ctx == 'store':
281 self.identifiers.declared_locally.add(node.name)
282 elif node.ctx == 'param':
283 self.identifiers.declared_parameter.add(node.name)
284 elif node.ctx == 'load' and not \
285 self.identifiers.is_declared(node.name):
286 self.identifiers.undeclared.add(node.name)
287
288 def visit_If(self, node):
289 self.visit(node.test)
290 real_identifiers = self.identifiers
291
292 old_names = real_identifiers.declared_locally | \
293 real_identifiers.declared_parameter
294
295 def inner_visit(nodes):
296 if not nodes:
297 return set()
298 self.identifiers = real_identifiers.copy()
299 for subnode in nodes:
300 self.visit(subnode)
301 rv = self.identifiers.declared_locally - old_names
302 # we have to remember the undeclared variables of this branch
303 # because we will have to pull them.
304 real_identifiers.undeclared.update(self.identifiers.undeclared)
305 self.identifiers = real_identifiers
306 return rv
307
308 body = inner_visit(node.body)
309 else_ = inner_visit(node.else_ or ())
310
311 # the differences between the two branches are also pulled as
312 # undeclared variables
313 real_identifiers.undeclared.update(body.symmetric_difference(else_) -
314 real_identifiers.declared)
315
316 # remember those that are declared.
317 real_identifiers.declared_locally.update(body | else_)
318
319 def visit_Macro(self, node):
320 self.identifiers.declared_locally.add(node.name)
321
322 def visit_Import(self, node):
323 self.generic_visit(node)
324 self.identifiers.declared_locally.add(node.target)
325
326 def visit_FromImport(self, node):
327 self.generic_visit(node)
328 for name in node.names:
329 if isinstance(name, tuple):
330 self.identifiers.declared_locally.add(name[1])
331 else:
332 self.identifiers.declared_locally.add(name)
333
334 def visit_Assign(self, node):
335 """Visit assignments in the correct order."""
336 self.visit(node.node)
337 self.visit(node.target)
338
339 def visit_For(self, node):
340 """Visiting stops at for blocks. However the block sequence
341 is visited as part of the outer scope.
342 """
343 self.visit(node.iter)
344
345 def visit_CallBlock(self, node):
346 self.visit(node.call)
347
348 def visit_FilterBlock(self, node):
349 self.visit(node.filter)
350
351 def visit_AssignBlock(self, node):
352 """Stop visiting at block assigns."""
353
354 def visit_Scope(self, node):
355 """Stop visiting at scopes."""
356
357 def visit_Block(self, node):
358 """Stop visiting at blocks."""
359
360
361 class CompilerExit(Exception):
362 """Raised if the compiler encountered a situation where it just
363 doesn't make sense to further process the code. Any block that
364 raises such an exception is not further processed.
365 """
366
367
368 class CodeGenerator(NodeVisitor):
369
370 def __init__(self, environment, name, filename, stream=None,
371 defer_init=False):
372 if stream is None:
373 stream = NativeStringIO()
374 self.environment = environment
375 self.name = name
376 self.filename = filename
377 self.stream = stream
378 self.created_block_context = False
379 self.defer_init = defer_init
380
381 # aliases for imports
382 self.import_aliases = {}
383
384 # a registry for all blocks. Because blocks are moved out
385 # into the global python scope they are registered here
386 self.blocks = {}
387
388 # the number of extends statements so far
389 self.extends_so_far = 0
390
391 # some templates have a rootlevel extends. In this case we
392 # can safely assume that we're a child template and do some
393 # more optimizations.
394 self.has_known_extends = False
395
396 # the current line number
397 self.code_lineno = 1
398
399 # registry of all filters and tests (global, not block local)
400 self.tests = {}
401 self.filters = {}
402
403 # the debug information
404 self.debug_info = []
405 self._write_debug_info = None
406
407 # the number of new lines before the next write()
408 self._new_lines = 0
409
410 # the line number of the last written statement
411 self._last_line = 0
412
413 # true if nothing was written so far.
414 self._first_write = True
415
416 # used by the `temporary_identifier` method to get new
417 # unique, temporary identifier
418 self._last_identifier = 0
419
420 # the current indentation
421 self._indentation = 0
422
423 # -- Various compilation helpers
424
425 def fail(self, msg, lineno):
426 """Fail with a :exc:`TemplateAssertionError`."""
427 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
428
429 def temporary_identifier(self):
430 """Get a new unique identifier."""
431 self._last_identifier += 1
432 return 't_%d' % self._last_identifier
433
434 def buffer(self, frame):
435 """Enable buffering for the frame from that point onwards."""
436 frame.buffer = self.temporary_identifier()
437 self.writeline('%s = []' % frame.buffer)
438
439 def return_buffer_contents(self, frame):
440 """Return the buffer contents of the frame."""
441 if frame.eval_ctx.volatile:
442 self.writeline('if context.eval_ctx.autoescape:')
443 self.indent()
444 self.writeline('return Markup(concat(%s))' % frame.buffer)
445 self.outdent()
446 self.writeline('else:')
447 self.indent()
448 self.writeline('return concat(%s)' % frame.buffer)
449 self.outdent()
450 elif frame.eval_ctx.autoescape:
451 self.writeline('return Markup(concat(%s))' % frame.buffer)
452 else:
453 self.writeline('return concat(%s)' % frame.buffer)
454
455 def indent(self):
456 """Indent by one."""
457 self._indentation += 1
458
459 def outdent(self, step=1):
460 """Outdent by step."""
461 self._indentation -= step
462
463 def start_write(self, frame, node=None):
464 """Yield or write into the frame buffer."""
465 if frame.buffer is None:
466 self.writeline('yield ', node)
467 else:
468 self.writeline('%s.append(' % frame.buffer, node)
469
470 def end_write(self, frame):
471 """End the writing process started by `start_write`."""
472 if frame.buffer is not None:
473 self.write(')')
474
475 def simple_write(self, s, frame, node=None):
476 """Simple shortcut for start_write + write + end_write."""
477 self.start_write(frame, node)
478 self.write(s)
479 self.end_write(frame)
480
481 def blockvisit(self, nodes, frame):
482 """Visit a list of nodes as block in a frame. If the current frame
483 is no buffer a dummy ``if 0: yield None`` is written automatically
484 unless the force_generator parameter is set to False.
485 """
486 if frame.buffer is None:
487 self.writeline('if 0: yield None')
488 else:
489 self.writeline('pass')
490 try:
491 for node in nodes:
492 self.visit(node, frame)
493 except CompilerExit:
494 pass
495
496 def write(self, x):
497 """Write a string into the output stream."""
498 if self._new_lines:
499 if not self._first_write:
500 self.stream.write('\n' * self._new_lines)
501 self.code_lineno += self._new_lines
502 if self._write_debug_info is not None:
503 self.debug_info.append((self._write_debug_info,
504 self.code_lineno))
505 self._write_debug_info = None
506 self._first_write = False
507 self.stream.write(' ' * self._indentation)
508 self._new_lines = 0
509 self.stream.write(x)
510
511 def writeline(self, x, node=None, extra=0):
512 """Combination of newline and write."""
513 self.newline(node, extra)
514 self.write(x)
515
516 def newline(self, node=None, extra=0):
517 """Add one or more newlines before the next write."""
518 self._new_lines = max(self._new_lines, 1 + extra)
519 if node is not None and node.lineno != self._last_line:
520 self._write_debug_info = node.lineno
521 self._last_line = node.lineno
522
523 def signature(self, node, frame, extra_kwargs=None):
524 """Writes a function call to the stream for the current node.
525 A leading comma is added automatically. The extra keyword
526 arguments may not include python keywords otherwise a syntax
527 error could occour. The extra keyword arguments should be given
528 as python dict.
529 """
530 # if any of the given keyword arguments is a python keyword
531 # we have to make sure that no invalid call is created.
532 kwarg_workaround = False
533 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
534 if is_python_keyword(kwarg):
535 kwarg_workaround = True
536 break
537
538 for arg in node.args:
539 self.write(', ')
540 self.visit(arg, frame)
541
542 if not kwarg_workaround:
543 for kwarg in node.kwargs:
544 self.write(', ')
545 self.visit(kwarg, frame)
546 if extra_kwargs is not None:
547 for key, value in iteritems(extra_kwargs):
548 self.write(', %s=%s' % (key, value))
549 if node.dyn_args:
550 self.write(', *')
551 self.visit(node.dyn_args, frame)
552
553 if kwarg_workaround:
554 if node.dyn_kwargs is not None:
555 self.write(', **dict({')
556 else:
557 self.write(', **{')
558 for kwarg in node.kwargs:
559 self.write('%r: ' % kwarg.key)
560 self.visit(kwarg.value, frame)
561 self.write(', ')
562 if extra_kwargs is not None:
563 for key, value in iteritems(extra_kwargs):
564 self.write('%r: %s, ' % (key, value))
565 if node.dyn_kwargs is not None:
566 self.write('}, **')
567 self.visit(node.dyn_kwargs, frame)
568 self.write(')')
569 else:
570 self.write('}')
571
572 elif node.dyn_kwargs is not None:
573 self.write(', **')
574 self.visit(node.dyn_kwargs, frame)
575
576 def pull_locals(self, frame):
577 """Pull all the references identifiers into the local scope."""
578 for name in frame.identifiers.undeclared:
579 self.writeline('l_%s = context.resolve(%r)' % (name, name))
580
581 def pull_dependencies(self, nodes):
582 """Pull all the dependencies."""
583 visitor = DependencyFinderVisitor()
584 for node in nodes:
585 visitor.visit(node)
586 for dependency in 'filters', 'tests':
587 mapping = getattr(self, dependency)
588 for name in getattr(visitor, dependency):
589 if name not in mapping:
590 mapping[name] = self.temporary_identifier()
591 self.writeline('%s = environment.%s[%r]' %
592 (mapping[name], dependency, name))
593
594 def unoptimize_scope(self, frame):
595 """Disable Python optimizations for the frame."""
596 # XXX: this is not that nice but it has no real overhead. It
597 # mainly works because python finds the locals before dead code
598 # is removed. If that breaks we have to add a dummy function
599 # that just accepts the arguments and does nothing.
600 if frame.identifiers.declared:
601 self.writeline('%sdummy(%s)' % (
602 unoptimize_before_dead_code and 'if 0: ' or '',
603 ', '.join('l_' + name for name in frame.identifiers.declared)
604 ))
605
606 def push_scope(self, frame, extra_vars=()):
607 """This function returns all the shadowed variables in a dict
608 in the form name: alias and will write the required assignments
609 into the current scope. No indentation takes place.
610
611 This also predefines locally declared variables from the loop
612 body because under some circumstances it may be the case that
613
614 `extra_vars` is passed to `Frame.find_shadowed`.
615 """
616 aliases = {}
617 for name in frame.find_shadowed(extra_vars):
618 aliases[name] = ident = self.temporary_identifier()
619 self.writeline('%s = l_%s' % (ident, name))
620 to_declare = set()
621 for name in frame.identifiers.declared_locally:
622 if name not in aliases:
623 to_declare.add('l_' + name)
624 if to_declare:
625 self.writeline(' = '.join(to_declare) + ' = missing')
626 return aliases
627
628 def pop_scope(self, aliases, frame):
629 """Restore all aliases and delete unused variables."""
630 for name, alias in iteritems(aliases):
631 self.writeline('l_%s = %s' % (name, alias))
632 to_delete = set()
633 for name in frame.identifiers.declared_locally:
634 if name not in aliases:
635 to_delete.add('l_' + name)
636 if to_delete:
637 # we cannot use the del statement here because enclosed
638 # scopes can trigger a SyntaxError:
639 # a = 42; b = lambda: a; del a
640 self.writeline(' = '.join(to_delete) + ' = missing')
641
642 def function_scoping(self, node, frame, children=None,
643 find_special=True):
644 """In Jinja a few statements require the help of anonymous
645 functions. Those are currently macros and call blocks and in
646 the future also recursive loops. As there is currently
647 technical limitation that doesn't allow reading and writing a
648 variable in a scope where the initial value is coming from an
649 outer scope, this function tries to fall back with a common
650 error message. Additionally the frame passed is modified so
651 that the argumetns are collected and callers are looked up.
652
653 This will return the modified frame.
654 """
655 # we have to iterate twice over it, make sure that works
656 if children is None:
657 children = node.iter_child_nodes()
658 children = list(children)
659 func_frame = frame.inner()
660 func_frame.inspect(children)
661
662 # variables that are undeclared (accessed before declaration) and
663 # declared locally *and* part of an outside scope raise a template
664 # assertion error. Reason: we can't generate reasonable code from
665 # it without aliasing all the variables.
666 # this could be fixed in Python 3 where we have the nonlocal
667 # keyword or if we switch to bytecode generation
668 overridden_closure_vars = (
669 func_frame.identifiers.undeclared &
670 func_frame.identifiers.declared &
671 (func_frame.identifiers.declared_locally |
672 func_frame.identifiers.declared_parameter)
673 )
674 if overridden_closure_vars:
675 self.fail('It\'s not possible to set and access variables '
676 'derived from an outer scope! (affects: %s)' %
677 ', '.join(sorted(overridden_closure_vars)), node.lineno)
678
679 # remove variables from a closure from the frame's undeclared
680 # identifiers.
681 func_frame.identifiers.undeclared -= (
682 func_frame.identifiers.undeclared &
683 func_frame.identifiers.declared
684 )
685
686 # no special variables for this scope, abort early
687 if not find_special:
688 return func_frame
689
690 func_frame.accesses_kwargs = False
691 func_frame.accesses_varargs = False
692 func_frame.accesses_caller = False
693 func_frame.arguments = args = ['l_' + x.name for x in node.args]
694
695 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
696
697 if 'caller' in undeclared:
698 func_frame.accesses_caller = True
699 func_frame.identifiers.add_special('caller')
700 args.append('l_caller')
701 if 'kwargs' in undeclared:
702 func_frame.accesses_kwargs = True
703 func_frame.identifiers.add_special('kwargs')
704 args.append('l_kwargs')
705 if 'varargs' in undeclared:
706 func_frame.accesses_varargs = True
707 func_frame.identifiers.add_special('varargs')
708 args.append('l_varargs')
709 return func_frame
710
711 def macro_body(self, node, frame, children=None):
712 """Dump the function def of a macro or call block."""
713 frame = self.function_scoping(node, frame, children)
714 # macros are delayed, they never require output checks
715 frame.require_output_check = False
716 args = frame.arguments
717 # XXX: this is an ugly fix for the loop nesting bug
718 # (tests.test_old_bugs.test_loop_call_bug). This works around
719 # a identifier nesting problem we have in general. It's just more
720 # likely to happen in loops which is why we work around it. The
721 # real solution would be "nonlocal" all the identifiers that are
722 # leaking into a new python frame and might be used both unassigned
723 # and assigned.
724 if 'loop' in frame.identifiers.declared:
725 args = args + ['l_loop=l_loop']
726 self.writeline('def macro(%s):' % ', '.join(args), node)
727 self.indent()
728 self.buffer(frame)
729 self.pull_locals(frame)
730 self.blockvisit(node.body, frame)
731 self.return_buffer_contents(frame)
732 self.outdent()
733 return frame
734
735 def macro_def(self, node, frame):
736 """Dump the macro definition for the def created by macro_body."""
737 arg_tuple = ', '.join(repr(x.name) for x in node.args)
738 name = getattr(node, 'name', None)
739 if len(node.args) == 1:
740 arg_tuple += ','
741 self.write('Macro(environment, macro, %r, (%s), (' %
742 (name, arg_tuple))
743 for arg in node.defaults:
744 self.visit(arg, frame)
745 self.write(', ')
746 self.write('), %r, %r, %r)' % (
747 bool(frame.accesses_kwargs),
748 bool(frame.accesses_varargs),
749 bool(frame.accesses_caller)
750 ))
751
752 def position(self, node):
753 """Return a human readable position for the node."""
754 rv = 'line %d' % node.lineno
755 if self.name is not None:
756 rv += ' in ' + repr(self.name)
757 return rv
758
759 # -- Statement Visitors
760
761 def visit_Template(self, node, frame=None):
762 assert frame is None, 'no root frame allowed'
763 eval_ctx = EvalContext(self.environment, self.name)
764
765 from jinja2.runtime import __all__ as exported
766 self.writeline('from __future__ import division')
767 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
768 if not unoptimize_before_dead_code:
769 self.writeline('dummy = lambda *x: None')
770
771 # if we want a deferred initialization we cannot move the
772 # environment into a local name
773 envenv = not self.defer_init and ', environment=environment' or ''
774
775 # do we have an extends tag at all? If not, we can save some
776 # overhead by just not processing any inheritance code.
777 have_extends = node.find(nodes.Extends) is not None
778
779 # find all blocks
780 for block in node.find_all(nodes.Block):
781 if block.name in self.blocks:
782 self.fail('block %r defined twice' % block.name, block.lineno)
783 self.blocks[block.name] = block
784
785 # find all imports and import them
786 for import_ in node.find_all(nodes.ImportedName):
787 if import_.importname not in self.import_aliases:
788 imp = import_.importname
789 self.import_aliases[imp] = alias = self.temporary_identifier()
790 if '.' in imp:
791 module, obj = imp.rsplit('.', 1)
792 self.writeline('from %s import %s as %s' %
793 (module, obj, alias))
794 else:
795 self.writeline('import %s as %s' % (imp, alias))
796
797 # add the load name
798 self.writeline('name = %r' % self.name)
799
800 # generate the root render function.
801 self.writeline('def root(context%s):' % envenv, extra=1)
802
803 # process the root
804 frame = Frame(eval_ctx)
805 frame.inspect(node.body)
806 frame.toplevel = frame.rootlevel = True
807 frame.require_output_check = have_extends and not self.has_known_extends
808 self.indent()
809 if have_extends:
810 self.writeline('parent_template = None')
811 if 'self' in find_undeclared(node.body, ('self',)):
812 frame.identifiers.add_special('self')
813 self.writeline('l_self = TemplateReference(context)')
814 self.pull_locals(frame)
815 self.pull_dependencies(node.body)
816 self.blockvisit(node.body, frame)
817 self.outdent()
818
819 # make sure that the parent root is called.
820 if have_extends:
821 if not self.has_known_extends:
822 self.indent()
823 self.writeline('if parent_template is not None:')
824 self.indent()
825 self.writeline('for event in parent_template.'
826 'root_render_func(context):')
827 self.indent()
828 self.writeline('yield event')
829 self.outdent(2 + (not self.has_known_extends))
830
831 # at this point we now have the blocks collected and can visit them too.
832 for name, block in iteritems(self.blocks):
833 block_frame = Frame(eval_ctx)
834 block_frame.inspect(block.body)
835 block_frame.block = name
836 self.writeline('def block_%s(context%s):' % (name, envenv),
837 block, 1)
838 self.indent()
839 undeclared = find_undeclared(block.body, ('self', 'super'))
840 if 'self' in undeclared:
841 block_frame.identifiers.add_special('self')
842 self.writeline('l_self = TemplateReference(context)')
843 if 'super' in undeclared:
844 block_frame.identifiers.add_special('super')
845 self.writeline('l_super = context.super(%r, '
846 'block_%s)' % (name, name))
847 self.pull_locals(block_frame)
848 self.pull_dependencies(block.body)
849 self.blockvisit(block.body, block_frame)
850 self.outdent()
851
852 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
853 for x in self.blocks),
854 extra=1)
855
856 # add a function that returns the debug info
857 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
858 in self.debug_info))
859
860 def visit_Block(self, node, frame):
861 """Call a block and register it for the template."""
862 level = 1
863 if frame.toplevel:
864 # if we know that we are a child template, there is no need to
865 # check if we are one
866 if self.has_known_extends:
867 return
868 if self.extends_so_far > 0:
869 self.writeline('if parent_template is None:')
870 self.indent()
871 level += 1
872 context = node.scoped and 'context.derived(locals())' or 'context'
873 self.writeline('for event in context.blocks[%r][0](%s):' % (
874 node.name, context), node)
875 self.indent()
876 self.simple_write('event', frame)
877 self.outdent(level)
878
879 def visit_Extends(self, node, frame):
880 """Calls the extender."""
881 if not frame.toplevel:
882 self.fail('cannot use extend from a non top-level scope',
883 node.lineno)
884
885 # if the number of extends statements in general is zero so
886 # far, we don't have to add a check if something extended
887 # the template before this one.
888 if self.extends_so_far > 0:
889
890 # if we have a known extends we just add a template runtime
891 # error into the generated code. We could catch that at compile
892 # time too, but i welcome it not to confuse users by throwing the
893 # same error at different times just "because we can".
894 if not self.has_known_extends:
895 self.writeline('if parent_template is not None:')
896 self.indent()
897 self.writeline('raise TemplateRuntimeError(%r)' %
898 'extended multiple times')
899
900 # if we have a known extends already we don't need that code here
901 # as we know that the template execution will end here.
902 if self.has_known_extends:
903 raise CompilerExit()
904 else:
905 self.outdent()
906
907 self.writeline('parent_template = environment.get_template(', node)
908 self.visit(node.template, frame)
909 self.write(', %r)' % self.name)
910 self.writeline('for name, parent_block in parent_template.'
911 'blocks.%s():' % dict_item_iter)
912 self.indent()
913 self.writeline('context.blocks.setdefault(name, []).'
914 'append(parent_block)')
915 self.outdent()
916
917 # if this extends statement was in the root level we can take
918 # advantage of that information and simplify the generated code
919 # in the top level from this point onwards
920 if frame.rootlevel:
921 self.has_known_extends = True
922
923 # and now we have one more
924 self.extends_so_far += 1
925
926 def visit_Include(self, node, frame):
927 """Handles includes."""
928 if node.with_context:
929 self.unoptimize_scope(frame)
930 if node.ignore_missing:
931 self.writeline('try:')
932 self.indent()
933
934 func_name = 'get_or_select_template'
935 if isinstance(node.template, nodes.Const):
936 if isinstance(node.template.value, string_types):
937 func_name = 'get_template'
938 elif isinstance(node.template.value, (tuple, list)):
939 func_name = 'select_template'
940 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
941 func_name = 'select_template'
942
943 self.writeline('template = environment.%s(' % func_name, node)
944 self.visit(node.template, frame)
945 self.write(', %r)' % self.name)
946 if node.ignore_missing:
947 self.outdent()
948 self.writeline('except TemplateNotFound:')
949 self.indent()
950 self.writeline('pass')
951 self.outdent()
952 self.writeline('else:')
953 self.indent()
954
955 if node.with_context:
956 self.writeline('for event in template.root_render_func('
957 'template.new_context(context.parent, True, '
958 'locals())):')
959 else:
960 self.writeline('for event in template.module._body_stream:')
961
962 self.indent()
963 self.simple_write('event', frame)
964 self.outdent()
965
966 if node.ignore_missing:
967 self.outdent()
968
969 def visit_Import(self, node, frame):
970 """Visit regular imports."""
971 if node.with_context:
972 self.unoptimize_scope(frame)
973 self.writeline('l_%s = ' % node.target, node)
974 if frame.toplevel:
975 self.write('context.vars[%r] = ' % node.target)
976 self.write('environment.get_template(')
977 self.visit(node.template, frame)
978 self.write(', %r).' % self.name)
979 if node.with_context:
980 self.write('make_module(context.parent, True, locals())')
981 else:
982 self.write('module')
983 if frame.toplevel and not node.target.startswith('_'):
984 self.writeline('context.exported_vars.discard(%r)' % node.target)
985 frame.assigned_names.add(node.target)
986
987 def visit_FromImport(self, node, frame):
988 """Visit named imports."""
989 self.newline(node)
990 self.write('included_template = environment.get_template(')
991 self.visit(node.template, frame)
992 self.write(', %r).' % self.name)
993 if node.with_context:
994 self.write('make_module(context.parent, True)')
995 else:
996 self.write('module')
997
998 var_names = []
999 discarded_names = []
1000 for name in node.names:
1001 if isinstance(name, tuple):
1002 name, alias = name
1003 else:
1004 alias = name
1005 self.writeline('l_%s = getattr(included_template, '
1006 '%r, missing)' % (alias, name))
1007 self.writeline('if l_%s is missing:' % alias)
1008 self.indent()
1009 self.writeline('l_%s = environment.undefined(%r %% '
1010 'included_template.__name__, '
1011 'name=%r)' %
1012 (alias, 'the template %%r (imported on %s) does '
1013 'not export the requested name %s' % (
1014 self.position(node),
1015 repr(name)
1016 ), name))
1017 self.outdent()
1018 if frame.toplevel:
1019 var_names.append(alias)
1020 if not alias.startswith('_'):
1021 discarded_names.append(alias)
1022 frame.assigned_names.add(alias)
1023
1024 if var_names:
1025 if len(var_names) == 1:
1026 name = var_names[0]
1027 self.writeline('context.vars[%r] = l_%s' % (name, name))
1028 else:
1029 self.writeline('context.vars.update({%s})' % ', '.join(
1030 '%r: l_%s' % (name, name) for name in var_names
1031 ))
1032 if discarded_names:
1033 if len(discarded_names) == 1:
1034 self.writeline('context.exported_vars.discard(%r)' %
1035 discarded_names[0])
1036 else:
1037 self.writeline('context.exported_vars.difference_'
1038 'update((%s))' % ', '.join(imap(repr, discarded_names)))
1039
1040 def visit_For(self, node, frame):
1041 # when calculating the nodes for the inner frame we have to exclude
1042 # the iterator contents from it
1043 children = node.iter_child_nodes(exclude=('iter',))
1044 if node.recursive:
1045 loop_frame = self.function_scoping(node, frame, children,
1046 find_special=False)
1047 else:
1048 loop_frame = frame.inner()
1049 loop_frame.inspect(children)
1050
1051 # try to figure out if we have an extended loop. An extended loop
1052 # is necessary if the loop is in recursive mode if the special loop
1053 # variable is accessed in the body.
1054 extended_loop = node.recursive or 'loop' in \
1055 find_undeclared(node.iter_child_nodes(
1056 only=('body',)), ('loop',))
1057
1058 # if we don't have an recursive loop we have to find the shadowed
1059 # variables at that point. Because loops can be nested but the loop
1060 # variable is a special one we have to enforce aliasing for it.
1061 if not node.recursive:
1062 aliases = self.push_scope(loop_frame, ('loop',))
1063
1064 # otherwise we set up a buffer and add a function def
1065 else:
1066 self.writeline('def loop(reciter, loop_render_func, depth=0):', node)
1067 self.indent()
1068 self.buffer(loop_frame)
1069 aliases = {}
1070
1071 # make sure the loop variable is a special one and raise a template
1072 # assertion error if a loop tries to write to loop
1073 if extended_loop:
1074 self.writeline('l_loop = missing')
1075 loop_frame.identifiers.add_special('loop')
1076 for name in node.find_all(nodes.Name):
1077 if name.ctx == 'store' and name.name == 'loop':
1078 self.fail('Can\'t assign to special loop variable '
1079 'in for-loop target', name.lineno)
1080
1081 self.pull_locals(loop_frame)
1082 if node.else_:
1083 iteration_indicator = self.temporary_identifier()
1084 self.writeline('%s = 1' % iteration_indicator)
1085
1086 # Create a fake parent loop if the else or test section of a
1087 # loop is accessing the special loop variable and no parent loop
1088 # exists.
1089 if 'loop' not in aliases and 'loop' in find_undeclared(
1090 node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1091 self.writeline("l_loop = environment.undefined(%r, name='loop')" %
1092 ("'loop' is undefined. the filter section of a loop as well "
1093 "as the else block don't have access to the special 'loop'"
1094 " variable of the current loop. Because there is no parent "
1095 "loop it's undefined. Happened in loop on %s" %
1096 self.position(node)))
1097
1098 self.writeline('for ', node)
1099 self.visit(node.target, loop_frame)
1100 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
1101
1102 # if we have an extened loop and a node test, we filter in the
1103 # "outer frame".
1104 if extended_loop and node.test is not None:
1105 self.write('(')
1106 self.visit(node.target, loop_frame)
1107 self.write(' for ')
1108 self.visit(node.target, loop_frame)
1109 self.write(' in ')
1110 if node.recursive:
1111 self.write('reciter')
1112 else:
1113 self.visit(node.iter, loop_frame)
1114 self.write(' if (')
1115 test_frame = loop_frame.copy()
1116 self.visit(node.test, test_frame)
1117 self.write('))')
1118
1119 elif node.recursive:
1120 self.write('reciter')
1121 else:
1122 self.visit(node.iter, loop_frame)
1123
1124 if node.recursive:
1125 self.write(', loop_render_func, depth):')
1126 else:
1127 self.write(extended_loop and '):' or ':')
1128
1129 # tests in not extended loops become a continue
1130 if not extended_loop and node.test is not None:
1131 self.indent()
1132 self.writeline('if not ')
1133 self.visit(node.test, loop_frame)
1134 self.write(':')
1135 self.indent()
1136 self.writeline('continue')
1137 self.outdent(2)
1138
1139 self.indent()
1140 self.blockvisit(node.body, loop_frame)
1141 if node.else_:
1142 self.writeline('%s = 0' % iteration_indicator)
1143 self.outdent()
1144
1145 if node.else_:
1146 self.writeline('if %s:' % iteration_indicator)
1147 self.indent()
1148 self.blockvisit(node.else_, loop_frame)
1149 self.outdent()
1150
1151 # reset the aliases if there are any.
1152 if not node.recursive:
1153 self.pop_scope(aliases, loop_frame)
1154
1155 # if the node was recursive we have to return the buffer contents
1156 # and start the iteration code
1157 if node.recursive:
1158 self.return_buffer_contents(loop_frame)
1159 self.outdent()
1160 self.start_write(frame, node)
1161 self.write('loop(')
1162 self.visit(node.iter, frame)
1163 self.write(', loop)')
1164 self.end_write(frame)
1165
1166 def visit_If(self, node, frame):
1167 if_frame = frame.soft()
1168 self.writeline('if ', node)
1169 self.visit(node.test, if_frame)
1170 self.write(':')
1171 self.indent()
1172 self.blockvisit(node.body, if_frame)
1173 self.outdent()
1174 if node.else_:
1175 self.writeline('else:')
1176 self.indent()
1177 self.blockvisit(node.else_, if_frame)
1178 self.outdent()
1179
1180 def visit_Macro(self, node, frame):
1181 macro_frame = self.macro_body(node, frame)
1182 self.newline()
1183 if frame.toplevel:
1184 if not node.name.startswith('_'):
1185 self.write('context.exported_vars.add(%r)' % node.name)
1186 self.writeline('context.vars[%r] = ' % node.name)
1187 self.write('l_%s = ' % node.name)
1188 self.macro_def(node, macro_frame)
1189 frame.assigned_names.add(node.name)
1190
1191 def visit_CallBlock(self, node, frame):
1192 children = node.iter_child_nodes(exclude=('call',))
1193 call_frame = self.macro_body(node, frame, children)
1194 self.writeline('caller = ')
1195 self.macro_def(node, call_frame)
1196 self.start_write(frame, node)
1197 self.visit_Call(node.call, call_frame, forward_caller=True)
1198 self.end_write(frame)
1199
1200 def visit_FilterBlock(self, node, frame):
1201 filter_frame = frame.inner()
1202 filter_frame.inspect(node.iter_child_nodes())
1203 aliases = self.push_scope(filter_frame)
1204 self.pull_locals(filter_frame)
1205 self.buffer(filter_frame)
1206 self.blockvisit(node.body, filter_frame)
1207 self.start_write(frame, node)
1208 self.visit_Filter(node.filter, filter_frame)
1209 self.end_write(frame)
1210 self.pop_scope(aliases, filter_frame)
1211
1212 def visit_ExprStmt(self, node, frame):
1213 self.newline(node)
1214 self.visit(node.node, frame)
1215
1216 def visit_Output(self, node, frame):
1217 # if we have a known extends statement, we don't output anything
1218 # if we are in a require_output_check section
1219 if self.has_known_extends and frame.require_output_check:
1220 return
1221
1222 allow_constant_finalize = True
1223 if self.environment.finalize:
1224 func = self.environment.finalize
1225 if getattr(func, 'contextfunction', False) or \
1226 getattr(func, 'evalcontextfunction', False):
1227 allow_constant_finalize = False
1228 elif getattr(func, 'environmentfunction', False):
1229 finalize = lambda x: text_type(
1230 self.environment.finalize(self.environment, x))
1231 else:
1232 finalize = lambda x: text_type(self.environment.finalize(x))
1233 else:
1234 finalize = text_type
1235
1236 # if we are inside a frame that requires output checking, we do so
1237 outdent_later = False
1238 if frame.require_output_check:
1239 self.writeline('if parent_template is None:')
1240 self.indent()
1241 outdent_later = True
1242
1243 # try to evaluate as many chunks as possible into a static
1244 # string at compile time.
1245 body = []
1246 for child in node.nodes:
1247 try:
1248 if not allow_constant_finalize:
1249 raise nodes.Impossible()
1250 const = child.as_const(frame.eval_ctx)
1251 except nodes.Impossible:
1252 body.append(child)
1253 continue
1254 # the frame can't be volatile here, becaus otherwise the
1255 # as_const() function would raise an Impossible exception
1256 # at that point.
1257 try:
1258 if frame.eval_ctx.autoescape:
1259 if hasattr(const, '__html__'):
1260 const = const.__html__()
1261 else:
1262 const = escape(const)
1263 const = finalize(const)
1264 except Exception:
1265 # if something goes wrong here we evaluate the node
1266 # at runtime for easier debugging
1267 body.append(child)
1268 continue
1269 if body and isinstance(body[-1], list):
1270 body[-1].append(const)
1271 else:
1272 body.append([const])
1273
1274 # if we have less than 3 nodes or a buffer we yield or extend/append
1275 if len(body) < 3 or frame.buffer is not None:
1276 if frame.buffer is not None:
1277 # for one item we append, for more we extend
1278 if len(body) == 1:
1279 self.writeline('%s.append(' % frame.buffer)
1280 else:
1281 self.writeline('%s.extend((' % frame.buffer)
1282 self.indent()
1283 for item in body:
1284 if isinstance(item, list):
1285 val = repr(concat(item))
1286 if frame.buffer is None:
1287 self.writeline('yield ' + val)
1288 else:
1289 self.writeline(val + ', ')
1290 else:
1291 if frame.buffer is None:
1292 self.writeline('yield ', item)
1293 else:
1294 self.newline(item)
1295 close = 1
1296 if frame.eval_ctx.volatile:
1297 self.write('(context.eval_ctx.autoescape and'
1298 ' escape or to_string)(')
1299 elif frame.eval_ctx.autoescape:
1300 self.write('escape(')
1301 else:
1302 self.write('to_string(')
1303 if self.environment.finalize is not None:
1304 self.write('environment.finalize(')
1305 if getattr(self.environment.finalize,
1306 "contextfunction", False):
1307 self.write('context, ')
1308 close += 1
1309 self.visit(item, frame)
1310 self.write(')' * close)
1311 if frame.buffer is not None:
1312 self.write(', ')
1313 if frame.buffer is not None:
1314 # close the open parentheses
1315 self.outdent()
1316 self.writeline(len(body) == 1 and ')' or '))')
1317
1318 # otherwise we create a format string as this is faster in that case
1319 else:
1320 format = []
1321 arguments = []
1322 for item in body:
1323 if isinstance(item, list):
1324 format.append(concat(item).replace('%', '%%'))
1325 else:
1326 format.append('%s')
1327 arguments.append(item)
1328 self.writeline('yield ')
1329 self.write(repr(concat(format)) + ' % (')
1330 self.indent()
1331 for argument in arguments:
1332 self.newline(argument)
1333 close = 0
1334 if frame.eval_ctx.volatile:
1335 self.write('(context.eval_ctx.autoescape and'
1336 ' escape or to_string)(')
1337 close += 1
1338 elif frame.eval_ctx.autoescape:
1339 self.write('escape(')
1340 close += 1
1341 if self.environment.finalize is not None:
1342 self.write('environment.finalize(')
1343 if getattr(self.environment.finalize,
1344 'contextfunction', False):
1345 self.write('context, ')
1346 elif getattr(self.environment.finalize,
1347 'evalcontextfunction', False):
1348 self.write('context.eval_ctx, ')
1349 elif getattr(self.environment.finalize,
1350 'environmentfunction', False):
1351 self.write('environment, ')
1352 close += 1
1353 self.visit(argument, frame)
1354 self.write(')' * close + ', ')
1355 self.outdent()
1356 self.writeline(')')
1357
1358 if outdent_later:
1359 self.outdent()
1360
1361 def make_assignment_frame(self, frame):
1362 # toplevel assignments however go into the local namespace and
1363 # the current template's context. We create a copy of the frame
1364 # here and add a set so that the Name visitor can add the assigned
1365 # names here.
1366 if not frame.toplevel:
1367 return frame
1368 assignment_frame = frame.copy()
1369 assignment_frame.toplevel_assignments = set()
1370 return assignment_frame
1371
1372 def export_assigned_vars(self, frame, assignment_frame):
1373 if not frame.toplevel:
1374 return
1375 public_names = [x for x in assignment_frame.toplevel_assignments
1376 if not x.startswith('_')]
1377 if len(assignment_frame.toplevel_assignments) == 1:
1378 name = next(iter(assignment_frame.toplevel_assignments))
1379 self.writeline('context.vars[%r] = l_%s' % (name, name))
1380 else:
1381 self.writeline('context.vars.update({')
1382 for idx, name in enumerate(assignment_frame.toplevel_assignments):
1383 if idx:
1384 self.write(', ')
1385 self.write('%r: l_%s' % (name, name))
1386 self.write('})')
1387 if public_names:
1388 if len(public_names) == 1:
1389 self.writeline('context.exported_vars.add(%r)' %
1390 public_names[0])
1391 else:
1392 self.writeline('context.exported_vars.update((%s))' %
1393 ', '.join(imap(repr, public_names)))
1394
1395 def visit_Assign(self, node, frame):
1396 self.newline(node)
1397 assignment_frame = self.make_assignment_frame(frame)
1398 self.visit(node.target, assignment_frame)
1399 self.write(' = ')
1400 self.visit(node.node, frame)
1401 self.export_assigned_vars(frame, assignment_frame)
1402
1403 def visit_AssignBlock(self, node, frame):
1404 block_frame = frame.inner()
1405 block_frame.inspect(node.body)
1406 aliases = self.push_scope(block_frame)
1407 self.pull_locals(block_frame)
1408 self.buffer(block_frame)
1409 self.blockvisit(node.body, block_frame)
1410 self.pop_scope(aliases, block_frame)
1411
1412 assignment_frame = self.make_assignment_frame(frame)
1413 self.newline(node)
1414 self.visit(node.target, assignment_frame)
1415 self.write(' = concat(%s)' % block_frame.buffer)
1416 self.export_assigned_vars(frame, assignment_frame)
1417
1418 # -- Expression Visitors
1419
1420 def visit_Name(self, node, frame):
1421 if node.ctx == 'store' and frame.toplevel:
1422 frame.toplevel_assignments.add(node.name)
1423 self.write('l_' + node.name)
1424 frame.assigned_names.add(node.name)
1425
1426 def visit_Const(self, node, frame):
1427 val = node.value
1428 if isinstance(val, float):
1429 self.write(str(val))
1430 else:
1431 self.write(repr(val))
1432
1433 def visit_TemplateData(self, node, frame):
1434 try:
1435 self.write(repr(node.as_const(frame.eval_ctx)))
1436 except nodes.Impossible:
1437 self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)'
1438 % node.data)
1439
1440 def visit_Tuple(self, node, frame):
1441 self.write('(')
1442 idx = -1
1443 for idx, item in enumerate(node.items):
1444 if idx:
1445 self.write(', ')
1446 self.visit(item, frame)
1447 self.write(idx == 0 and ',)' or ')')
1448
1449 def visit_List(self, node, frame):
1450 self.write('[')
1451 for idx, item in enumerate(node.items):
1452 if idx:
1453 self.write(', ')
1454 self.visit(item, frame)
1455 self.write(']')
1456
1457 def visit_Dict(self, node, frame):
1458 self.write('{')
1459 for idx, item in enumerate(node.items):
1460 if idx:
1461 self.write(', ')
1462 self.visit(item.key, frame)
1463 self.write(': ')
1464 self.visit(item.value, frame)
1465 self.write('}')
1466
1467 def binop(operator, interceptable=True):
1468 def visitor(self, node, frame):
1469 if self.environment.sandboxed and \
1470 operator in self.environment.intercepted_binops:
1471 self.write('environment.call_binop(context, %r, ' % operator)
1472 self.visit(node.left, frame)
1473 self.write(', ')
1474 self.visit(node.right, frame)
1475 else:
1476 self.write('(')
1477 self.visit(node.left, frame)
1478 self.write(' %s ' % operator)
1479 self.visit(node.right, frame)
1480 self.write(')')
1481 return visitor
1482
1483 def uaop(operator, interceptable=True):
1484 def visitor(self, node, frame):
1485 if self.environment.sandboxed and \
1486 operator in self.environment.intercepted_unops:
1487 self.write('environment.call_unop(context, %r, ' % operator)
1488 self.visit(node.node, frame)
1489 else:
1490 self.write('(' + operator)
1491 self.visit(node.node, frame)
1492 self.write(')')
1493 return visitor
1494
1495 visit_Add = binop('+')
1496 visit_Sub = binop('-')
1497 visit_Mul = binop('*')
1498 visit_Div = binop('/')
1499 visit_FloorDiv = binop('//')
1500 visit_Pow = binop('**')
1501 visit_Mod = binop('%')
1502 visit_And = binop('and', interceptable=False)
1503 visit_Or = binop('or', interceptable=False)
1504 visit_Pos = uaop('+')
1505 visit_Neg = uaop('-')
1506 visit_Not = uaop('not ', interceptable=False)
1507 del binop, uaop
1508
1509 def visit_Concat(self, node, frame):
1510 if frame.eval_ctx.volatile:
1511 func_name = '(context.eval_ctx.volatile and' \
1512 ' markup_join or unicode_join)'
1513 elif frame.eval_ctx.autoescape:
1514 func_name = 'markup_join'
1515 else:
1516 func_name = 'unicode_join'
1517 self.write('%s((' % func_name)
1518 for arg in node.nodes:
1519 self.visit(arg, frame)
1520 self.write(', ')
1521 self.write('))')
1522
1523 def visit_Compare(self, node, frame):
1524 self.visit(node.expr, frame)
1525 for op in node.ops:
1526 self.visit(op, frame)
1527
1528 def visit_Operand(self, node, frame):
1529 self.write(' %s ' % operators[node.op])
1530 self.visit(node.expr, frame)
1531
1532 def visit_Getattr(self, node, frame):
1533 self.write('environment.getattr(')
1534 self.visit(node.node, frame)
1535 self.write(', %r)' % node.attr)
1536
1537 def visit_Getitem(self, node, frame):
1538 # slices bypass the environment getitem method.
1539 if isinstance(node.arg, nodes.Slice):
1540 self.visit(node.node, frame)
1541 self.write('[')
1542 self.visit(node.arg, frame)
1543 self.write(']')
1544 else:
1545 self.write('environment.getitem(')
1546 self.visit(node.node, frame)
1547 self.write(', ')
1548 self.visit(node.arg, frame)
1549 self.write(')')
1550
1551 def visit_Slice(self, node, frame):
1552 if node.start is not None:
1553 self.visit(node.start, frame)
1554 self.write(':')
1555 if node.stop is not None:
1556 self.visit(node.stop, frame)
1557 if node.step is not None:
1558 self.write(':')
1559 self.visit(node.step, frame)
1560
1561 def visit_Filter(self, node, frame):
1562 self.write(self.filters[node.name] + '(')
1563 func = self.environment.filters.get(node.name)
1564 if func is None:
1565 self.fail('no filter named %r' % node.name, node.lineno)
1566 if getattr(func, 'contextfilter', False):
1567 self.write('context, ')
1568 elif getattr(func, 'evalcontextfilter', False):
1569 self.write('context.eval_ctx, ')
1570 elif getattr(func, 'environmentfilter', False):
1571 self.write('environment, ')
1572
1573 # if the filter node is None we are inside a filter block
1574 # and want to write to the current buffer
1575 if node.node is not None:
1576 self.visit(node.node, frame)
1577 elif frame.eval_ctx.volatile:
1578 self.write('(context.eval_ctx.autoescape and'
1579 ' Markup(concat(%s)) or concat(%s))' %
1580 (frame.buffer, frame.buffer))
1581 elif frame.eval_ctx.autoescape:
1582 self.write('Markup(concat(%s))' % frame.buffer)
1583 else:
1584 self.write('concat(%s)' % frame.buffer)
1585 self.signature(node, frame)
1586 self.write(')')
1587
1588 def visit_Test(self, node, frame):
1589 self.write(self.tests[node.name] + '(')
1590 if node.name not in self.environment.tests:
1591 self.fail('no test named %r' % node.name, node.lineno)
1592 self.visit(node.node, frame)
1593 self.signature(node, frame)
1594 self.write(')')
1595
1596 def visit_CondExpr(self, node, frame):
1597 def write_expr2():
1598 if node.expr2 is not None:
1599 return self.visit(node.expr2, frame)
1600 self.write('environment.undefined(%r)' % ('the inline if-'
1601 'expression on %s evaluated to false and '
1602 'no else section was defined.' % self.position(node)))
1603
1604 self.write('(')
1605 self.visit(node.expr1, frame)
1606 self.write(' if ')
1607 self.visit(node.test, frame)
1608 self.write(' else ')
1609 write_expr2()
1610 self.write(')')
1611
1612 def visit_Call(self, node, frame, forward_caller=False):
1613 if self.environment.sandboxed:
1614 self.write('environment.call(context, ')
1615 else:
1616 self.write('context.call(')
1617 self.visit(node.node, frame)
1618 extra_kwargs = forward_caller and {'caller': 'caller'} or None
1619 self.signature(node, frame, extra_kwargs)
1620 self.write(')')
1621
1622 def visit_Keyword(self, node, frame):
1623 self.write(node.key + '=')
1624 self.visit(node.value, frame)
1625
1626 # -- Unused nodes for extensions
1627
1628 def visit_MarkSafe(self, node, frame):
1629 self.write('Markup(')
1630 self.visit(node.expr, frame)
1631 self.write(')')
1632
1633 def visit_MarkSafeIfAutoescape(self, node, frame):
1634 self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1635 self.visit(node.expr, frame)
1636 self.write(')')
1637
1638 def visit_EnvironmentAttribute(self, node, frame):
1639 self.write('environment.' + node.name)
1640
1641 def visit_ExtensionAttribute(self, node, frame):
1642 self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
1643
1644 def visit_ImportedName(self, node, frame):
1645 self.write(self.import_aliases[node.importname])
1646
1647 def visit_InternalName(self, node, frame):
1648 self.write(node.name)
1649
1650 def visit_ContextReference(self, node, frame):
1651 self.write('context')
1652
1653 def visit_Continue(self, node, frame):
1654 self.writeline('continue', node)
1655
1656 def visit_Break(self, node, frame):
1657 self.writeline('break', node)
1658
1659 def visit_Scope(self, node, frame):
1660 scope_frame = frame.inner()
1661 scope_frame.inspect(node.iter_child_nodes())
1662 aliases = self.push_scope(scope_frame)
1663 self.pull_locals(scope_frame)
1664 self.blockvisit(node.body, scope_frame)
1665 self.pop_scope(aliases, scope_frame)
1666
1667 def visit_EvalContextModifier(self, node, frame):
1668 for keyword in node.options:
1669 self.writeline('context.eval_ctx.%s = ' % keyword.key)
1670 self.visit(keyword.value, frame)
1671 try:
1672 val = keyword.value.as_const(frame.eval_ctx)
1673 except nodes.Impossible:
1674 frame.eval_ctx.volatile = True
1675 else:
1676 setattr(frame.eval_ctx, keyword.key, val)
1677
1678 def visit_ScopedEvalContextModifier(self, node, frame):
1679 old_ctx_name = self.temporary_identifier()
1680 safed_ctx = frame.eval_ctx.save()
1681 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1682 self.visit_EvalContextModifier(node, frame)
1683 for child in node.body:
1684 self.visit(child, frame)
1685 frame.eval_ctx.revert(safed_ctx)
1686 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)