~brad-marshall/charms/trusty/apache2-wsgi/fix-haproxy-relations

« back to all changes in this revision

Viewing changes to hooks/lib/jinja2/compiler.py

  • Committer: Robin Winslow
  • Date: 2014-05-27 14:00:44 UTC
  • Revision ID: robin.winslow@canonical.com-20140527140044-8rpmb3wx4djzwa83
Add all files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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, next, 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 = CodeGenerator(environment, name, filename, stream, defer_init)
 
61
    generator.visit(node)
 
62
    if stream is None:
 
63
        return generator.stream.getvalue()
 
64
 
 
65
 
 
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:
 
69
        return True
 
70
    if isinstance(value, (bool, int, float, complex, range_type,
 
71
            Markup) + string_types):
 
72
        return True
 
73
    if isinstance(value, (tuple, list, set, frozenset)):
 
74
        for item in value:
 
75
            if not has_safe_repr(item):
 
76
                return False
 
77
        return True
 
78
    elif isinstance(value, dict):
 
79
        for key, value in iteritems(value):
 
80
            if not has_safe_repr(key):
 
81
                return False
 
82
            if not has_safe_repr(value):
 
83
                return False
 
84
        return True
 
85
    return False
 
86
 
 
87
 
 
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.
 
91
    """
 
92
    visitor = UndeclaredNameVisitor(names)
 
93
    try:
 
94
        for node in nodes:
 
95
            visitor.visit(node)
 
96
    except VisitorExit:
 
97
        pass
 
98
    return visitor.undeclared
 
99
 
 
100
 
 
101
class Identifiers(object):
 
102
    """Tracks the status of identifiers in frames."""
 
103
 
 
104
    def __init__(self):
 
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()
 
108
 
 
109
        # undeclared variables from outer scopes
 
110
        self.outer_undeclared = set()
 
111
 
 
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()
 
116
 
 
117
        # names that are declared locally
 
118
        self.declared_locally = set()
 
119
 
 
120
        # names that are declared by parameters
 
121
        self.declared_parameter = set()
 
122
 
 
123
    def add_special(self, name):
 
124
        """Register a special name like `loop`."""
 
125
        self.undeclared.discard(name)
 
126
        self.declared.add(name)
 
127
 
 
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:
 
131
            return True
 
132
        return name in self.declared
 
133
 
 
134
    def copy(self):
 
135
        return deepcopy(self)
 
136
 
 
137
 
 
138
class Frame(object):
 
139
    """Holds compile time information for us."""
 
140
 
 
141
    def __init__(self, eval_ctx, parent=None):
 
142
        self.eval_ctx = eval_ctx
 
143
        self.identifiers = Identifiers()
 
144
 
 
145
        # a toplevel frame is the root + soft frames such as if conditions.
 
146
        self.toplevel = False
 
147
 
 
148
        # the root frame is basically just the outermost frame, so no if
 
149
        # conditions.  This information is used to optimize inheritance
 
150
        # situations.
 
151
        self.rootlevel = False
 
152
 
 
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
 
156
 
 
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
 
160
        # buffer.
 
161
        self.buffer = None
 
162
 
 
163
        # the name of the block we're in, otherwise None.
 
164
        self.block = parent and parent.block or None
 
165
 
 
166
        # a set of actually assigned names
 
167
        self.assigned_names = set()
 
168
 
 
169
        # the parent of this frame
 
170
        self.parent = parent
 
171
 
 
172
        if parent is not None:
 
173
            self.identifiers.declared.update(
 
174
                parent.identifiers.declared |
 
175
                parent.identifiers.declared_parameter |
 
176
                parent.assigned_names
 
177
            )
 
178
            self.identifiers.outer_undeclared.update(
 
179
                parent.identifiers.undeclared -
 
180
                self.identifiers.declared
 
181
            )
 
182
            self.buffer = parent.buffer
 
183
 
 
184
    def copy(self):
 
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__)
 
190
        return rv
 
191
 
 
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
 
195
        differently.
 
196
        """
 
197
        visitor = FrameIdentifierVisitor(self.identifiers)
 
198
        for node in nodes:
 
199
            visitor.visit(node)
 
200
 
 
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.
 
204
        """
 
205
        i = self.identifiers
 
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))
 
209
 
 
210
    def inner(self):
 
211
        """Return an inner frame."""
 
212
        return Frame(self.eval_ctx, self)
 
213
 
 
214
    def soft(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.
 
218
        """
 
219
        rv = self.copy()
 
220
        rv.rootlevel = False
 
221
        return rv
 
222
 
 
223
    __copy__ = copy
 
224
 
 
225
 
 
226
class VisitorExit(RuntimeError):
 
227
    """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
 
228
 
 
229
 
 
230
class DependencyFinderVisitor(NodeVisitor):
 
231
    """A visitor that collects filter and test calls."""
 
232
 
 
233
    def __init__(self):
 
234
        self.filters = set()
 
235
        self.tests = set()
 
236
 
 
237
    def visit_Filter(self, node):
 
238
        self.generic_visit(node)
 
239
        self.filters.add(node.name)
 
240
 
 
241
    def visit_Test(self, node):
 
242
        self.generic_visit(node)
 
243
        self.tests.add(node.name)
 
244
 
 
245
    def visit_Block(self, node):
 
246
        """Stop visiting at blocks."""
 
247
 
 
248
 
 
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.
 
253
    """
 
