1
# -*- coding: utf-8 -*-
6
Compiles nodes into python code.
8
:copyright: (c) 2010 by the Jinja Team.
9
:license: BSD, see LICENSE for more details.
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, next, text_type, string_types, \
20
iteritems, NativeStringIO, imap
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'
39
dict_item_iter = 'items'
42
# does if 0: dummy(x) get us x into the scope?
43
def unoptimize_before_dead_code():
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))
55
def generate(node, environment, name, filename, stream=None,
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 = CodeGenerator(environment, name, filename, stream, defer_init)
63
return generator.stream.getvalue()
66
def has_safe_repr(value):
67
"""Does the node have a safe representation?"""
68
if value is None or value is NotImplemented or value is Ellipsis:
70
if isinstance(value, (bool, int, float, complex, range_type,
71
Markup) + string_types):
73
if isinstance(value, (tuple, list, set, frozenset)):
75
if not has_safe_repr(item):
78
elif isinstance(value, dict):
79
for key, value in iteritems(value):
80
if not has_safe_repr(key):
82
if not has_safe_repr(value):
88
def find_undeclared(nodes, names):
89
"""Check if the names passed are accessed undeclared. The return value
90
is a set of all the undeclared names from the sequence of names found.
92
visitor = UndeclaredNameVisitor(names)
98
return visitor.undeclared
101
class Identifiers(object):
102
"""Tracks the status of identifiers in frames."""
105
# variables that are known to be declared (probably from outer
106
# frames or because they are special for the frame)
107
self.declared = set()
109
# undeclared variables from outer scopes
110
self.outer_undeclared = set()
112
# names that are accessed without being explicitly declared by
113
# this one or any of the outer scopes. Names can appear both in
114
# declared and undeclared.
115
self.undeclared = set()
117
# names that are declared locally
118
self.declared_locally = set()
120
# names that are declared by parameters
121
self.declared_parameter = set()
123
def add_special(self, name):
124
"""Register a special name like `loop`."""
125
self.undeclared.discard(name)
126
self.declared.add(name)
128
def is_declared(self, name):
129
"""Check if a name is declared in this or an outer scope."""
130
if name in self.declared_locally or name in self.declared_parameter:
132
return name in self.declared
135
return deepcopy(self)
139
"""Holds compile time information for us."""
141
def __init__(self, eval_ctx, parent=None):
142
self.eval_ctx = eval_ctx
143
self.identifiers = Identifiers()
145
# a toplevel frame is the root + soft frames such as if conditions.
146
self.toplevel = False
148
# the root frame is basically just the outermost frame, so no if
149
# conditions. This information is used to optimize inheritance
151
self.rootlevel = False
153
# in some dynamic inheritance situations the compiler needs to add
154
# write tests around output statements.
155
self.require_output_check = parent and parent.require_output_check
157
# inside some tags we are using a buffer rather than yield statements.
158
# this for example affects {% filter %} or {% macro %}. If a frame
159
# is buffered this variable points to the name of the list used as
163
# the name of the block we're in, otherwise None.
164
self.block = parent and parent.block or None
166
# a set of actually assigned names
167
self.assigned_names = set()
169
# the parent of this frame
172
if parent is not None:
173
self.identifiers.declared.update(
174
parent.identifiers.declared |
175
parent.identifiers.declared_parameter |
176
parent.assigned_names
178
self.identifiers.outer_undeclared.update(
179
parent.identifiers.undeclared -
180
self.identifiers.declared
182
self.buffer = parent.buffer
185
"""Create a copy of the current one."""
186
rv = object.__new__(self.__class__)
187
rv.__dict__.update(self.__dict__)
188
rv.identifiers = object.__new__(self.identifiers.__class__)
189
rv.identifiers.__dict__.update(self.identifiers.__dict__)
192
def inspect(self, nodes):
193
"""Walk the node and check for identifiers. If the scope is hard (eg:
194
enforce on a python level) overrides from outer scopes are tracked
197
visitor = FrameIdentifierVisitor(self.identifiers)
201
def find_shadowed(self, extra=()):
202
"""Find all the shadowed names. extra is an iterable of variables
203
that may be defined with `add_special` which may occour scoped.
206
return (i.declared | i.outer_undeclared) & \
207
(i.declared_locally | i.declared_parameter) | \
208
set(x for x in extra if i.is_declared(x))
211
"""Return an inner frame."""
212
return Frame(self.eval_ctx, self)
215
"""Return a soft frame. A soft frame may not be modified as
216
standalone thing as it shares the resources with the frame it
217
was created of, but it's not a rootlevel frame any longer.
226
class VisitorExit(RuntimeError):
227
"""Exception used by the `UndeclaredNameVisitor` to signal a stop."""
230
class DependencyFinderVisitor(NodeVisitor):
231
"""A visitor that collects filter and test calls."""
237
def visit_Filter(self, node):
238
self.generic_visit(node)
239
self.filters.add(node.name)
241
def visit_Test(self, node):
242
self.generic_visit(node)
243
self.tests.add(node.name)
245
def visit_Block(self, node):
246
"""Stop visiting at blocks."""
249
class UndeclaredNameVisitor(NodeVisitor):
250
"""A visitor that checks if a name is accessed without being
251
declared. This is different from the frame visitor as it will
252
not stop at closure frames.
255
def __init__(self, names):
256
self.names = set(names)
257
self.undeclared = set()
259
def visit_Name(self, node):
260
if node.ctx == 'load' and node.name in self.names:
261
self.undeclared.add(node.name)
262
if self.undeclared == self.names:
265
self.names.discard(node.name)
267
def visit_Block(self, node):
268
"""Stop visiting a blocks."""
271
class FrameIdentifierVisitor(NodeVisitor):
272
"""A visitor for `Frame.inspect`."""
274
def __init__(self, identifiers):
275
self.identifiers = identifiers
277
def visit_Name(self, node):
278
"""All assignments to names go through this function."""
279
if node.ctx == 'store':
280
self.identifiers.declared_locally.add(node.name)
281
elif node.ctx == 'param':
282
self.identifiers.declared_parameter.add(node.name)
283
elif node.ctx == 'load' and not \
284
self.identifiers.is_declared(node.name):
285
self.identifiers.undeclared.add(node.name)
287
def visit_If(self, node):
288
self.visit(node.test)
289
real_identifiers = self.identifiers
291
old_names = real_identifiers.declared_locally | \
292
real_identifiers.declared_parameter
294
def inner_visit(nodes):
297
self.identifiers = real_identifiers.copy()
298
for subnode in nodes:
300
rv = self.identifiers.declared_locally - old_names
301
# we have to remember the undeclared variables of this branch
302
# because we will have to pull them.
303
real_identifiers.undeclared.update(self.identifiers.undeclared)
304
self.identifiers = real_identifiers
307
body = inner_visit(node.body)
308
else_ = inner_visit(node.else_ or ())
310
# the differences between the two branches are also pulled as
311
# undeclared variables
312
real_identifiers.undeclared.update(body.symmetric_difference(else_) -
313
real_identifiers.declared)
315
# remember those that are declared.
316
real_identifiers.declared_locally.update(body | else_)
318
def visit_Macro(self, node):
319
self.identifiers.declared_locally.add(node.name)
321
def visit_Import(self, node):
322
self.generic_visit(node)
323
self.identifiers.declared_locally.add(node.target)
325
def visit_FromImport(self, node):
326
self.generic_visit(node)
327
for name in node.names:
328
if isinstance(name, tuple):
329
self.identifiers.declared_locally.add(name[1])
331
self.identifiers.declared_locally.add(name)
333
def visit_Assign(self, node):
334
"""Visit assignments in the correct order."""
335
self.visit(node.node)
336
self.visit(node.target)
338
def visit_For(self, node):
339
"""Visiting stops at for blocks. However the block sequence
340
is visited as part of the outer scope.
342
self.visit(node.iter)
344
def visit_CallBlock(self, node):
345
self.visit(node.call)
347
def visit_FilterBlock(self, node):
348
self.visit(node.filter)
350
def visit_Scope(self, node):
351
"""Stop visiting at scopes."""
353
def visit_Block(self, node):
354
"""Stop visiting at blocks."""
357
class CompilerExit(Exception):
358
"""Raised if the compiler encountered a situation where it just
359
doesn't make sense to further process the code. Any block that
360
raises such an exception is not further processed.
364
class CodeGenerator(NodeVisitor):
366
def __init__(self, environment, name, filename, stream=None,
369
stream = NativeStringIO()
370
self.environment = environment
372
self.filename = filename
374
self.created_block_context = False
375
self.defer_init = defer_init
377
# aliases for imports
378
self.import_aliases = {}
380
# a registry for all blocks. Because blocks are moved out
381
# into the global python scope they are registered here
384
# the number of extends statements so far
385
self.extends_so_far = 0
387
# some templates have a rootlevel extends. In this case we
388
# can safely assume that we're a child template and do some
389
# more optimizations.
390
self.has_known_extends = False
392
# the current line number
395
# registry of all filters and tests (global, not block local)
399
# the debug information
401
self._write_debug_info = None
403
# the number of new lines before the next write()
406
# the line number of the last written statement
409
# true if nothing was written so far.
410
self._first_write = True
412
# used by the `temporary_identifier` method to get new
413
# unique, temporary identifier
414
self._last_identifier = 0
416
# the current indentation
417
self._indentation = 0
419
# -- Various compilation helpers
421
def fail(self, msg, lineno):
422
"""Fail with a :exc:`TemplateAssertionError`."""
423
raise TemplateAssertionError(msg, lineno, self.name, self.filename)
425
def temporary_identifier(self):
426
"""Get a new unique identifier."""
427
self._last_identifier += 1
428
return 't_%d' % self._last_identifier
430
def buffer(self, frame):
431
"""Enable buffering for the frame from that point onwards."""
432
frame.buffer = self.temporary_identifier()
433
self.writeline('%s = []' % frame.buffer)
435
def return_buffer_contents(self, frame):
436
"""Return the buffer contents of the frame."""
437
if frame.eval_ctx.volatile:
438
self.writeline('if context.eval_ctx.autoescape:')
440
self.writeline('return Markup(concat(%s))' % frame.buffer)
442
self.writeline('else:')
444
self.writeline('return concat(%s)' % frame.buffer)
446
elif frame.eval_ctx.autoescape:
447
self.writeline('return Markup(concat(%s))' % frame.buffer)
449
self.writeline('return concat(%s)' % frame.buffer)
453
self._indentation += 1
455
def outdent(self, step=1):
456
"""Outdent by step."""
457
self._indentation -= step
459
def start_write(self, frame, node=None):
460
"""Yield or write into the frame buffer."""
461
if frame.buffer is None:
462
self.writeline('yield ', node)
464
self.writeline('%s.append(' % frame.buffer, node)
466
def end_write(self, frame):
467
"""End the writing process started by `start_write`."""
468
if frame.buffer is not None:
471
def simple_write(self, s, frame, node=None):
472
"""Simple shortcut for start_write + write + end_write."""
473
self.start_write(frame, node)
475
self.end_write(frame)
477
def blockvisit(self, nodes, frame):
478
"""Visit a list of nodes as block in a frame. If the current frame
479
is no buffer a dummy ``if 0: yield None`` is written automatically
480
unless the force_generator parameter is set to False.
482
if frame.buffer is None:
483
self.writeline('if 0: yield None')
485
self.writeline('pass')
488
self.visit(node, frame)
493
"""Write a string into the output stream."""
495
if not self._first_write:
496
self.stream.write('\n' * self._new_lines)
497
self.code_lineno += self._new_lines
498
if self._write_debug_info is not None:
499
self.debug_info.append((self._write_debug_info,
501
self._write_debug_info = None
502
self._first_write = False
503
self.stream.write(' ' * self._indentation)
507
def writeline(self, x, node=None, extra=0):
508
"""Combination of newline and write."""
509
self.newline(node, extra)
512
def newline(self, node=None, extra=0):
513
"""Add one or more newlines before the next write."""
514
self._new_lines = max(self._new_lines, 1 + extra)
515
if node is not None and node.lineno != self._last_line:
516
self._write_debug_info = node.lineno
517
self._last_line = node.lineno
519
def signature(self, node, frame, extra_kwargs=None):
520
"""Writes a function call to the stream for the current node.
521
A leading comma is added automatically. The extra keyword
522
arguments may not include python keywords otherwise a syntax
523
error could occour. The extra keyword arguments should be given
526
# if any of the given keyword arguments is a python keyword
527
# we have to make sure that no invalid call is created.
528
kwarg_workaround = False
529
for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
530
if is_python_keyword(kwarg):
531
kwarg_workaround = True
534
for arg in node.args:
536
self.visit(arg, frame)
538
if not kwarg_workaround:
539
for kwarg in node.kwargs:
541
self.visit(kwarg, frame)
542
if extra_kwargs is not None:
543
for key, value in iteritems(extra_kwargs):
544
self.write(', %s=%s' % (key, value))
547
self.visit(node.dyn_args, frame)
550
if node.dyn_kwargs is not None:
551
self.write(', **dict({')
554
for kwarg in node.kwargs:
555
self.write('%r: ' % kwarg.key)
556
self.visit(kwarg.value, frame)
558
if extra_kwargs is not None:
559
for key, value in iteritems(extra_kwargs):
560
self.write('%r: %s, ' % (key, value))
561
if node.dyn_kwargs is not None:
563
self.visit(node.dyn_kwargs, frame)
568
elif node.dyn_kwargs is not None:
570
self.visit(node.dyn_kwargs, frame)
572
def pull_locals(self, frame):
573
"""Pull all the references identifiers into the local scope."""
574
for name in frame.identifiers.undeclared:
575
self.writeline('l_%s = context.resolve(%r)' % (name, name))
577
def pull_dependencies(self, nodes):
578
"""Pull all the dependencies."""
579
visitor = DependencyFinderVisitor()
582
for dependency in 'filters', 'tests':
583
mapping = getattr(self, dependency)
584
for name in getattr(visitor, dependency):
585
if name not in mapping:
586
mapping[name] = self.temporary_identifier()
587
self.writeline('%s = environment.%s[%r]' %
588
(mapping[name], dependency, name))
590
def unoptimize_scope(self, frame):
591
"""Disable Python optimizations for the frame."""
592
# XXX: this is not that nice but it has no real overhead. It
593
# mainly works because python finds the locals before dead code
594
# is removed. If that breaks we have to add a dummy function
595
# that just accepts the arguments and does nothing.
596
if frame.identifiers.declared:
597
self.writeline('%sdummy(%s)' % (
598
unoptimize_before_dead_code and 'if 0: ' or '',
599
', '.join('l_' + name for name in frame.identifiers.declared)
602
def push_scope(self, frame, extra_vars=()):
603
"""This function returns all the shadowed variables in a dict
604
in the form name: alias and will write the required assignments
605
into the current scope. No indentation takes place.
607
This also predefines locally declared variables from the loop
608
body because under some circumstances it may be the case that
610
`extra_vars` is passed to `Frame.find_shadowed`.
613
for name in frame.find_shadowed(extra_vars):
614
aliases[name] = ident = self.temporary_identifier()
615
self.writeline('%s = l_%s' % (ident, name))
617
for name in frame.identifiers.declared_locally:
618
if name not in aliases:
619
to_declare.add('l_' + name)
621
self.writeline(' = '.join(to_declare) + ' = missing')
624
def pop_scope(self, aliases, frame):
625
"""Restore all aliases and delete unused variables."""
626
for name, alias in iteritems(aliases):
627
self.writeline('l_%s = %s' % (name, alias))
629
for name in frame.identifiers.declared_locally:
630
if name not in aliases:
631
to_delete.add('l_' + name)
633
# we cannot use the del statement here because enclosed
634
# scopes can trigger a SyntaxError:
635
# a = 42; b = lambda: a; del a
636
self.writeline(' = '.join(to_delete) + ' = missing')
638
def function_scoping(self, node, frame, children=None,
640
"""In Jinja a few statements require the help of anonymous
641
functions. Those are currently macros and call blocks and in
642
the future also recursive loops. As there is currently
643
technical limitation that doesn't allow reading and writing a
644
variable in a scope where the initial value is coming from an
645
outer scope, this function tries to fall back with a common
646
error message. Additionally the frame passed is modified so
647
that the argumetns are collected and callers are looked up.
649
This will return the modified frame.
651
# we have to iterate twice over it, make sure that works
653
children = node.iter_child_nodes()
654
children = list(children)
655
func_frame = frame.inner()
656
func_frame.inspect(children)
658
# variables that are undeclared (accessed before declaration) and
659
# declared locally *and* part of an outside scope raise a template
660
# assertion error. Reason: we can't generate reasonable code from
661
# it without aliasing all the variables.
662
# this could be fixed in Python 3 where we have the nonlocal
663
# keyword or if we switch to bytecode generation
664
overridden_closure_vars = (
665
func_frame.identifiers.undeclared &
666
func_frame.identifiers.declared &
667
(func_frame.identifiers.declared_locally |
668
func_frame.identifiers.declared_parameter)
670
if overridden_closure_vars:
671
self.fail('It\'s not possible to set and access variables '
672
'derived from an outer scope! (affects: %s)' %
673
', '.join(sorted(overridden_closure_vars)), node.lineno)
675
# remove variables from a closure from the frame's undeclared
677
func_frame.identifiers.undeclared -= (
678
func_frame.identifiers.undeclared &
679
func_frame.identifiers.declared
682
# no special variables for this scope, abort early
686
func_frame.accesses_kwargs = False
687
func_frame.accesses_varargs = False
688
func_frame.accesses_caller = False
689
func_frame.arguments = args = ['l_' + x.name for x in node.args]
691
undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
693
if 'caller' in undeclared:
694
func_frame.accesses_caller = True
695
func_frame.identifiers.add_special('caller')
696
args.append('l_caller')
697
if 'kwargs' in undeclared:
698
func_frame.accesses_kwargs = True
699
func_frame.identifiers.add_special('kwargs')
700
args.append('l_kwargs')
701
if 'varargs' in undeclared:
702
func_frame.accesses_varargs = True
703
func_frame.identifiers.add_special('varargs')
704
args.append('l_varargs')
707
def macro_body(self, node, frame, children=None):
708
"""Dump the function def of a macro or call block."""
709
frame = self.function_scoping(node, frame, children)
710
# macros are delayed, they never require output checks
711
frame.require_output_check = False
712
args = frame.arguments
713
# XXX: this is an ugly fix for the loop nesting bug
714
# (tests.test_old_bugs.test_loop_call_bug). This works around
715
# a identifier nesting problem we have in general. It's just more
716
# likely to happen in loops which is why we work around it. The
717
# real solution would be "nonlocal" all the identifiers that are
718
# leaking into a new python frame and might be used both unassigned
720
if 'loop' in frame.identifiers.declared:
721
args = args + ['l_loop=l_loop']
722
self.writeline('def macro(%s):' % ', '.join(args), node)
725
self.pull_locals(frame)
726
self.blockvisit(node.body, frame)
727
self.return_buffer_contents(frame)
731
def macro_def(self, node, frame):
732
"""Dump the macro definition for the def created by macro_body."""
733
arg_tuple = ', '.join(repr(x.name) for x in node.args)
734
name = getattr(node, 'name', None)
735
if len(node.args) == 1:
737
self.write('Macro(environment, macro, %r, (%s), (' %
739
for arg in node.defaults:
740
self.visit(arg, frame)
742
self.write('), %r, %r, %r)' % (
743
bool(frame.accesses_kwargs),
744
bool(frame.accesses_varargs),
745
bool(frame.accesses_caller)
748
def position(self, node):
749
"""Return a human readable position for the node."""
750
rv = 'line %d' % node.lineno
751
if self.name is not None:
752
rv += ' in ' + repr(self.name)
755
# -- Statement Visitors
757
def visit_Template(self, node, frame=None):
758
assert frame is None, 'no root frame allowed'
759
eval_ctx = EvalContext(self.environment, self.name)
761
from jinja2.runtime import __all__ as exported
762
self.writeline('from __future__ import division')
763
self.writeline('from jinja2.runtime import ' + ', '.join(exported))
764
if not unoptimize_before_dead_code:
765
self.writeline('dummy = lambda *x: None')
767
# if we want a deferred initialization we cannot move the
768
# environment into a local name
769
envenv = not self.defer_init and ', environment=environment' or ''
771
# do we have an extends tag at all? If not, we can save some
772
# overhead by just not processing any inheritance code.
773
have_extends = node.find(nodes.Extends) is not None
776
for block in node.find_all(nodes.Block):
777
if block.name in self.blocks:
778
self.fail('block %r defined twice' % block.name, block.lineno)
779
self.blocks[block.name] = block
781
# find all imports and import them
782
for import_ in node.find_all(nodes.ImportedName):
783
if import_.importname not in self.import_aliases:
784
imp = import_.importname
785
self.import_aliases[imp] = alias = self.temporary_identifier()
787
module, obj = imp.rsplit('.', 1)
788
self.writeline('from %s import %s as %s' %
789
(module, obj, alias))
791
self.writeline('import %s as %s' % (imp, alias))
794
self.writeline('name = %r' % self.name)
796
# generate the root render function.
797
self.writeline('def root(context%s):' % envenv, extra=1)
800
frame = Frame(eval_ctx)
801
frame.inspect(node.body)
802
frame.toplevel = frame.rootlevel = True
803
frame.require_output_check = have_extends and not self.has_known_extends
806
self.writeline('parent_template = None')
807
if 'self' in find_undeclared(node.body, ('self',)):
808
frame.identifiers.add_special('self')
809
self.writeline('l_self = TemplateReference(context)')
810
self.pull_locals(frame)
811
self.pull_dependencies(node.body)
812
self.blockvisit(node.body, frame)
815
# make sure that the parent root is called.
817
if not self.has_known_extends:
819
self.writeline('if parent_template is not None:')
821
self.writeline('for event in parent_template.'
822
'root_render_func(context):')
824
self.writeline('yield event')
825
self.outdent(2 + (not self.has_known_extends))
827
# at this point we now have the blocks collected and can visit them too.
828
for name, block in iteritems(self.blocks):
829
block_frame = Frame(eval_ctx)
830
block_frame.inspect(block.body)
831
block_frame.block = name
832
self.writeline('def block_%s(context%s):' % (name, envenv),
835
undeclared = find_undeclared(block.body, ('self', 'super'))
836
if 'self' in undeclared:
837
block_frame.identifiers.add_special('self')
838
self.writeline('l_self = TemplateReference(context)')
839
if 'super' in undeclared:
840
block_frame.identifiers.add_special('super')
841
self.writeline('l_super = context.super(%r, '
842
'block_%s)' % (name, name))
843
self.pull_locals(block_frame)
844
self.pull_dependencies(block.body)
845
self.blockvisit(block.body, block_frame)
848
self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
849
for x in self.blocks),
852
# add a function that returns the debug info
853
self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
856
def visit_Block(self, node, frame):
857
"""Call a block and register it for the template."""
860
# if we know that we are a child template, there is no need to
861
# check if we are one
862
if self.has_known_extends:
864
if self.extends_so_far > 0:
865
self.writeline('if parent_template is None:')
868
context = node.scoped and 'context.derived(locals())' or 'context'
869
self.writeline('for event in context.blocks[%r][0](%s):' % (
870
node.name, context), node)
872
self.simple_write('event', frame)
875
def visit_Extends(self, node, frame):
876
"""Calls the extender."""
877
if not frame.toplevel:
878
self.fail('cannot use extend from a non top-level scope',
881
# if the number of extends statements in general is zero so
882
# far, we don't have to add a check if something extended
883
# the template before this one.
884
if self.extends_so_far > 0:
886
# if we have a known extends we just add a template runtime
887
# error into the generated code. We could catch that at compile
888
# time too, but i welcome it not to confuse users by throwing the
889
# same error at different times just "because we can".
890
if not self.has_known_extends:
891
self.writeline('if parent_template is not None:')
893
self.writeline('raise TemplateRuntimeError(%r)' %
894
'extended multiple times')
896
# if we have a known extends already we don't need that code here
897
# as we know that the template execution will end here.
898
if self.has_known_extends:
903
self.writeline('parent_template = environment.get_template(', node)
904
self.visit(node.template, frame)
905
self.write(', %r)' % self.name)
906
self.writeline('for name, parent_block in parent_template.'
907
'blocks.%s():' % dict_item_iter)
909
self.writeline('context.blocks.setdefault(name, []).'
910
'append(parent_block)')
913
# if this extends statement was in the root level we can take
914
# advantage of that information and simplify the generated code
915
# in the top level from this point onwards
917
self.has_known_extends = True
919
# and now we have one more
920
self.extends_so_far += 1
922
def visit_Include(self, node, frame):
923
"""Handles includes."""
924
if node.with_context:
925
self.unoptimize_scope(frame)
926
if node.ignore_missing:
927
self.writeline('try:')
930
func_name = 'get_or_select_template'
931
if isinstance(node.template, nodes.Const):
932
if isinstance(node.template.value, string_types):
933
func_name = 'get_template'
934
elif isinstance(node.template.value, (tuple, list)):
935
func_name = 'select_template'
936
elif isinstance(node.template, (nodes.Tuple, nodes.List)):
937
func_name = 'select_template'
939
self.writeline('template = environment.%s(' % func_name, node)
940
self.visit(node.template, frame)
941
self.write(', %r)' % self.name)
942
if node.ignore_missing:
944
self.writeline('except TemplateNotFound:')
946
self.writeline('pass')
948
self.writeline('else:')
951
if node.with_context:
952
self.writeline('for event in template.root_render_func('
953
'template.new_context(context.parent, True, '
956
self.writeline('for event in template.module._body_stream:')
959
self.simple_write('event', frame)
962
if node.ignore_missing:
965
def visit_Import(self, node, frame):
966
"""Visit regular imports."""
967
if node.with_context:
968
self.unoptimize_scope(frame)
969
self.writeline('l_%s = ' % node.target, node)
971
self.write('context.vars[%r] = ' % node.target)
972
self.write('environment.get_template(')
973
self.visit(node.template, frame)
974
self.write(', %r).' % self.name)
975
if node.with_context:
976
self.write('make_module(context.parent, True, locals())')
979
if frame.toplevel and not node.target.startswith('_'):
980
self.writeline('context.exported_vars.discard(%r)' % node.target)
981
frame.assigned_names.add(node.target)
983
def visit_FromImport(self, node, frame):
984
"""Visit named imports."""
986
self.write('included_template = environment.get_template(')
987
self.visit(node.template, frame)
988
self.write(', %r).' % self.name)
989
if node.with_context:
990
self.write('make_module(context.parent, True)')
996
for name in node.names:
997
if isinstance(name, tuple):
1001
self.writeline('l_%s = getattr(included_template, '
1002
'%r, missing)' % (alias, name))
1003
self.writeline('if l_%s is missing:' % alias)
1005
self.writeline('l_%s = environment.undefined(%r %% '
1006
'included_template.__name__, '
1008
(alias, 'the template %%r (imported on %s) does '
1009
'not export the requested name %s' % (
1010
self.position(node),
1015
var_names.append(alias)
1016
if not alias.startswith('_'):
1017
discarded_names.append(alias)
1018
frame.assigned_names.add(alias)
1021
if len(var_names) == 1:
1023
self.writeline('context.vars[%r] = l_%s' % (name, name))
1025
self.writeline('context.vars.update({%s})' % ', '.join(
1026
'%r: l_%s' % (name, name) for name in var_names
1029
if len(discarded_names) == 1:
1030
self.writeline('context.exported_vars.discard(%r)' %
1033
self.writeline('context.exported_vars.difference_'
1034
'update((%s))' % ', '.join(imap(repr, discarded_names)))
1036
def visit_For(self, node, frame):
1037
# when calculating the nodes for the inner frame we have to exclude
1038
# the iterator contents from it
1039
children = node.iter_child_nodes(exclude=('iter',))
1041
loop_frame = self.function_scoping(node, frame, children,
1044
loop_frame = frame.inner()
1045
loop_frame.inspect(children)
1047
# try to figure out if we have an extended loop. An extended loop
1048
# is necessary if the loop is in recursive mode if the special loop
1049
# variable is accessed in the body.
1050
extended_loop = node.recursive or 'loop' in \
1051
find_undeclared(node.iter_child_nodes(
1052
only=('body',)), ('loop',))
1054
# if we don't have an recursive loop we have to find the shadowed
1055
# variables at that point. Because loops can be nested but the loop
1056
# variable is a special one we have to enforce aliasing for it.
1057
if not node.recursive:
1058
aliases = self.push_scope(loop_frame, ('loop',))
1060
# otherwise we set up a buffer and add a function def
1062
self.writeline('def loop(reciter, loop_render_func, depth=0):', node)
1064
self.buffer(loop_frame)
1067
# make sure the loop variable is a special one and raise a template
1068
# assertion error if a loop tries to write to loop
1070
self.writeline('l_loop = missing')
1071
loop_frame.identifiers.add_special('loop')
1072
for name in node.find_all(nodes.Name):
1073
if name.ctx == 'store' and name.name == 'loop':
1074
self.fail('Can\'t assign to special loop variable '
1075
'in for-loop target', name.lineno)
1077
self.pull_locals(loop_frame)
1079
iteration_indicator = self.temporary_identifier()
1080
self.writeline('%s = 1' % iteration_indicator)
1082
# Create a fake parent loop if the else or test section of a
1083
# loop is accessing the special loop variable and no parent loop
1085
if 'loop' not in aliases and 'loop' in find_undeclared(
1086
node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
1087
self.writeline("l_loop = environment.undefined(%r, name='loop')" %
1088
("'loop' is undefined. the filter section of a loop as well "
1089
"as the else block don't have access to the special 'loop'"
1090
" variable of the current loop. Because there is no parent "
1091
"loop it's undefined. Happened in loop on %s" %
1092
self.position(node)))
1094
self.writeline('for ', node)
1095
self.visit(node.target, loop_frame)
1096
self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
1098
# if we have an extened loop and a node test, we filter in the
1100
if extended_loop and node.test is not None:
1102
self.visit(node.target, loop_frame)
1104
self.visit(node.target, loop_frame)
1107
self.write('reciter')
1109
self.visit(node.iter, loop_frame)
1111
test_frame = loop_frame.copy()
1112
self.visit(node.test, test_frame)
1115
elif node.recursive:
1116
self.write('reciter')
1118
self.visit(node.iter, loop_frame)
1121
self.write(', loop_render_func, depth):')
1123
self.write(extended_loop and '):' or ':')
1125
# tests in not extended loops become a continue
1126
if not extended_loop and node.test is not None:
1128
self.writeline('if not ')
1129
self.visit(node.test, loop_frame)
1132
self.writeline('continue')
1136
self.blockvisit(node.body, loop_frame)
1138
self.writeline('%s = 0' % iteration_indicator)
1142
self.writeline('if %s:' % iteration_indicator)
1144
self.blockvisit(node.else_, loop_frame)
1147
# reset the aliases if there are any.
1148
if not node.recursive:
1149
self.pop_scope(aliases, loop_frame)
1151
# if the node was recursive we have to return the buffer contents
1152
# and start the iteration code
1154
self.return_buffer_contents(loop_frame)
1156
self.start_write(frame, node)
1158
self.visit(node.iter, frame)
1159
self.write(', loop)')
1160
self.end_write(frame)
1162
def visit_If(self, node, frame):
1163
if_frame = frame.soft()
1164
self.writeline('if ', node)
1165
self.visit(node.test, if_frame)
1168
self.blockvisit(node.body, if_frame)
1171
self.writeline('else:')
1173
self.blockvisit(node.else_, if_frame)
1176
def visit_Macro(self, node, frame):
1177
macro_frame = self.macro_body(node, frame)
1180
if not node.name.startswith('_'):
1181
self.write('context.exported_vars.add(%r)' % node.name)
1182
self.writeline('context.vars[%r] = ' % node.name)
1183
self.write('l_%s = ' % node.name)
1184
self.macro_def(node, macro_frame)
1185
frame.assigned_names.add(node.name)
1187
def visit_CallBlock(self, node, frame):
1188
children = node.iter_child_nodes(exclude=('call',))
1189
call_frame = self.macro_body(node, frame, children)
1190
self.writeline('caller = ')
1191
self.macro_def(node, call_frame)
1192
self.start_write(frame, node)
1193
self.visit_Call(node.call, call_frame, forward_caller=True)
1194
self.end_write(frame)
1196
def visit_FilterBlock(self, node, frame):
1197
filter_frame = frame.inner()
1198
filter_frame.inspect(node.iter_child_nodes())
1199
aliases = self.push_scope(filter_frame)
1200
self.pull_locals(filter_frame)
1201
self.buffer(filter_frame)
1202
self.blockvisit(node.body, filter_frame)
1203
self.start_write(frame, node)
1204
self.visit_Filter(node.filter, filter_frame)
1205
self.end_write(frame)
1206
self.pop_scope(aliases, filter_frame)
1208
def visit_ExprStmt(self, node, frame):
1210
self.visit(node.node, frame)
1212
def visit_Output(self, node, frame):
1213
# if we have a known extends statement, we don't output anything
1214
# if we are in a require_output_check section
1215
if self.has_known_extends and frame.require_output_check:
1218
if self.environment.finalize:
1219
finalize = lambda x: text_type(self.environment.finalize(x))
1221
finalize = text_type
1223
# if we are inside a frame that requires output checking, we do so
1224
outdent_later = False
1225
if frame.require_output_check:
1226
self.writeline('if parent_template is None:')
1228
outdent_later = True
1230
# try to evaluate as many chunks as possible into a static
1231
# string at compile time.
1233
for child in node.nodes:
1235
const = child.as_const(frame.eval_ctx)
1236
except nodes.Impossible:
1239
# the frame can't be volatile here, becaus otherwise the
1240
# as_const() function would raise an Impossible exception
1243
if frame.eval_ctx.autoescape:
1244
if hasattr(const, '__html__'):
1245
const = const.__html__()
1247
const = escape(const)
1248
const = finalize(const)
1250
# if something goes wrong here we evaluate the node
1251
# at runtime for easier debugging
1254
if body and isinstance(body[-1], list):
1255
body[-1].append(const)
1257
body.append([const])
1259
# if we have less than 3 nodes or a buffer we yield or extend/append
1260
if len(body) < 3 or frame.buffer is not None:
1261
if frame.buffer is not None:
1262
# for one item we append, for more we extend
1264
self.writeline('%s.append(' % frame.buffer)
1266
self.writeline('%s.extend((' % frame.buffer)
1269
if isinstance(item, list):
1270
val = repr(concat(item))
1271
if frame.buffer is None:
1272
self.writeline('yield ' + val)
1274
self.writeline(val + ', ')
1276
if frame.buffer is None:
1277
self.writeline('yield ', item)
1281
if frame.eval_ctx.volatile:
1282
self.write('(context.eval_ctx.autoescape and'
1283
' escape or to_string)(')
1284
elif frame.eval_ctx.autoescape:
1285
self.write('escape(')
1287
self.write('to_string(')
1288
if self.environment.finalize is not None:
1289
self.write('environment.finalize(')
1291
self.visit(item, frame)
1292
self.write(')' * close)
1293
if frame.buffer is not None:
1295
if frame.buffer is not None:
1296
# close the open parentheses
1298
self.writeline(len(body) == 1 and ')' or '))')
1300
# otherwise we create a format string as this is faster in that case
1305
if isinstance(item, list):
1306
format.append(concat(item).replace('%', '%%'))
1309
arguments.append(item)
1310
self.writeline('yield ')
1311
self.write(repr(concat(format)) + ' % (')
1314
for argument in arguments:
1315
self.newline(argument)
1317
if frame.eval_ctx.volatile:
1318
self.write('(context.eval_ctx.autoescape and'
1319
' escape or to_string)(')
1321
elif frame.eval_ctx.autoescape:
1322
self.write('escape(')
1324
if self.environment.finalize is not None:
1325
self.write('environment.finalize(')
1327
self.visit(argument, frame)
1328
self.write(')' * close + ', ')
1335
def visit_Assign(self, node, frame):
1337
# toplevel assignments however go into the local namespace and
1338
# the current template's context. We create a copy of the frame
1339
# here and add a set so that the Name visitor can add the assigned
1342
assignment_frame = frame.copy()
1343
assignment_frame.toplevel_assignments = set()
1345
assignment_frame = frame
1346
self.visit(node.target, assignment_frame)
1348
self.visit(node.node, frame)
1350
# make sure toplevel assignments are added to the context.
1352
public_names = [x for x in assignment_frame.toplevel_assignments
1353
if not x.startswith('_')]
1354
if len(assignment_frame.toplevel_assignments) == 1:
1355
name = next(iter(assignment_frame.toplevel_assignments))
1356
self.writeline('context.vars[%r] = l_%s' % (name, name))
1358
self.writeline('context.vars.update({')
1359
for idx, name in enumerate(assignment_frame.toplevel_assignments):
1362
self.write('%r: l_%s' % (name, name))
1365
if len(public_names) == 1:
1366
self.writeline('context.exported_vars.add(%r)' %
1369
self.writeline('context.exported_vars.update((%s))' %
1370
', '.join(imap(repr, public_names)))
1372
# -- Expression Visitors
1374
def visit_Name(self, node, frame):
1375
if node.ctx == 'store' and frame.toplevel:
1376
frame.toplevel_assignments.add(node.name)
1377
self.write('l_' + node.name)
1378
frame.assigned_names.add(node.name)
1380
def visit_Const(self, node, frame):
1382
if isinstance(val, float):
1383
self.write(str(val))
1385
self.write(repr(val))
1387
def visit_TemplateData(self, node, frame):
1389
self.write(repr(node.as_const(frame.eval_ctx)))
1390
except nodes.Impossible:
1391
self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)'
1394
def visit_Tuple(self, node, frame):
1397
for idx, item in enumerate(node.items):
1400
self.visit(item, frame)
1401
self.write(idx == 0 and ',)' or ')')
1403
def visit_List(self, node, frame):
1405
for idx, item in enumerate(node.items):
1408
self.visit(item, frame)
1411
def visit_Dict(self, node, frame):
1413
for idx, item in enumerate(node.items):
1416
self.visit(item.key, frame)
1418
self.visit(item.value, frame)
1421
def binop(operator, interceptable=True):
1422
def visitor(self, node, frame):
1423
if self.environment.sandboxed and \
1424
operator in self.environment.intercepted_binops:
1425
self.write('environment.call_binop(context, %r, ' % operator)
1426
self.visit(node.left, frame)
1428
self.visit(node.right, frame)
1431
self.visit(node.left, frame)
1432
self.write(' %s ' % operator)
1433
self.visit(node.right, frame)
1437
def uaop(operator, interceptable=True):
1438
def visitor(self, node, frame):
1439
if self.environment.sandboxed and \
1440
operator in self.environment.intercepted_unops:
1441
self.write('environment.call_unop(context, %r, ' % operator)
1442
self.visit(node.node, frame)
1444
self.write('(' + operator)
1445
self.visit(node.node, frame)
1449
visit_Add = binop('+')
1450
visit_Sub = binop('-')
1451
visit_Mul = binop('*')
1452
visit_Div = binop('/')
1453
visit_FloorDiv = binop('//')
1454
visit_Pow = binop('**')
1455
visit_Mod = binop('%')
1456
visit_And = binop('and', interceptable=False)
1457
visit_Or = binop('or', interceptable=False)
1458
visit_Pos = uaop('+')
1459
visit_Neg = uaop('-')
1460
visit_Not = uaop('not ', interceptable=False)
1463
def visit_Concat(self, node, frame):
1464
if frame.eval_ctx.volatile:
1465
func_name = '(context.eval_ctx.volatile and' \
1466
' markup_join or unicode_join)'
1467
elif frame.eval_ctx.autoescape:
1468
func_name = 'markup_join'
1470
func_name = 'unicode_join'
1471
self.write('%s((' % func_name)
1472
for arg in node.nodes:
1473
self.visit(arg, frame)
1477
def visit_Compare(self, node, frame):
1478
self.visit(node.expr, frame)
1480
self.visit(op, frame)
1482
def visit_Operand(self, node, frame):
1483
self.write(' %s ' % operators[node.op])
1484
self.visit(node.expr, frame)
1486
def visit_Getattr(self, node, frame):
1487
self.write('environment.getattr(')
1488
self.visit(node.node, frame)
1489
self.write(', %r)' % node.attr)
1491
def visit_Getitem(self, node, frame):
1492
# slices bypass the environment getitem method.
1493
if isinstance(node.arg, nodes.Slice):
1494
self.visit(node.node, frame)
1496
self.visit(node.arg, frame)
1499
self.write('environment.getitem(')
1500
self.visit(node.node, frame)
1502
self.visit(node.arg, frame)
1505
def visit_Slice(self, node, frame):
1506
if node.start is not None:
1507
self.visit(node.start, frame)
1509
if node.stop is not None:
1510
self.visit(node.stop, frame)
1511
if node.step is not None:
1513
self.visit(node.step, frame)
1515
def visit_Filter(self, node, frame):
1516
self.write(self.filters[node.name] + '(')
1517
func = self.environment.filters.get(node.name)
1519
self.fail('no filter named %r' % node.name, node.lineno)
1520
if getattr(func, 'contextfilter', False):
1521
self.write('context, ')
1522
elif getattr(func, 'evalcontextfilter', False):
1523
self.write('context.eval_ctx, ')
1524
elif getattr(func, 'environmentfilter', False):
1525
self.write('environment, ')
1527
# if the filter node is None we are inside a filter block
1528
# and want to write to the current buffer
1529
if node.node is not None:
1530
self.visit(node.node, frame)
1531
elif frame.eval_ctx.volatile:
1532
self.write('(context.eval_ctx.autoescape and'
1533
' Markup(concat(%s)) or concat(%s))' %
1534
(frame.buffer, frame.buffer))
1535
elif frame.eval_ctx.autoescape:
1536
self.write('Markup(concat(%s))' % frame.buffer)
1538
self.write('concat(%s)' % frame.buffer)
1539
self.signature(node, frame)
1542
def visit_Test(self, node, frame):
1543
self.write(self.tests[node.name] + '(')
1544
if node.name not in self.environment.tests:
1545
self.fail('no test named %r' % node.name, node.lineno)
1546
self.visit(node.node, frame)
1547
self.signature(node, frame)
1550
def visit_CondExpr(self, node, frame):
1552
if node.expr2 is not None:
1553
return self.visit(node.expr2, frame)
1554
self.write('environment.undefined(%r)' % ('the inline if-'
1555
'expression on %s evaluated to false and '
1556
'no else section was defined.' % self.position(node)))
1559
self.visit(node.expr1, frame)
1561
self.visit(node.test, frame)
1562
self.write(' else ')
1566
def visit_Call(self, node, frame, forward_caller=False):
1567
if self.environment.sandboxed:
1568
self.write('environment.call(context, ')
1570
self.write('context.call(')
1571
self.visit(node.node, frame)
1572
extra_kwargs = forward_caller and {'caller': 'caller'} or None
1573
self.signature(node, frame, extra_kwargs)
1576
def visit_Keyword(self, node, frame):
1577
self.write(node.key + '=')
1578
self.visit(node.value, frame)
1580
# -- Unused nodes for extensions
1582
def visit_MarkSafe(self, node, frame):
1583
self.write('Markup(')
1584
self.visit(node.expr, frame)
1587
def visit_MarkSafeIfAutoescape(self, node, frame):
1588
self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1589
self.visit(node.expr, frame)
1592
def visit_EnvironmentAttribute(self, node, frame):
1593
self.write('environment.' + node.name)
1595
def visit_ExtensionAttribute(self, node, frame):
1596
self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
1598
def visit_ImportedName(self, node, frame):
1599
self.write(self.import_aliases[node.importname])
1601
def visit_InternalName(self, node, frame):
1602
self.write(node.name)
1604
def visit_ContextReference(self, node, frame):
1605
self.write('context')
1607
def visit_Continue(self, node, frame):
1608
self.writeline('continue', node)
1610
def visit_Break(self, node, frame):
1611
self.writeline('break', node)
1613
def visit_Scope(self, node, frame):
1614
scope_frame = frame.inner()
1615
scope_frame.inspect(node.iter_child_nodes())
1616
aliases = self.push_scope(scope_frame)
1617
self.pull_locals(scope_frame)
1618
self.blockvisit(node.body, scope_frame)
1619
self.pop_scope(aliases, scope_frame)
1621
def visit_EvalContextModifier(self, node, frame):
1622
for keyword in node.options:
1623
self.writeline('context.eval_ctx.%s = ' % keyword.key)
1624
self.visit(keyword.value, frame)
1626
val = keyword.value.as_const(frame.eval_ctx)
1627
except nodes.Impossible:
1628
frame.eval_ctx.volatile = True
1630
setattr(frame.eval_ctx, keyword.key, val)
1632
def visit_ScopedEvalContextModifier(self, node, frame):
1633
old_ctx_name = self.temporary_identifier()
1634
safed_ctx = frame.eval_ctx.save()
1635
self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1636
self.visit_EvalContextModifier(node, frame)
1637
for child in node.body:
1638
self.visit(child, frame)
1639
frame.eval_ctx.revert(safed_ctx)
1640
self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)