Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(171)

Side by Side Diff: third_party/jinja2/compiler.py

Issue 14761007: Add Python templating engine Jinja2 to third_party (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/jinja2/bccache.py ('k') | third_party/jinja2/constants.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 cStringIO import StringIO
12 from itertools import chain
13 from copy import deepcopy
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, is_python_keyword, next
19
20
21 operators = {
22 'eq': '==',
23 'ne': '!=',
24 'gt': '>',
25 'gteq': '>=',
26 'lt': '<',
27 'lteq': '<=',
28 'in': 'in',
29 'notin': 'not in'
30 }
31
32 try:
33 exec '(0 if 0 else 0)'
34 except SyntaxError:
35 have_condexpr = False
36 else:
37 have_condexpr = True
38
39
40 # what method to iterate over items do we want to use for dict iteration
41 # in generated code? on 2.x let's go with iteritems, on 3.x with items
42 if hasattr(dict, 'iteritems'):
43 dict_item_iter = 'iteritems'
44 else:
45 dict_item_iter = 'items'
46
47
48 # does if 0: dummy(x) get us x into the scope?
49 def unoptimize_before_dead_code():
50 x = 42
51 def f():
52 if 0: dummy(x)
53 return f
54 unoptimize_before_dead_code = bool(unoptimize_before_dead_code().func_closure)
55
56
57 def generate(node, environment, name, filename, stream=None,
58 defer_init=False):
59 """Generate the python source for a node tree."""
60 if not isinstance(node, nodes.Template):
61 raise TypeError('Can\'t compile non template nodes')
62 generator = CodeGenerator(environment, name, filename, stream, defer_init)
63 generator.visit(node)
64 if stream is None:
65 return generator.stream.getvalue()
66
67
68 def has_safe_repr(value):
69 """Does the node have a safe representation?"""
70 if value is None or value is NotImplemented or value is Ellipsis:
71 return True
72 if isinstance(value, (bool, int, long, float, complex, basestring,
73 xrange, Markup)):
74 return True
75 if isinstance(value, (tuple, list, set, frozenset)):
76 for item in value:
77 if not has_safe_repr(item):
78 return False
79 return True
80 elif isinstance(value, dict):
81 for key, value in value.iteritems():
82 if not has_safe_repr(key):
83 return False
84 if not has_safe_repr(value):
85 return False
86 return True
87 return False
88
89
90 def find_undeclared(nodes, names):
91 """Check if the names passed are accessed undeclared. The return value
92 is a set of all the undeclared names from the sequence of names found.
93 """
94 visitor = UndeclaredNameVisitor(names)
95 try:
96 for node in nodes:
97 visitor.visit(node)
98 except VisitorExit:
99 pass
100 return visitor.undeclared
101
102
103 class Identifiers(object):
104 """Tracks the status of identifiers in frames."""
105
106 def __init__(self):
107 # variables that are known to be declared (probably from outer
108 # frames or because they are special for the frame)
109 self.declared = set()
110
111 # undeclared variables from outer scopes
112 self.outer_undeclared = set()
113
114 # names that are accessed without being explicitly declared by
115 # this one or any of the outer scopes. Names can appear both in
116 # declared and undeclared.
117 self.undeclared = set()
118
119 # names that are declared locally
120 self.declared_locally = set()
121
122 # names that are declared by parameters
123 self.declared_parameter = set()
124
125 def add_special(self, name):
126 """Register a special name like `loop`."""
127 self.undeclared.discard(name)
128 self.declared.add(name)
129
130 def is_declared(self, name):
131 """Check if a name is declared in this or an outer scope."""
132 if name in self.declared_locally or name in self.declared_parameter:
133 return True
134 return name in self.declared
135
136 def copy(self):
137 return deepcopy(self)
138
139
140 class Frame(object):
141 """Holds compile time information for us."""
142
143 def __init__(self, eval_ctx, parent=None):
144 self.eval_ctx = eval_ctx
145 self.identifiers = Identifiers()
146
147 # a toplevel frame is the root + soft frames such as if conditions.
148 self.toplevel = False
149
150 # the root frame is basically just the outermost frame, so no if
151 # conditions. This information is used to optimize inheritance
152 # situations.
153 self.rootlevel = False
154
155 # in some dynamic inheritance situations the compiler needs to add
156 # write tests around output statements.
157 self.require_output_check = parent and parent.require_output_check
158
159 # inside some tags we are using a buffer rather than yield statements.
160 # this for example affects {% filter %} or {% macro %}. If a frame
161 # is buffered this variable points to the name of the list used as
162 # buffer.
163 self.buffer = None
164
165 # the name of the block we're in, otherwise None.
166 self.block = parent and parent.block or None
167
168 # a set of actually assigned names
169 self.assigned_names = set()
170
171 # the parent of this frame
172 self.parent = parent
173
174 if parent is not None:
175 self.identifiers.declared.update(
176 parent.identifiers.declared |
177 parent.identifiers.declared_parameter |
178 parent.assigned_names
179 )
180 self.identifiers.outer_undeclared.update(
181 parent.identifiers.undeclared -
182 self.identifiers.declared
183 )
184 self.buffer = parent.buffer
185
186 def copy(self):
187 """Create a copy of the current one."""
188 rv = object.__new__(self.__class__)
189 rv.__dict__.update(self.__dict__)
190 rv.identifiers = object.__new__(self.identifiers.__class__)
191 rv.identifiers.__dict__.update(self.identifiers.__dict__)
192 return rv
193
194 def inspect(self, nodes):
195 """Walk the node and check for identifiers. If the scope is hard (eg:
196 enforce on a python level) overrides from outer scopes are tracked
197 differently.
198 """
199 visitor = FrameIdentifierVisitor(self.identifiers)
200 for node in nodes:
201 visitor.visit(node)
202
203 def find_shadowed(self, extra=()):
204 """Find all the shadowed names. extra is an iterable of variables
205 that may be defined with `add_special` which may occour scoped.
206 """
207 i = self.identifiers
208 return (i.declared | i.outer_undeclared) & \
209 (i.declared_locally | i.declared_parameter) | \
210 set(x for x in extra if i.is_declared(x))
211
212 def inner(self):
213 """Return an inner frame."""
214 return Frame(self.eval_ctx, self)
215
216 def soft(self):
217 """Return a soft frame. A soft frame may not be modified as
218 standalone thing as it shares the resources with the frame it
219 was created of, but it's not a rootlevel frame any longer.
220 """
221 rv = self.copy()
222 rv.rootlevel = False
223 return rv
224
225 __copy__ = copy
226
227
228 class VisitorExit(RuntimeError):
229 """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
230
231
232 class DependencyFinderVisitor(NodeVisitor):
233 """A visitor that collects filter and test calls."""
234
235 def __init__(self):
236 self.filters = set()
237 self.tests = set()
238
239 def visit_Filter(self, node):
240 self.generic_visit(node)
241 self.filters.add(node.name)
242
243 def visit_Test(self, node):
244 self.generic_visit(node)
245 self.tests.add(node.name)
246
247 def visit_Block(self, node):
248 """Stop visiting at blocks."""
249
250
251 class UndeclaredNameVisitor(NodeVisitor):
252 """A visitor that checks if a name is accessed without being
253 declared. This is different from the frame visitor as it will
254 not stop at closure frames.
255 """
256
257 def __init__(self, names):
258 self.names = set(names)
259 self.undeclared = set()
260
261 def visit_Name(self, node):
262 if node.ctx == 'load' and node.name in self.names:
263 self.undeclared.add(node.name)
264 if self.undeclared == self.names:
265 raise VisitorExit()
266 else:
267 self.names.discard(node.name)
268
269 def visit_Block(self, node):
270 """Stop visiting a blocks."""
271
272
273 class FrameIdentifierVisitor(NodeVisitor):
274 """A visitor for `Frame.inspect`."""
275
276 def __init__(self, identifiers):
277 self.identifiers = identifiers
278
279 def visit_Name(self, node):
280 """All assignments to names go through this function."""
281 if node.ctx == 'store':
282 self.identifiers.declared_locally.add(node.name)
283 elif node.ctx == 'param':
284 self.identifiers.declared_parameter.add(node.name)
285 elif node.ctx == 'load' and not \
286 self.identifiers.is_declared(node.name):
287 self.identifiers.undeclared.add(node.name)
288
289 def visit_If(self, node):
290 self.visit(node.test)
291 real_identifiers = self.identifiers
292
293 old_names = real_identifiers.declared_locally | \
294 real_identifiers.declared_parameter
295
296 def inner_visit(nodes):
297 if not nodes:
298 return set()
299 self.identifiers = real_identifiers.copy()
300 for subnode in nodes:
301 self.visit(subnode)
302 rv = self.identifiers.declared_locally - old_names
303 # we have to remember the undeclared variables of this branch
304 # because we will have to pull them.
305 real_identifiers.undeclared.update(self.identifiers.undeclared)
306 self.identifiers = real_identifiers
307 return rv
308
309 body = inner_visit(node.body)
310 else_ = inner_visit(node.else_ or ())
311
312 # the differences between the two branches are also pulled as
313 # undeclared variables
314 real_identifiers.undeclared.update(body.symmetric_difference(else_) -
315 real_identifiers.declared)
316
317 # remember those that are declared.
318 real_identifiers.declared_locally.update(body | else_)
319
320 def visit_Macro(self, node):
321 self.identifiers.declared_locally.add(node.name)
322
323 def visit_Import(self, node):
324 self.generic_visit(node)
325 self.identifiers.declared_locally.add(node.target)
326
327 def visit_FromImport(self, node):
328 self.generic_visit(node)
329 for name in node.names:
330 if isinstance(name, tuple):
331 self.identifiers.declared_locally.add(name[1])
332 else:
333 self.identifiers.declared_locally.add(name)
334
335 def visit_Assign(self, node):
336 """Visit assignments in the correct order."""
337 self.visit(node.node)
338 self.visit(node.target)
339
340 def visit_For(self, node):
341 """Visiting stops at for blocks. However the block sequence
342 is visited as part of the outer scope.
343 """
344 self.visit(node.iter)
345
346 def visit_CallBlock(self, node):
347 self.visit(node.call)
348
349 def visit_FilterBlock(self, node):
350 self.visit(node.filter)
351
352 def visit_Scope(self, node):
353 """Stop visiting at scopes."""
354
355 def visit_Block(self, node):
356 """Stop visiting at blocks."""
357
358
359 class CompilerExit(Exception):
360 """Raised if the compiler encountered a situation where it just
361 doesn't make sense to further process the code. Any block that
362 raises such an exception is not further processed.
363 """
364
365
366 class CodeGenerator(NodeVisitor):
367
368 def __init__(self, environment, name, filename, stream=None,
369 defer_init=False):
370 if stream is None:
371 stream = StringIO()
372 self.environment = environment
373 self.name = name
374 self.filename = filename
375 self.stream = stream
376 self.created_block_context = False
377 self.defer_init = defer_init
378
379 # aliases for imports
380 self.import_aliases = {}
381
382 # a registry for all blocks. Because blocks are moved out
383 # into the global python scope they are registered here
384 self.blocks = {}
385
386 # the number of extends statements so far
387 self.extends_so_far = 0
388
389 # some templates have a rootlevel extends. In this case we
390 # can safely assume that we're a child template and do some
391 # more optimizations.
392 self.has_known_extends = False
393
394 # the current line number
395 self.code_lineno = 1
396
397 # registry of all filters and tests (global, not block local)
398 self.tests = {}
399 self.filters = {}
400
401 # the debug information
402 self.debug_info = []
403 self._write_debug_info = None
404
405 # the number of new lines before the next write()
406 self._new_lines = 0
407
408 # the line number of the last written statement
409 self._last_line = 0
410
411 # true if nothing was written so far.
412 self._first_write = True
413
414 # used by the `temporary_identifier` method to get new
415 # unique, temporary identifier
416 self._last_identifier = 0
417
418 # the current indentation
419 self._indentation = 0
420
421 # -- Various compilation helpers
422
423 def fail(self, msg, lineno):
424 """Fail with a :exc:`TemplateAssertionError`."""
425 raise TemplateAssertionError(msg, lineno, self.name, self.filename)
426
427 def temporary_identifier(self):
428 """Get a new unique identifier."""
429 self._last_identifier += 1
430 return 't_%d' % self._last_identifier
431
432 def buffer(self, frame):
433 """Enable buffering for the frame from that point onwards."""
434 frame.buffer = self.temporary_identifier()
435 self.writeline('%s = []' % frame.buffer)
436
437 def return_buffer_contents(self, frame):
438 """Return the buffer contents of the frame."""
439 if frame.eval_ctx.volatile:
440 self.writeline('if context.eval_ctx.autoescape:')
441 self.indent()
442 self.writeline('return Markup(concat(%s))' % frame.buffer)
443 self.outdent()
444 self.writeline('else:')
445 self.indent()
446 self.writeline('return concat(%s)' % frame.buffer)
447 self.outdent()
448 elif frame.eval_ctx.autoescape:
449 self.writeline('return Markup(concat(%s))' % frame.buffer)
450 else:
451 self.writeline('return concat(%s)' % frame.buffer)
452
453 def indent(self):
454 """Indent by one."""
455 self._indentation += 1
456
457 def outdent(self, step=1):
458 """Outdent by step."""
459 self._indentation -= step
460
461 def start_write(self, frame, node=None):
462 """Yield or write into the frame buffer."""
463 if frame.buffer is None:
464 self.writeline('yield ', node)
465 else:
466 self.writeline('%s.append(' % frame.buffer, node)
467
468 def end_write(self, frame):
469 """End the writing process started by `start_write`."""
470 if frame.buffer is not None:
471 self.write(')')
472
473 def simple_write(self, s, frame, node=None):
474 """Simple shortcut for start_write + write + end_write."""
475 self.start_write(frame, node)
476 self.write(s)
477 self.end_write(frame)
478
479 def blockvisit(self, nodes, frame):
480 """Visit a list of nodes as block in a frame. If the current frame
481 is no buffer a dummy ``if 0: yield None`` is written automatically
482 unless the force_generator parameter is set to False.
483 """
484 if frame.buffer is None:
485 self.writeline('if 0: yield None')
486 else:
487 self.writeline('pass')
488 try:
489 for node in nodes:
490 self.visit(node, frame)
491 except CompilerExit:
492 pass
493
494 def write(self, x):
495 """Write a string into the output stream."""
496 if self._new_lines:
497 if not self._first_write:
498 self.stream.write('\n' * self._new_lines)
499 self.code_lineno += self._new_lines
500 if self._write_debug_info is not None:
501 self.debug_info.append((self._write_debug_info,
502 self.code_lineno))
503 self._write_debug_info = None
504 self._first_write = False
505 self.stream.write(' ' * self._indentation)
506 self._new_lines = 0
507 self.stream.write(x)
508
509 def writeline(self, x, node=None, extra=0):
510 """Combination of newline and write."""
511 self.newline(node, extra)
512 self.write(x)
513
514 def newline(self, node=None, extra=0):
515 """Add one or more newlines before the next write."""
516 self._new_lines = max(self._new_lines, 1 + extra)
517 if node is not None and node.lineno != self._last_line:
518 self._write_debug_info = node.lineno
519 self._last_line = node.lineno
520
521 def signature(self, node, frame, extra_kwargs=None):
522 """Writes a function call to the stream for the current node.
523 A leading comma is added automatically. The extra keyword
524 arguments may not include python keywords otherwise a syntax
525 error could occour. The extra keyword arguments should be given
526 as python dict.
527 """
528 # if any of the given keyword arguments is a python keyword
529 # we have to make sure that no invalid call is created.
530 kwarg_workaround = False
531 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
532 if is_python_keyword(kwarg):
533 kwarg_workaround = True
534 break
535
536 for arg in node.args:
537 self.write(', ')
538 self.visit(arg, frame)
539
540 if not kwarg_workaround:
541 for kwarg in node.kwargs:
542 self.write(', ')
543 self.visit(kwarg, frame)
544 if extra_kwargs is not None:
545 for key, value in extra_kwargs.iteritems():
546 self.write(', %s=%s' % (key, value))
547 if node.dyn_args:
548 self.write(', *')
549 self.visit(node.dyn_args, frame)
550
551 if kwarg_workaround:
552 if node.dyn_kwargs is not None:
553 self.write(', **dict({')
554 else:
555 self.write(', **{')
556 for kwarg in node.kwargs:
557 self.write('%r: ' % kwarg.key)
558 self.visit(kwarg.value, frame)
559 self.write(', ')
560 if extra_kwargs is not None:
561 for key, value in extra_kwargs.iteritems():
562 self.write('%r: %s, ' % (key, value))
563 if node.dyn_kwargs is not None:
564 self.write('}, **')
565 self.visit(node.dyn_kwargs, frame)
566 self.write(')')
567 else:
568 self.write('}')
569
570 elif node.dyn_kwargs is not None:
571 self.write(', **')
572 self.visit(node.dyn_kwargs, frame)
573
574 def pull_locals(self, frame):
575 """Pull all the references identifiers into the local scope."""
576 for name in frame.identifiers.undeclared:
577 self.writeline('l_%s = context.resolve(%r)' % (name, name))
578
579 def pull_dependencies(self, nodes):
580 """Pull all the dependencies."""
581 visitor = DependencyFinderVisitor()
582 for node in nodes:
583 visitor.visit(node)
584 for dependency in 'filters', 'tests':
585 mapping = getattr(self, dependency)
586 for name in getattr(visitor, dependency):
587 if name not in mapping:
588 mapping[name] = self.temporary_identifier()
589 self.writeline('%s = environment.%s[%r]' %
590 (mapping[name], dependency, name))
591
592 def unoptimize_scope(self, frame):
593 """Disable Python optimizations for the frame."""
594 # XXX: this is not that nice but it has no real overhead. It
595 # mainly works because python finds the locals before dead code
596 # is removed. If that breaks we have to add a dummy function
597 # that just accepts the arguments and does nothing.
598 if frame.identifiers.declared:
599 self.writeline('%sdummy(%s)' % (
600 unoptimize_before_dead_code and 'if 0: ' or '',
601 ', '.join('l_' + name for name in frame.identifiers.declared)
602 ))
603
604 def push_scope(self, frame, extra_vars=()):
605 """This function returns all the shadowed variables in a dict
606 in the form name: alias and will write the required assignments
607 into the current scope. No indentation takes place.
608
609 This also predefines locally declared variables from the loop
610 body because under some circumstances it may be the case that
611
612 `extra_vars` is passed to `Frame.find_shadowed`.
613 """
614 aliases = {}
615 for name in frame.find_shadowed(extra_vars):
616 aliases[name] = ident = self.temporary_identifier()
617 self.writeline('%s = l_%s' % (ident, name))
618 to_declare = set()
619 for name in frame.identifiers.declared_locally:
620 if name not in aliases:
621 to_declare.add('l_' + name)
622 if to_declare:
623 self.writeline(' = '.join(to_declare) + ' = missing')
624 return aliases
625
626 def pop_scope(self, aliases, frame):
627 """Restore all aliases and delete unused variables."""
628 for name, alias in aliases.iteritems():
629 self.writeline('l_%s = %s' % (name, alias))
630 to_delete = set()
631 for name in frame.identifiers.declared_locally:
632 if name not in aliases:
633 to_delete.add('l_' + name)
634 if to_delete:
635 # we cannot use the del statement here because enclosed
636 # scopes can trigger a SyntaxError:
637 # a = 42; b = lambda: a; del a
638 self.writeline(' = '.join(to_delete) + ' = missing')
639
640 def function_scoping(self, node, frame, children=None,
641 find_special=True):
642 """In Jinja a few statements require the help of anonymous
643 functions. Those are currently macros and call blocks and in
644 the future also recursive loops. As there is currently
645 technical limitation that doesn't allow reading and writing a
646 variable in a scope where the initial value is coming from an
647 outer scope, this function tries to fall back with a common
648 error message. Additionally the frame passed is modified so
649 that the argumetns are collected and callers are looked up.
650
651 This will return the modified frame.
652 """
653 # we have to iterate twice over it, make sure that works
654 if children is None:
655 children = node.iter_child_nodes()
656 children = list(children)
657 func_frame = frame.inner()
658 func_frame.inspect(children)
659
660 # variables that are undeclared (accessed before declaration) and
661 # declared locally *and* part of an outside scope raise a template
662 # assertion error. Reason: we can't generate reasonable code from
663 # it without aliasing all the variables.
664 # this could be fixed in Python 3 where we have the nonlocal
665 # keyword or if we switch to bytecode generation
666 overriden_closure_vars = (
667 func_frame.identifiers.undeclared &
668 func_frame.identifiers.declared &
669 (func_frame.identifiers.declared_locally |
670 func_frame.identifiers.declared_parameter)
671 )
672 if overriden_closure_vars:
673 self.fail('It\'s not possible to set and access variables '
674 'derived from an outer scope! (affects: %s)' %
675 ', '.join(sorted(overriden_closure_vars)), node.lineno)
676
677 # remove variables from a closure from the frame's undeclared
678 # identifiers.
679 func_frame.identifiers.undeclared -= (
680 func_frame.identifiers.undeclared &
681 func_frame.identifiers.declared
682 )
683
684 # no special variables for this scope, abort early
685 if not find_special:
686 return func_frame
687
688 func_frame.accesses_kwargs = False
689 func_frame.accesses_varargs = False
690 func_frame.accesses_caller = False
691 func_frame.arguments = args = ['l_' + x.name for x in node.args]
692
693 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
694
695 if 'caller' in undeclared:
696 func_frame.accesses_caller = True
697 func_frame.identifiers.add_special('caller')
698 args.append('l_caller')
699 if 'kwargs' in undeclared:
700 func_frame.accesses_kwargs = True
701 func_frame.identifiers.add_special('kwargs')
702 args.append('l_kwargs')
703 if 'varargs' in undeclared:
704 func_frame.accesses_varargs = True
705 func_frame.identifiers.add_special('varargs')
706 args.append('l_varargs')
707 return func_frame
708
709 def macro_body(self, node, frame, children=None):
710 """Dump the function def of a macro or call block."""
711 frame = self.function_scoping(node, frame, children)
712 # macros are delayed, they never require output checks
713 frame.require_output_check = False
714 args = frame.arguments
715 # XXX: this is an ugly fix for the loop nesting bug
716 # (tests.test_old_bugs.test_loop_call_bug). This works around
717 # a identifier nesting problem we have in general. It's just more
718 # likely to happen in loops which is why we work around it. The
719 # real solution would be "nonlocal" all the identifiers that are
720 # leaking into a new python frame and might be used both unassigned
721 # and assigned.
722 if 'loop' in frame.identifiers.declared:
723 args = args + ['l_loop=l_loop']
724 self.writeline('def macro(%s):' % ', '.join(args), node)
725 self.indent()
726 self.buffer(frame)
727 self.pull_locals(frame)
728 self.blockvisit(node.body, frame)
729 self.return_buffer_contents(frame)
730 self.outdent()
731 return frame
732
733 def macro_def(self, node, frame):
734 """Dump the macro definition for the def created by macro_body."""
735 arg_tuple = ', '.join(repr(x.name) for x in node.args)
736 name = getattr(node, 'name', None)
737 if len(node.args) == 1:
738 arg_tuple += ','
739 self.write('Macro(environment, macro, %r, (%s), (' %
740 (name, arg_tuple))
741 for arg in node.defaults:
742 self.visit(arg, frame)
743 self.write(', ')
744 self.write('), %r, %r, %r)' % (
745 bool(frame.accesses_kwargs),
746 bool(frame.accesses_varargs),
747 bool(frame.accesses_caller)
748 ))
749
750 def position(self, node):
751 """Return a human readable position for the node."""
752 rv = 'line %d' % node.lineno
753 if self.name is not None:
754 rv += ' in ' + repr(self.name)
755 return rv
756
757 # -- Statement Visitors
758
759 def visit_Template(self, node, frame=None):
760 assert frame is None, 'no root frame allowed'
761 eval_ctx = EvalContext(self.environment, self.name)
762
763 from jinja2.runtime import __all__ as exported
764 self.writeline('from __future__ import division')
765 self.writeline('from jinja2.runtime import ' + ', '.join(exported))
766 if not unoptimize_before_dead_code:
767 self.writeline('dummy = lambda *x: None')
768
769 # if we want a deferred initialization we cannot move the
770 # environment into a local name
771 envenv = not self.defer_init and ', environment=environment' or ''
772
773 # do we have an extends tag at all? If not, we can save some
774 # overhead by just not processing any inheritance code.
775 have_extends = node.find(nodes.Extends) is not None
776
777 # find all blocks
778 for block in node.find_all(nodes.Block):
779 if block.name in self.blocks:
780 self.fail('block %r defined twice' % block.name, block.lineno)
781 self.blocks[block.name] = block
782
783 # find all imports and import them
784 for import_ in node.find_all(nodes.ImportedName):
785 if import_.importname not in self.import_aliases:
786 imp = import_.importname
787 self.import_aliases[imp] = alias = self.temporary_identifier()
788 if '.' in imp:
789 module, obj = imp.rsplit('.', 1)
790 self.writeline('from %s import %s as %s' %
791 (module, obj, alias))
792 else:
793 self.writeline('import %s as %s' % (imp, alias))
794
795 # add the load name
796 self.writeline('name = %r' % self.name)
797
798 # generate the root render function.
799 self.writeline('def root(context%s):' % envenv, extra=1)
800
801 # process the root
802 frame = Frame(eval_ctx)
803 frame.inspect(node.body)
804 frame.toplevel = frame.rootlevel = True
805 frame.require_output_check = have_extends and not self.has_known_extends
806 self.indent()
807 if have_extends:
808 self.writeline('parent_template = None')
809 if 'self' in find_undeclared(node.body, ('self',)):
810 frame.identifiers.add_special('self')
811 self.writeline('l_self = TemplateReference(context)')
812 self.pull_locals(frame)
813 self.pull_dependencies(node.body)
814 self.blockvisit(node.body, frame)
815 self.outdent()
816
817 # make sure that the parent root is called.
818 if have_extends:
819 if not self.has_known_extends:
820 self.indent()
821 self.writeline('if parent_template is not None:')
822 self.indent()
823 self.writeline('for event in parent_template.'
824 'root_render_func(context):')
825 self.indent()
826 self.writeline('yield event')
827 self.outdent(2 + (not self.has_known_extends))
828
829 # at this point we now have the blocks collected and can visit them too.
830 for name, block in self.blocks.iteritems():
831 block_frame = Frame(eval_ctx)
832 block_frame.inspect(block.body)
833 block_frame.block = name
834 self.writeline('def block_%s(context%s):' % (name, envenv),
835 block, 1)
836 self.indent()
837 undeclared = find_undeclared(block.body, ('self', 'super'))
838 if 'self' in undeclared:
839 block_frame.identifiers.add_special('self')
840 self.writeline('l_self = TemplateReference(context)')
841 if 'super' in undeclared:
842 block_frame.identifiers.add_special('super')
843 self.writeline('l_super = context.super(%r, '
844 'block_%s)' % (name, name))
845 self.pull_locals(block_frame)
846 self.pull_dependencies(block.body)
847 self.blockvisit(block.body, block_frame)
848 self.outdent()
849
850 self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
851 for x in self.blocks),
852 extra=1)
853
854 # add a function that returns the debug info
855 self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
856 in self.debug_info))
857
858 def visit_Block(self, node, frame):
859 """Call a block and register it for the template."""
860 level = 1
861 if frame.toplevel:
862 # if we know that we are a child template, there is no need to
863 # check if we are one
864 if self.has_known_extends:
865 return
866 if self.extends_so_far > 0:
867 self.writeline('if parent_template is None:')
868 self.indent()
869 level += 1
870 context = node.scoped and 'context.derived(locals())' or 'context'
871 self.writeline('for event in context.blocks[%r][0](%s):' % (
872 node.name, context), node)
873 self.indent()
874 self.simple_write('event', frame)
875 self.outdent(level)
876
877 def visit_Extends(self, node, frame):
878 """Calls the extender."""
879 if not frame.toplevel:
880 self.fail('cannot use extend from a non top-level scope',
881 node.lineno)
882
883 # if the number of extends statements in general is zero so
884 # far, we don't have to add a check if something extended
885 # the template before this one.
886 if self.extends_so_far > 0:
887
888 # if we have a known extends we just add a template runtime
889 # error into the generated code. We could catch that at compile
890 # time too, but i welcome it not to confuse users by throwing the
891 # same error at different times just "because we can".
892 if not self.has_known_extends:
893 self.writeline('if parent_template is not None:')
894 self.indent()
895 self.writeline('raise TemplateRuntimeError(%r)' %
896 'extended multiple times')
897 self.outdent()
898
899 # if we have a known extends already we don't need that code here
900 # as we know that the template execution will end here.
901 if self.has_known_extends:
902 raise CompilerExit()
903
904 self.writeline('parent_template = environment.get_template(', node)
905 self.visit(node.template, frame)
906 self.write(', %r)' % self.name)
907 self.writeline('for name, parent_block in parent_template.'
908 'blocks.%s():' % dict_item_iter)
909 self.indent()
910 self.writeline('context.blocks.setdefault(name, []).'
911 'append(parent_block)')
912 self.outdent()
913
914 # if this extends statement was in the root level we can take
915 # advantage of that information and simplify the generated code
916 # in the top level from this point onwards
917 if frame.rootlevel:
918 self.has_known_extends = True
919
920 # and now we have one more
921 self.extends_so_far += 1
922
923 def visit_Include(self, node, frame):
924 """Handles includes."""
925 if node.with_context:
926 self.unoptimize_scope(frame)
927 if node.ignore_missing:
928 self.writeline('try:')
929 self.indent()
930
931 func_name = 'get_or_select_template'
932 if isinstance(node.template, nodes.Const):
933 if isinstance(node.template.value, basestring):
934 func_name = 'get_template'
935 elif isinstance(node.template.value, (tuple, list)):
936 func_name = 'select_template'
937 elif isinstance(node.template, (nodes.Tuple, nodes.List)):
938 func_name = 'select_template'
939
940 self.writeline('template = environment.%s(' % func_name, node)
941 self.visit(node.template, frame)
942 self.write(', %r)' % self.name)
943 if node.ignore_missing:
944 self.outdent()
945 self.writeline('except TemplateNotFound:')
946 self.indent()
947 self.writeline('pass')
948 self.outdent()
949 self.writeline('else:')
950 self.indent()
951
952 if node.with_context:
953 self.writeline('for event in template.root_render_func('
954 'template.new_context(context.parent, True, '
955 'locals())):')
956 else:
957 self.writeline('for event in template.module._body_stream:')
958
959 self.indent()
960 self.simple_write('event', frame)
961 self.outdent()
962
963 if node.ignore_missing:
964 self.outdent()
965
966 def visit_Import(self, node, frame):
967 """Visit regular imports."""
968 if node.with_context:
969 self.unoptimize_scope(frame)
970 self.writeline('l_%s = ' % node.target, node)
971 if frame.toplevel:
972 self.write('context.vars[%r] = ' % node.target)
973 self.write('environment.get_template(')
974 self.visit(node.template, frame)
975 self.write(', %r).' % self.name)
976 if node.with_context:
977 self.write('make_module(context.parent, True, locals())')
978 else:
979 self.write('module')
980 if frame.toplevel and not node.target.startswith('_'):
981 self.writeline('context.exported_vars.discard(%r)' % node.target)
982 frame.assigned_names.add(node.target)
983
984 def visit_FromImport(self, node, frame):
985 """Visit named imports."""
986 self.newline(node)
987 self.write('included_template = environment.get_template(')
988 self.visit(node.template, frame)
989 self.write(', %r).' % self.name)
990 if node.with_context:
991 self.write('make_module(context.parent, True)')
992 else:
993 self.write('module')
994
995 var_names = []
996 discarded_names = []
997 for name in node.names:
998 if isinstance(name, tuple):
999 name, alias = name
1000 else:
1001 alias = name
1002 self.writeline('l_%s = getattr(included_template, '
1003 '%r, missing)' % (alias, name))
1004 self.writeline('if l_%s is missing:' % alias)
1005 self.indent()
1006 self.writeline('l_%s = environment.undefined(%r %% '
1007 'included_template.__name__, '
1008 'name=%r)' %
1009 (alias, 'the template %%r (imported on %s) does '
1010 'not export the requested name %s' % (
1011 self.position(node),
1012 repr(name)
1013 ), name))
1014 self.outdent()
1015 if frame.toplevel:
1016 var_names.append(alias)
1017 if not alias.startswith('_'):
1018 discarded_names.append(alias)
1019 frame.assigned_names.add(alias)
1020
1021 if var_names:
1022 if len(var_names) == 1:
1023 name = var_names[0]
1024 self.writeline('context.vars[%r] = l_%s' % (name, name))
1025 else:
1026 self.writeline('context.vars.update({%s})' % ', '.join(
1027 '%r: l_%s' % (name, name) for name in var_names
1028 ))
1029 if discarded_names:
1030 if len(discarded_names) == 1:
1031 self.writeline('context.exported_vars.discard(%r)' %
1032 discarded_names[0])
1033 else:
1034 self.writeline('context.exported_vars.difference_'
1035 'update((%s))' % ', '.join(map(repr, discarded_na mes)))
1036
1037 def visit_For(self, node, frame):
1038 # when calculating the nodes for the inner frame we have to exclude
1039 # the iterator contents from it
1040 children = node.iter_child_nodes(exclude=('iter',))
1041 if node.recursive:
1042 loop_frame = self.function_scoping(node, frame, children,
1043 find_special=False)
1044 else:
1045 loop_frame = frame.inner()
1046 loop_frame.inspect(children)
1047
1048 # try to figure out if we have an extended loop. An extended loop
1049 # is necessary if the loop is in recursive mode if the special loop
1050 # variable is accessed in the body.
1051 extended_loop = node.recursive or 'loop' in \
1052 find_undeclared(node.iter_child_nodes(
1053 only=('body',)), ('loop',))
1054
1055 # if we don't have an recursive loop we have to find the shadowed
1056 # variables at that point. Because loops can be nested but the loop
1057 # variable is a special one we have to enforce aliasing for it.
1058 if not node.recursive:
1059 aliases = self.push_scope(loop_frame, ('loop',))
1060
1061 # otherwise we set up a buffer and add a function def
1062 else:
1063 self.writeline('def loop(reciter, loop_render_func):', node)
1064 self.indent()
1065 self.buffer(loop_frame)
1066 aliases = {}
1067
1068 # make sure the loop variable is a special one and raise a template
1069 # assertion error if a loop tries to write to loop
1070 if extended_loop:
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(', recurse=loop_render_func):')
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: unicode(self.environment.finalize(x))
1220 else:
1221 finalize = unicode
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(map(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 if not have_condexpr:
1559 self.write('((')
1560 self.visit(node.test, frame)
1561 self.write(') and (')
1562 self.visit(node.expr1, frame)
1563 self.write(',) or (')
1564 write_expr2()
1565 self.write(',))[0]')
1566 else:
1567 self.write('(')
1568 self.visit(node.expr1, frame)
1569 self.write(' if ')
1570 self.visit(node.test, frame)
1571 self.write(' else ')
1572 write_expr2()
1573 self.write(')')
1574
1575 def visit_Call(self, node, frame, forward_caller=False):
1576 if self.environment.sandboxed:
1577 self.write('environment.call(context, ')
1578 else:
1579 self.write('context.call(')
1580 self.visit(node.node, frame)
1581 extra_kwargs = forward_caller and {'caller': 'caller'} or None
1582 self.signature(node, frame, extra_kwargs)
1583 self.write(')')
1584
1585 def visit_Keyword(self, node, frame):
1586 self.write(node.key + '=')
1587 self.visit(node.value, frame)
1588
1589 # -- Unused nodes for extensions
1590
1591 def visit_MarkSafe(self, node, frame):
1592 self.write('Markup(')
1593 self.visit(node.expr, frame)
1594 self.write(')')
1595
1596 def visit_MarkSafeIfAutoescape(self, node, frame):
1597 self.write('(context.eval_ctx.autoescape and Markup or identity)(')
1598 self.visit(node.expr, frame)
1599 self.write(')')
1600
1601 def visit_EnvironmentAttribute(self, node, frame):
1602 self.write('environment.' + node.name)
1603
1604 def visit_ExtensionAttribute(self, node, frame):
1605 self.write('environment.extensions[%r].%s' % (node.identifier, node.name ))
1606
1607 def visit_ImportedName(self, node, frame):
1608 self.write(self.import_aliases[node.importname])
1609
1610 def visit_InternalName(self, node, frame):
1611 self.write(node.name)
1612
1613 def visit_ContextReference(self, node, frame):
1614 self.write('context')
1615
1616 def visit_Continue(self, node, frame):
1617 self.writeline('continue', node)
1618
1619 def visit_Break(self, node, frame):
1620 self.writeline('break', node)
1621
1622 def visit_Scope(self, node, frame):
1623 scope_frame = frame.inner()
1624 scope_frame.inspect(node.iter_child_nodes())
1625 aliases = self.push_scope(scope_frame)
1626 self.pull_locals(scope_frame)
1627 self.blockvisit(node.body, scope_frame)
1628 self.pop_scope(aliases, scope_frame)
1629
1630 def visit_EvalContextModifier(self, node, frame):
1631 for keyword in node.options:
1632 self.writeline('context.eval_ctx.%s = ' % keyword.key)
1633 self.visit(keyword.value, frame)
1634 try:
1635 val = keyword.value.as_const(frame.eval_ctx)
1636 except nodes.Impossible:
1637 frame.eval_ctx.volatile = True
1638 else:
1639 setattr(frame.eval_ctx, keyword.key, val)
1640
1641 def visit_ScopedEvalContextModifier(self, node, frame):
1642 old_ctx_name = self.temporary_identifier()
1643 safed_ctx = frame.eval_ctx.save()
1644 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
1645 self.visit_EvalContextModifier(node, frame)
1646 for child in node.body:
1647 self.visit(child, frame)
1648 frame.eval_ctx.revert(safed_ctx)
1649 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)
OLDNEW
« no previous file with comments | « third_party/jinja2/bccache.py ('k') | third_party/jinja2/constants.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698