254
 
 
255
    def __init__(self, names):
 
256
        self.names = set(names)
 
257
        self.undeclared = set()
 
258
 
 
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:
 
263
                raise VisitorExit()
 
264
        else:
 
265
            self.names.discard(node.name)
 
266
 
 
267
    def visit_Block(self, node):
 
268
        """Stop visiting a blocks."""
 
269
 
 
270
 
 
271
class FrameIdentifierVisitor(NodeVisitor):
 
272
    """A visitor for `Frame.inspect`."""
 
273
 
 
274
    def __init__(self, identifiers):
 
275
        self.identifiers = identifiers
 
276
 
 
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)
 
286
 
 
287
    def visit_If(self, node):
 
288
        self.visit(node.test)
 
289
        real_identifiers = self.identifiers
 
290
 
 
291
        old_names = real_identifiers.declared_locally | \
 
292
                    real_identifiers.declared_parameter
 
293
 
 
294
        def inner_visit(nodes):
 
295
            if not nodes:
 
296
                return set()
 
297
            self.identifiers = real_identifiers.copy()
 
298
            for subnode in nodes:
 
299
                self.visit(subnode)
 
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
 
305
            return rv
 
306
 
 
307
        body = inner_visit(node.body)
 
308
        else_ = inner_visit(node.else_ or ())
 
309
 
 
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)
 
314
 
 
315
        # remember those that are declared.
 
316
        real_identifiers.declared_locally.update(body | else_)
 
317
 
 
318
    def visit_Macro(self, node):
 
319
        self.identifiers.declared_locally.add(node.name)
 
320
 
 
321
    def visit_Import(self, node):
 
322
        self.generic_visit(node)
 
323
        self.identifiers.declared_locally.add(node.target)
 
324
 
 
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])
 
330
            else:
 
331
                self.identifiers.declared_locally.add(name)
 
332
 
 
333
    def visit_Assign(self, node):
 
334
        """Visit assignments in the correct order."""
 
335
        self.visit(node.node)
 
336
        self.visit(node.target)
 
337
 
 
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.
 
341
        """
 
342
        self.visit(node.iter)
 
343
 
 
344
    def visit_CallBlock(self, node):
 
345
        self.visit(node.call)
 
346
 
 
347
    def visit_FilterBlock(self, node):
 
348
        self.visit(node.filter)
 
349
 
 
350
    def visit_Scope(self, node):
 
351
        """Stop visiting at scopes."""
 
352
 
 
353
    def visit_Block(self, node):
 
354
        """Stop visiting at blocks."""
 
355
 
 
356
 
 
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.
 
361
    """
 
362
 
 
363
 
 
364
class CodeGenerator(NodeVisitor):
 
365
 
 
366
    def __init__(self, environment, name, filename, stream=None,
 
367
                 defer_init=False):
 
368
        if stream is None:
 
369
            stream = NativeStringIO()
 
370
        self.environment = environment
 
371
        self.name = name
 
372
        self.filename = filename
 
373
        self.stream = stream
 
374
        self.created_block_context = False
 
375
        self.defer_init = defer_init
 
376
 
 
377
        # aliases for imports
 
378
        self.import_aliases = {}
 
379
 
 
380
        # a registry for all blocks.  Because blocks are moved out
 
381
        # into the global python scope they are registered here
 
382
        self.blocks = {}
 
383
 
 
384
        # the number of extends statements so far
 
385
        self.extends_so_far = 0
 
386
 
 
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
 
391
 
 
392
        # the current line number
 
393
        self.code_lineno = 1
 
394
 
 
395
        # registry of all filters and tests (global, not block local)
 
396
        self.tests = {}
 
397
        self.filters = {}
 
398
 
 
399
        # the debug information
 
400
        self.debug_info = []
 
401
        self._write_debug_info = None
 
402
 
 
403
        # the number of new lines before the next write()
 
404
        self._new_lines = 0
 
405
 
 
406
        # the line number of the last written statement
 
407
        self._last_line = 0
 
408
 
 
409
        # true if nothing was written so far.
 
410
        self._first_write = True
 
411
 
 
412
        # used by the `temporary_identifier` method to get new
 
413
        # unique, temporary identifier
 
414
        self._last_identifier = 0
 
415
 
 
416
        # the current indentation
 
417
        self._indentation = 0
 
418
 
 
419
    # -- Various compilation helpers
 
420
 
 
421
    def fail(self, msg, lineno):
 
422
        """Fail with a :exc:`TemplateAssertionError`."""
 
423
        raise TemplateAssertionError(msg, lineno, self.name, self.filename)
 
424
 
 
425
    def temporary_identifier(self):
 
426
        """Get a new unique identifier."""
 
427
        self._last_identifier += 1
 
