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