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