428
        return 't_%d' % self._last_identifier
 
429
 
 
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)
 
434
 
 
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:')
 
439
            self.indent()
 
440
            self.writeline('return Markup(concat(%s))' % frame.buffer)
 
441
            self.outdent()
 
442
            self.writeline('else:')
 
443
            self.indent()
 
444
            self.writeline('return concat(%s)' % frame.buffer)
 
445
            self.outdent()
 
446
        elif frame.eval_ctx.autoescape:
 
447
            self.writeline('return Markup(concat(%s))' % frame.buffer)
 
448
        else:
 
449
            self.writeline('return concat(%s)' % frame.buffer)
 
450
 
 
451
    def indent(self):
 
452
        """Indent by one."""
 
453
        self._indentation += 1
 
454
 
 
455
    def outdent(self, step=1):
 
456
        """Outdent by step."""
 
457
        self._indentation -= step
 
458
 
 
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)
 
463
        else:
 
464
            self.writeline('%s.append(' % frame.buffer, node)
 
465
 
 
466
    def end_write(self, frame):
 
467
        """End the writing process started by `start_write`."""
 
468
        if frame.buffer is not None:
 
469
            self.write(')')
 
470
 
 
471
    def simple_write(self, s, frame, node=None):
 
472
        """Simple shortcut for start_write + write + end_write."""
 
473
        self.start_write(frame, node)
 
474
        self.write(s)
 
475
        self.end_write(frame)
 
476
 
 
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.
 
481
        """
 
482
        if frame.buffer is None:
 
483
            self.writeline('if 0: yield None')
 
484
        else:
 
485
            self.writeline('pass')
 
486
        try:
 
487
            for node in nodes:
 
488
                self.visit(node, frame)
 
489
        except CompilerExit:
 
490
            pass
 
491
 
 
492
    def write(self, x):
 
493
        """Write a string into the output stream."""
 
494
        if self._new_lines:
 
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,
 
500
                                            self.code_lineno))
 
501
                    self._write_debug_info = None
 
502
            self._first_write = False
 
503
            self.stream.write('    ' * self._indentation)
 
504
            self._new_lines = 0
 
505
        self.stream.write(x)
 
506
 
 
507
    def writeline(self, x, node=None, extra=0):
 
508
        """Combination of newline and write."""
 
509
        self.newline(node, extra)
 
510
        self.write(x)
 
511
 
 
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
 
518
 
 
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
 
524
        as python dict.
 
525
        """
 
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
 
532
                break
 
533
 
 
534
        for arg in node.args:
 
535
            self.write(', ')
 
536
            self.visit(arg, frame)
 
537
 
 
538
        if not kwarg_workaround:
 
539
            for kwarg in node.kwargs:
 
540
                self.write(', ')
 
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))
 
545
        if node.dyn_args:
 
546
            self.write(', *')
 
547
            self.visit(node.dyn_args, frame)
 
548
 
 
549
        if kwarg_workaround:
 
550
            if node.dyn_kwargs is not None:
 
551
                self.write(', **dict({')
 
552
            else:
 
553
                self.write(', **{')
 
554
            for kwarg in node.kwargs:
 
555
                self.write('%r: ' % kwarg.key)
 
556
                self.visit(kwarg.value, frame)
 
557
                self.write(', ')
 
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:
 
562
                self.write('}, **')
 
563
                self.visit(node.dyn_kwargs, frame)
 
564
                self.write(')')
 
565
            else:
 
566
                self.write('}')
 
567
 
 
568
        elif node.dyn_kwargs is not None:
 
569
            self.write(', **')
 
570
            self.visit(node.dyn_kwargs, frame)
 
571
 
 
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))
 
576
 
 
577
    def pull_dependencies(self, nodes):
 
578
        """Pull all the dependencies."""
 
579
        visitor = DependencyFinderVisitor()
 
580
        for node in nodes:
 
581
            visitor.visit(node)
 
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))
 
589
 
 
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)
 
600
            ))
 
601
 
 
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.
 
606
 
 
607
        This also predefines locally declared variables from the loop
 
608
        body because under some circumstances it may be the case that
 
609
 
 
610
        `extra_vars` is passed to `Frame.find_shadowed`.
 
611
        """
 
612
        aliases = {}
 
613
        for name in frame.find_shadowed(extra_vars):
 
614
            aliases[name] = ident = self.temporary_identifier()
 
615
            self.writeline('%s = l_%s' % (ident, name))
 
616
        to_declare = set()
 
617
        for name in frame.identifiers.declared_locally:
 
618
            if name not in aliases:
 
619
                to_declare.add('l_' + name)
 
620
        if to_declare:
 
621
            self.writeline(' = '.join(to_declare) + ' = missing')
 
622
        return aliases
 
623
 
 
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))
 
628
        to_delete = set()
 
629
        for name in frame.identifiers.declared_locally:
 
630
            if name not in aliases:
 
631
                to_delete.add('l_' + name)
 
632
        if to_delete:
 
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')
 
637
 
 
638
    def function_scoping(self, node, frame, children=None,
 
639
                         find_special=True):
 
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.
 
648
 
 
649
        This will return the modified frame.
 
650
        """
 
651
        # we have to iterate twice over it, make sure that works
 
652
        if children is None:
 
653
            children = node.iter_child_nodes()
 
654
        children = list(children)
 
655
        func_frame = frame.inner()
 
656
        func_frame.inspect(children)
 
657
 
 
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)
 
669
        )
 
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)
 
674
 
 
675
        # remove variables from a closure from the frame's undeclared
 
676
        # identifiers.
 
677
        func_frame.identifiers.undeclared -= (
 
678
            func_frame.identifiers.undeclared &
 
679
            func_frame.identifiers.declared
 
680
        )
 
681
 
 
682
        # no special variables for this scope, abort early
 
683
        if not find_special:
 
684
            return func_frame
 
685
 
 
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]
 
690
 
 
691
        undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
 
692
 
 
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')
 
705
        return func_frame
 
706
 
 
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
 
719
        # and assigned.
 
720
        if 'loop' in frame.identifiers.declared:
 
721
            args = args + ['l_loop=l_loop']
 
722
        self.writeline('def macro(%s):' % ', '.join(args), node)
 
723
        self.indent()
 
724
        self.buffer(frame)
 
725
        self.pull_locals(frame)
 
726
        self.blockvisit(node.body, frame)
 
727
        self.return_buffer_contents(frame)
 
728
        self.outdent()
 
729
        return frame
 
730
 
 
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:
 
736
            arg_tuple += ','
 
737
        self.write('Macro(environment, macro, %r, (%s), (' %
 
738
                   (name, arg_tuple))
 
739
        for arg in node.defaults:
 
740
            self.visit(arg, frame)
 
741
            self.write(', ')
 
742
        self.write('), %r, %r, %r)' % (
 
743
            bool(frame.accesses_kwargs),
 
744
            bool(frame.accesses_varargs),
 
745
            bool(frame.accesses_caller)
 
746
        ))
 
747
 
 
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)
 
753
        return rv
 
754
 
 
755
    # -- Statement Visitors
 
756
 
 
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)
 
760
 
 
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')
 
766
 
 
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 ''
 
770
 
 
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
 
774
 
 
775
        # find all blocks
 
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
 
780
 
 
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()
 
786
                if '.' in imp:
 
787
                    module, obj = imp.rsplit('.', 1)
 
788
                    self.writeline('from %s import %s as %s' %
 
789
                                   (module, obj, alias))
 
790
                else:
 
791
                    self.writeline('import %s as %s' % (imp, alias))
 
792
 
 
793
        # add the load name
 
794
        self.writeline('name = %r' % self.name)
 
795
 
 
796
        # generate the root render function.
 
797
        self.writeline('def root(context%s):' % envenv, extra=1)
 
798
 
 
799
        # process the root
 
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
 
804
        self.indent()
 
805
        if have_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)
 
813
        self.outdent()
 
814
 
 
815
        # make sure that the parent root is called.
 
816
        if have_extends:
 
817
            if not self.has_known_extends:
 
818
                self.indent()
 
819
                self.writeline('if parent_template is not None:')
 
820
            self.indent()
 
821
            self.writeline('for event in parent_template.'
 
822
                           'root_render_func(context):')
 
823
            self.indent()
 
824
            self.writeline('yield event')
 
825
            self.outdent(2 + (not self.has_known_extends))
 
826
 
 
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),
 
833
                           block, 1)
 
834
            self.indent()
 
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)
 
846
            self.outdent()
 
847
 
 
848
        self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
 
849
                                                   for x in self.blocks),
 
850
                       extra=1)
 
851
 
 
852
        # add a function that returns the debug info
 
853
        self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
 
854
                                                    in self.debug_info))
 
855
 
 
856
    def visit_Block(self, node, frame):
 
857
        """Call a block and register it for the template."""
 
858
        level = 1
 
859
        if frame.toplevel:
 
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:
 
863
                return
 
864
            if self.extends_so_far > 0:
 
865
                self.writeline('if parent_template is None:')
 
866
                self.indent()
 
867
                level += 1
 
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)
 
871
        self.indent()
 
872
        self.simple_write('event', frame)
 
873
        self.outdent(level)
 
874
 
 
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',
 
879
                      node.lineno)
 
880
 
 
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:
 
885
 
 
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:')
 
892
                self.indent()
 
893
            self.writeline('raise TemplateRuntimeError(%r)' %
 
894
                           'extended multiple times')
 
895
 
 
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:
 
899
                raise CompilerExit()
 
900
            else:
 
901
                self.outdent()
 
902
 
 
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)
 
908
        self.indent()
 
909
        self.writeline('context.blocks.setdefault(name, []).'
 
910
                       'append(parent_block)')
 
911
        self.outdent()
 
912
 
 
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
 
916
        if frame.rootlevel:
 
917
            self.has_known_extends = True
 
918
 
 
919
        # and now we have one more
 
920
        self.extends_so_far += 1
 
921
 
 
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:')
 
928
            self.indent()
 
929
 
 
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'
 
938
 
 
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:
 
943
            self.outdent()
 
944
            self.writeline('except TemplateNotFound:')
 
945
            self.indent()
 
946
            self.writeline('pass')
 
947
            self.outdent()
 
948
            self.writeline('else:')
 
949
            self.indent()
 
950
 
 
951
        if node.with_context:
 
952
            self.writeline('for event in template.root_render_func('
 
953
                           'template.new_context(context.parent, True, '
 
954
                           'locals())):')
 
955
        else:
 
956
            self.writeline('for event in template.module._body_stream:')
 
957
 
 
958
        self.indent()
 
959
        self.simple_write('event', frame)
 
960
        self.outdent()
 
961
 
 
962
        if node.ignore_missing:
 
963
            self.outdent()
 
964
 
 
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)
 
970
        if frame.toplevel:
 
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())')
 
977
        else:
 
978
            self.write('module')
 
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)
 
982
 
 
983
    def visit_FromImport(self, node, frame):
 
984
        """Visit named imports."""
 
985
        self.newline(node)
 
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)')
 
991
        else:
 
992
            self.write('module')
 
993
 
 
994
        var_names = []
 
995
        discarded_names = []
 
996
        for name in node.names:
 
997
            if isinstance(name, tuple):
 
998
                name, alias = name
 
999
            else:
 
1000
                alias = name
 
1001
            self.writeline('l_%s = getattr(included_template, '
 
1002
                           '%r, missing)' % (alias, name))
 
1003
            self.writeline('if l_%s is missing:' % alias)
 
1004
            self.indent()
 
1005
            self.writeline('l_%s = environment.undefined(%r %% '
 
1006
                           'included_template.__name__, '
 
1007
                           'name=%r)' %
 
1008
                           (alias, 'the template %%r (imported on %s) does '
 
1009
                           'not export the requested name %s' % (
 
1010
                                self.position(node),
 
1011
                                repr(name)
 
1012
                           ), name))
 
1013
            self.outdent()
 
1014
            if frame.toplevel:
 
1015
                var_names.append(alias)
 
1016
                if not alias.startswith('_'):
 
1017
                    discarded_names.append(alias)
 
1018
            frame.assigned_names.add(alias)
 
1019
 
 
1020
        if var_names:
 
1021
            if len(var_names) == 1:
 
1022
                name = var_names[0]
 
1023
                self.writeline('context.vars[%r] = l_%s' % (name, name))
 
1024
            else:
 
1025
                self.writeline('context.vars.update({%s})' % ', '.join(
 
1026
                    '%r: l_%s' % (name, name) for name in var_names
 
1027
                ))
 
1028
        if discarded_names:
 
1029
            if len(discarded_names) == 1:
 
1030
                self.writeline('context.exported_vars.discard(%r)' %
 
1031
                               discarded_names[0])
 
1032
            else:
 
1033
                self.writeline('context.exported_vars.difference_'
 
1034
                               'update((%s))' % ', '.join(imap(repr, discarded_names)))
 
1035
 
 
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',))
 
1040
        if node.recursive:
 
1041
            loop_frame = self.function_scoping(node, frame, children,
 
1042
                                               find_special=False)
 
1043
        else:
 
1044
            loop_frame = frame.inner()
 
1045
            loop_frame.inspect(children)
 
1046
 
 
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',))
 
1053
 
 
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',))
 
1059
 
 
1060
        # otherwise we set up a buffer and add a function def
 
1061
        else:
 
1062
            self.writeline('def loop(reciter, loop_render_func, depth=0):', node)
 
1063
            self.indent()
 
1064
            self.buffer(loop_frame)
 
1065
            aliases = {}
 
1066
 
 
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
 
1069
        if extended_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)
 
1076
 
 
1077
        self.pull_locals(loop_frame)
 
1078
        if node.else_:
 
1079
            iteration_indicator = self.temporary_identifier()
 
1080
            self.writeline('%s = 1' % iteration_indicator)
 
1081
 
 
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
 
1084
        # exists.
 
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)))
 
1093
 
 
1094
        self.writeline('for ', node)
 
1095
        self.visit(node.target, loop_frame)
 
1096
        self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
 
1097
 
 
1098
        # if we have an extened loop and a node test, we filter in the
 
1099
        # "outer frame".
 
1100
        if extended_loop and node.test is not None:
 
1101
            self.write('(')
 
1102
            self.visit(node.target, loop_frame)
 
1103
            self.write(' for ')
 
1104
            self.visit(node.target, loop_frame)
 
1105
            self.write(' in ')
 
1106
            if node.recursive:
 
1107
                self.write('reciter')
 
1108
            else:
 
1109
                self.visit(node.iter, loop_frame)
 
1110
            self.write(' if (')
 
1111
            test_frame = loop_frame.copy()
 
1112
            self.visit(node.test, test_frame)
 
1113
            self.write('))')
 
1114
 
 
1115
        elif node.recursive:
 
1116
            self.write('reciter')
 
1117
        else:
 
1118
            self.visit(node.iter, loop_frame)
 
1119
 
 
1120
        if node.recursive:
 
1121
            self.write(', loop_render_func, depth):')
 
1122
        else:
 
1123
            self.write(extended_loop and '):' or ':')
 
1124
 
 
1125
        # tests in not extended loops become a continue
 
1126
        if not extended_loop and node.test is not None:
 
1127
            self.indent()
 
1128
            self.writeline('if not ')
 
1129
            self.visit(node.test, loop_frame)
 
1130
            self.write(':')
 
1131
            self.indent()
 
1132
            self.writeline('continue')
 
1133
            self.outdent(2)
 
1134
 
 
1135
        self.indent()
 
1136
        self.blockvisit(node.body, loop_frame)
 
1137
        if node.else_:
 
1138
            self.writeline('%s = 0' % iteration_indicator)
 
1139
        self.outdent()
 
1140
 
 
1141
        if node.else_:
 
1142
            self.writeline('if %s:' % iteration_indicator)
 
1143
            self.indent()
 
1144
            self.blockvisit(node.else_, loop_frame)
 
1145
            self.outdent()
 
1146
 
 
1147
        # reset the aliases if there are any.
 
1148
        if not node.recursive:
 
1149
            self.pop_scope(aliases, loop_frame)
 
1150
 
 
1151
        # if the node was recursive we have to return the buffer contents
 
1152
        # and start the iteration code
 
1153
        if node.recursive:
 
1154
            self.return_buffer_contents(loop_frame)
 
1155
            self.outdent()
 
1156
            self.start_write(frame, node)
 
1157
            self.write('loop(')
 
1158
            self.visit(node.iter, frame)
 
1159
            self.write(', loop)')
 
1160
            self.end_write(frame)
 
1161
 
 
1162
    def visit_If(self, node, frame):
 
1163
        if_frame = frame.soft()
 
1164
        self.writeline('if ', node)
 
1165
        self.visit(node.test, if_frame)
 
1166
        self.write(':')
 
1167
        self.indent()
 
1168
        self.blockvisit(node.body, if_frame)
 
1169
        self.outdent()
 
1170
        if node.else_:
 
1171
            self.writeline('else:')
 
1172
            self.indent()
 
1173
            self.blockvisit(node.else_, if_frame)
 
1174
            self.outdent()
 
1175
 
 
1176
    def visit_Macro(self, node, frame):
 
1177
        macro_frame = self.macro_body(node, frame)
 
1178
        self.newline()
 
1179
        if frame.toplevel:
 
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)
 
1186
 
 
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)
 
1195
 
 
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)
 
1207
 
 
1208
    def visit_ExprStmt(self, node, frame):
 
1209
        self.newline(node)
 
1210
        self.visit(node.node, frame)
 
1211
 
 
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:
 
1216
            return
 
1217
 
 
1218
        if self.environment.finalize:
 
1219
            finalize = lambda x: text_type(self.environment.finalize(x))
 
1220
        else:
 
1221
            finalize = text_type
 
1222
 
 
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:')
 
1227
            self.indent()
 
1228
            outdent_later = True
 
1229
 
 
1230
        # try to evaluate as many chunks as possible into a static
 
1231
        # string at compile time.
 
1232
        body = []
 
1233
        for child in node.nodes:
 
1234
            try:
 
1235
                const = child.as_const(frame.eval_ctx)
 
1236
            except nodes.Impossible:
 
1237
                body.append(child)
 
1238
                continue
 
1239
            # the frame can't be volatile here, becaus otherwise the
 
1240
            # as_const() function would raise an Impossible exception
 
1241
            # at that point.
 
1242
            try:
 
1243
                if frame.eval_ctx.autoescape:
 
1244
                    if hasattr(const, '__html__'):
 
1245
                        const = const.__html__()
 
1246
                    else:
 
1247
                        const = escape(const)
 
1248
                const = finalize(const)
 
1249
            except Exception:
 
1250
                # if something goes wrong here we evaluate the node
 
1251
                # at runtime for easier debugging
 
1252
                body.append(child)
 
1253
                continue
 
1254
            if body and isinstance(body[-1], list):
 
1255
                body[-1].append(const)
 
1256
            else:
 
1257
                body.append([const])
 
1258
 
 
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
 
1263
                if len(body) == 1:
 
1264
                    self.writeline('%s.append(' % frame.buffer)
 
1265
                else:
 
1266
                    self.writeline('%s.extend((' % frame.buffer)
 
1267
                self.indent()
 
1268
            for item in body:
 
1269
                if isinstance(item, list):
 
1270
                    val = repr(concat(item))
 
1271
                    if frame.buffer is None:
 
1272
                        self.writeline('yield ' + val)
 
1273
                    else:
 
1274
                        self.writeline(val + ', ')
 
1275
                else:
 
1276
                    if frame.buffer is None:
 
1277
                        self.writeline('yield ', item)
 
1278
                    else:
 
1279
                        self.newline(item)
 
1280
                    close = 1
 
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(')
 
1286
                    else:
 
1287
                        self.write('to_string(')
 
1288
                    if self.environment.finalize is not None:
 
1289
                        self.write('environment.finalize(')
 
1290
                        close += 1
 
1291
                    self.visit(item, frame)
 
1292
                    self.write(')' * close)
 
1293
                    if frame.buffer is not None:
 
1294
                        self.write(', ')
 
1295
            if frame.buffer is not None:
 
1296
                # close the open parentheses
 
1297
                self.outdent()
 
1298
                self.writeline(len(body) == 1 and ')' or '))')
 
1299
 
 
1300
        # otherwise we create a format string as this is faster in that case
 
1301
        else:
 
1302
            format = []
 
1303
            arguments = []
 
1304
            for item in body:
 
1305
                if isinstance(item, list):
 
1306
                    format.append(concat(item).replace('%', '%%'))
 
1307
                else:
 
1308
                    format.append('%s')
 
1309
                    arguments.append(item)
 
1310
            self.writeline('yield ')
 
1311
            self.write(repr(concat(format)) + ' % (')
 
1312
            idx = -1
 
1313
            self.indent()
 
1314
            for argument in arguments:
 
1315
                self.newline(argument)
 
1316
                close = 0
 
1317
                if frame.eval_ctx.volatile:
 
1318
                    self.write('(context.eval_ctx.autoescape and'
 
1319
                               ' escape or to_string)(')
 
1320
                    close += 1
 
1321
                elif frame.eval_ctx.autoescape:
 
1322
                    self.write('escape(')
 
1323
                    close += 1
 
1324
                if self.environment.finalize is not None:
 
1325
                    self.write('environment.finalize(')
 
1326
                    close += 1
 
1327
                self.visit(argument, frame)
 
1328
                self.write(')' * close + ', ')
 
1329
            self.outdent()
 
1330
            self.writeline(')')
 
1331
 
 
1332
        if outdent_later:
 
1333
            self.outdent()
 
1334
 
 
1335
    def visit_Assign(self, node, frame):
 
1336
        self.newline(node)
 
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
 
1340
        # names here.
 
1341
        if frame.toplevel:
 
1342
            assignment_frame = frame.copy()
 
1343
            assignment_frame.toplevel_assignments = set()
 
1344
        else:
 
1345
            assignment_frame = frame
 
1346
        self.visit(node.target, assignment_frame)
 
1347
        self.write(' = ')
 
1348
        self.visit(node.node, frame)
 
1349
 
 
1350
        # make sure toplevel assignments are added to the context.
 
1351
        if frame.toplevel:
 
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))
 
1357
            else:
 
1358
                self.writeline('context.vars.update({')
 
1359
                for idx, name in enumerate(assignment_frame.toplevel_assignments):
 
1360
                    if idx:
 
1361
                        self.write(', ')
 
1362
                    self.write('%r: l_%s' % (name, name))
 
1363
                self.write('})')
 
1364
            if public_names:
 
1365
                if len(public_names) == 1:
 
1366
                    self.writeline('context.exported_vars.add(%r)' %
 
1367
                                   public_names[0])
 
1368
                else:
 
1369
                    self.writeline('context.exported_vars.update((%s))' %
 
1370
                                   ', '.join(imap(repr, public_names)))
 
1371
 
 
1372
    # -- Expression Visitors
 
1373
 
 
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)
 
1379
 
 
1380
    def visit_Const(self, node, frame):
 
1381
        val = node.value
 
1382
        if isinstance(val, float):
 
1383
            self.write(str(val))
 
1384
        else:
 
1385
            self.write(repr(val))
 
1386
 
 
1387
    def visit_TemplateData(self, node, frame):
 
1388
        try:
 
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)'
 
1392
                       % node.data)
 
1393
 
 
1394
    def visit_Tuple(self, node, frame):
 
1395
        self.write('(')
 
1396
        idx = -1
 
1397
        for idx, item in enumerate(node.items):
 
1398
            if idx:
 
1399
                self.write(', ')
 
1400
            self.visit(item, frame)
 
1401
        self.write(idx == 0 and ',)' or ')')
 
1402
 
 
1403
    def visit_List(self, node, frame):
 
1404
        self.write('[')
 
1405
        for idx, item in enumerate(node.items):
 
1406
            if idx:
 
1407
                self.write(', ')
 
1408
            self.visit(item, frame)
 
1409
        self.write(']')
 
1410
 
 
1411
    def visit_Dict(self, node, frame):
 
1412
        self.write('{')
 
1413
        for idx, item in enumerate(node.items):
 
1414
            if idx:
 
1415
                self.write(', ')
 
1416
            self.visit(item.key, frame)
 
1417
            self.write(': ')
 
1418
            self.visit(item.value, frame)
 
1419
        self.write('}')
 
1420
 
 
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)
 
1427
                self.write(', ')
 
1428
                self.visit(node.right, frame)
 
1429
            else:
 
1430
                self.write('(')
 
1431
                self.visit(node.left, frame)
 
1432
                self.write(' %s ' % operator)
 
1433
                self.visit(node.right, frame)
 
1434
            self.write(')')
 
1435
        return visitor
 
1436
 
 
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)
 
1443
            else:
 
1444
                self.write('(' + operator)
 
1445
                self.visit(node.node, frame)
 
1446
            self.write(')')
 
1447
        return visitor
 
1448
 
 
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)
 
1461
    del binop, uaop
 
1462
 
 
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'
 
1469
        else:
 
1470
            func_name = 'unicode_join'
 
1471
        self.write('%s((' % func_name)
 
1472
        for arg in node.nodes:
 
1473
            self.visit(arg, frame)
 
1474
            self.write(', ')
 
1475
        self.write('))')
 
1476
 
 
1477
    def visit_Compare(self, node, frame):
 
1478
        self.visit(node.expr, frame)
 
1479
        for op in node.ops:
 
1480
            self.visit(op, frame)
 
1481
 
 
1482
    def visit_Operand(self, node, frame):
 
1483
        self.write(' %s ' % operators[node.op])
 
1484
        self.visit(node.expr, frame)
 
1485
 
 
1486
    def visit_Getattr(self, node, frame):
 
1487
        self.write('environment.getattr(')
 
1488
        self.visit(node.node, frame)
 
1489
        self.write(', %r)' % node.attr)
 
1490
 
 
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)
 
1495
            self.write('[')
 
1496
            self.visit(node.arg, frame)
 
1497
            self.write(']')
 
1498
        else:
 
1499
            self.write('environment.getitem(')
 
1500
            self.visit(node.node, frame)
 
1501
            self.write(', ')
 
1502
            self.visit(node.arg, frame)
 
1503
            self.write(')')
 
1504
 
 
1505
    def visit_Slice(self, node, frame):
 
1506
        if node.start is not None:
 
1507
            self.visit(node.start, frame)
 
1508
        self.write(':')
 
1509
        if node.stop is not None:
 
1510
            self.visit(node.stop, frame)
 
1511
        if node.step is not None:
 
1512
            self.write(':')
 
1513
            self.visit(node.step, frame)
 
1514
 
 
1515
    def visit_Filter(self, node, frame):
 
1516
        self.write(self.filters[node.name] + '(')
 
1517
        func = self.environment.filters.get(node.name)
 
1518
        if func is None:
 
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, ')
 
1526
 
 
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)
 
1537
        else:
 
1538
            self.write('concat(%s)' % frame.buffer)
 
1539
        self.signature(node, frame)
 
1540
        self.write(')')
 
1541
 
 
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)
 
1548
        self.write(')')
 
1549
 
 
1550
    def visit_CondExpr(self, node, frame):
 
1551
        def write_expr2():
 
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)))
 
1557
 
 
1558
        self.write('(')
 
1559
        self.visit(node.expr1, frame)
 
1560
        self.write(' if ')
 
1561
        self.visit(node.test, frame)
 
1562
        self.write(' else ')
 
1563
        write_expr2()
 
1564
        self.write(')')
 
1565
 
 
1566
    def visit_Call(self, node, frame, forward_caller=False):
 
1567
        if self.environment.sandboxed:
 
1568
            self.write('environment.call(context, ')
 
1569
        else:
 
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)
 
1574
        self.write(')')
 
1575
 
 
1576
    def visit_Keyword(self, node, frame):
 
1577
        self.write(node.key + '=')
 
1578
        self.visit(node.value, frame)
 
1579
 
 
1580
    # -- Unused nodes for extensions
 
1581
 
 
1582
    def visit_MarkSafe(self, node, frame):
 
1583
        self.write('Markup(')
 
1584
        self.visit(node.expr, frame)
 
1585
        self.write(')')
 
1586
 
 
1587
    def visit_MarkSafeIfAutoescape(self, node, frame):
 
1588
        self.write('(context.eval_ctx.autoescape and Markup or identity)(')
 
1589
        self.visit(node.expr, frame)
 
1590
        self.write(')')
 
1591
 
 
1592
    def visit_EnvironmentAttribute(self, node, frame):
 
1593
        self.write('environment.' + node.name)
 
1594
 
 
1595
    def visit_ExtensionAttribute(self, node, frame):
 
1596
        self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
 
1597
 
 
1598
    def visit_ImportedName(self, node, frame):
 
1599
        self.write(self.import_aliases[node.importname])
 
1600
 
 
1601
    def visit_InternalName(self, node, frame):
 
1602
        self.write(node.name)
 
1603
 
 
1604
    def visit_ContextReference(self, node, frame):
 
1605
        self.write('context')
 
1606
 
 
1607
    def visit_Continue(self, node, frame):
 
1608
        self.writeline('continue', node)
 
1609
 
 
1610
    def visit_Break(self, node, frame):
 
1611
        self.writeline('break', node)
 
1612
 
 
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)
 
1620
 
 
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)
 
1625
            try:
 
1626
                val = keyword.value.as_const(frame.eval_ctx)
 
1627
            except nodes.Impossible:
 
1628
                frame.eval_ctx.volatile = True
 
1629
            else:
 
1630
                setattr(frame.eval_ctx, keyword.key, val)
 
1631
 
 
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)