compiler.py (46530B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\jinja2\compiler.py 2 from cStringIO import StringIO 3 from itertools import chain 4 from copy import deepcopy 5 from jinja2 import nodes 6 from jinja2.nodes import EvalContext 7 from jinja2.visitor import NodeVisitor 8 from jinja2.exceptions import TemplateAssertionError 9 from jinja2.utils import Markup, concat, escape, is_python_keyword, next 10 operators = {'eq': '==', 11 'ne': '!=', 12 'gt': '>', 13 'gteq': '>=', 14 'lt': '<', 15 'lteq': '<=', 16 'in': 'in', 17 'notin': 'not in'} 18 try: 19 exec '(0 if 0 else 0)' 20 except SyntaxError: 21 have_condexpr = False 22 else: 23 have_condexpr = True 24 25 if hasattr(dict, 'iteritems'): 26 dict_item_iter = 'iteritems' 27 else: 28 dict_item_iter = 'items' 29 30 def unoptimize_before_dead_code(): 31 x = 42 32 33 def f(): 34 pass 35 36 return f 37 38 39 unoptimize_before_dead_code = bool(unoptimize_before_dead_code().func_closure) 40 41 def generate(node, environment, name, filename, stream = None, defer_init = False): 42 if not isinstance(node, nodes.Template): 43 raise TypeError("Can't compile non template nodes") 44 generator = CodeGenerator(environment, name, filename, stream, defer_init) 45 generator.visit(node) 46 if stream is None: 47 return generator.stream.getvalue() 48 49 50 def has_safe_repr(value): 51 if value is None or value is NotImplemented or value is Ellipsis: 52 return True 53 if isinstance(value, (bool, 54 int, 55 long, 56 float, 57 complex, 58 basestring, 59 xrange, 60 Markup)): 61 return True 62 if isinstance(value, (tuple, 63 list, 64 set, 65 frozenset)): 66 for item in value: 67 if not has_safe_repr(item): 68 return False 69 70 return True 71 if isinstance(value, dict): 72 for key, value in value.iteritems(): 73 if not has_safe_repr(key): 74 return False 75 if not has_safe_repr(value): 76 return False 77 78 return True 79 return False 80 81 82 def find_undeclared(nodes, names): 83 visitor = UndeclaredNameVisitor(names) 84 try: 85 for node in nodes: 86 visitor.visit(node) 87 88 except VisitorExit: 89 pass 90 91 return visitor.undeclared 92 93 94 class Identifiers(object): 95 96 def __init__(self): 97 self.declared = set() 98 self.outer_undeclared = set() 99 self.undeclared = set() 100 self.declared_locally = set() 101 self.declared_parameter = set() 102 103 def add_special(self, name): 104 self.undeclared.discard(name) 105 self.declared.add(name) 106 107 def is_declared(self, name): 108 if name in self.declared_locally or name in self.declared_parameter: 109 return True 110 return name in self.declared 111 112 def copy(self): 113 return deepcopy(self) 114 115 116 class Frame(object): 117 118 def __init__(self, eval_ctx, parent = None): 119 self.eval_ctx = eval_ctx 120 self.identifiers = Identifiers() 121 self.toplevel = False 122 self.rootlevel = False 123 self.require_output_check = parent and parent.require_output_check 124 self.buffer = None 125 self.block = parent and parent.block or None 126 self.assigned_names = set() 127 self.parent = parent 128 if parent is not None: 129 self.identifiers.declared.update(parent.identifiers.declared | parent.identifiers.declared_parameter | parent.assigned_names) 130 self.identifiers.outer_undeclared.update(parent.identifiers.undeclared - self.identifiers.declared) 131 self.buffer = parent.buffer 132 133 def copy(self): 134 rv = object.__new__(self.__class__) 135 rv.__dict__.update(self.__dict__) 136 rv.identifiers = object.__new__(self.identifiers.__class__) 137 rv.identifiers.__dict__.update(self.identifiers.__dict__) 138 return rv 139 140 def inspect(self, nodes): 141 visitor = FrameIdentifierVisitor(self.identifiers) 142 for node in nodes: 143 visitor.visit(node) 144 145 def find_shadowed(self, extra = ()): 146 i = self.identifiers 147 return (i.declared | i.outer_undeclared) & (i.declared_locally | i.declared_parameter) | set((x for x in extra if i.is_declared(x))) 148 149 def inner(self): 150 return Frame(self.eval_ctx, self) 151 152 def soft(self): 153 rv = self.copy() 154 rv.rootlevel = False 155 return rv 156 157 __copy__ = copy 158 159 160 class VisitorExit(RuntimeError): 161 pass 162 163 164 class DependencyFinderVisitor(NodeVisitor): 165 166 def __init__(self): 167 self.filters = set() 168 self.tests = set() 169 170 def visit_Filter(self, node): 171 self.generic_visit(node) 172 self.filters.add(node.name) 173 174 def visit_Test(self, node): 175 self.generic_visit(node) 176 self.tests.add(node.name) 177 178 def visit_Block(self, node): 179 pass 180 181 182 class UndeclaredNameVisitor(NodeVisitor): 183 184 def __init__(self, names): 185 self.names = set(names) 186 self.undeclared = set() 187 188 def visit_Name(self, node): 189 if node.ctx == 'load' and node.name in self.names: 190 self.undeclared.add(node.name) 191 if self.undeclared == self.names: 192 raise VisitorExit() 193 else: 194 self.names.discard(node.name) 195 196 def visit_Block(self, node): 197 pass 198 199 200 class FrameIdentifierVisitor(NodeVisitor): 201 202 def __init__(self, identifiers): 203 self.identifiers = identifiers 204 205 def visit_Name(self, node): 206 if node.ctx == 'store': 207 self.identifiers.declared_locally.add(node.name) 208 elif node.ctx == 'param': 209 self.identifiers.declared_parameter.add(node.name) 210 elif node.ctx == 'load' and not self.identifiers.is_declared(node.name): 211 self.identifiers.undeclared.add(node.name) 212 213 def visit_If(self, node): 214 self.visit(node.test) 215 real_identifiers = self.identifiers 216 old_names = real_identifiers.declared_locally | real_identifiers.declared_parameter 217 218 def inner_visit(nodes): 219 if not nodes: 220 return set() 221 self.identifiers = real_identifiers.copy() 222 for subnode in nodes: 223 self.visit(subnode) 224 225 rv = self.identifiers.declared_locally - old_names 226 real_identifiers.undeclared.update(self.identifiers.undeclared) 227 self.identifiers = real_identifiers 228 return rv 229 230 body = inner_visit(node.body) 231 else_ = inner_visit(node.else_ or ()) 232 real_identifiers.undeclared.update(body.symmetric_difference(else_) - real_identifiers.declared) 233 real_identifiers.declared_locally.update(body | else_) 234 235 def visit_Macro(self, node): 236 self.identifiers.declared_locally.add(node.name) 237 238 def visit_Import(self, node): 239 self.generic_visit(node) 240 self.identifiers.declared_locally.add(node.target) 241 242 def visit_FromImport(self, node): 243 self.generic_visit(node) 244 for name in node.names: 245 if isinstance(name, tuple): 246 self.identifiers.declared_locally.add(name[1]) 247 else: 248 self.identifiers.declared_locally.add(name) 249 250 def visit_Assign(self, node): 251 self.visit(node.node) 252 self.visit(node.target) 253 254 def visit_For(self, node): 255 self.visit(node.iter) 256 257 def visit_CallBlock(self, node): 258 self.visit(node.call) 259 260 def visit_FilterBlock(self, node): 261 self.visit(node.filter) 262 263 def visit_Scope(self, node): 264 pass 265 266 def visit_Block(self, node): 267 pass 268 269 270 class CompilerExit(Exception): 271 pass 272 273 274 class CodeGenerator(NodeVisitor): 275 276 def __init__(self, environment, name, filename, stream = None, defer_init = False): 277 if stream is None: 278 stream = StringIO() 279 self.environment = environment 280 self.name = name 281 self.filename = filename 282 self.stream = stream 283 self.created_block_context = False 284 self.defer_init = defer_init 285 self.import_aliases = {} 286 self.blocks = {} 287 self.extends_so_far = 0 288 self.has_known_extends = False 289 self.code_lineno = 1 290 self.tests = {} 291 self.filters = {} 292 self.debug_info = [] 293 self._write_debug_info = None 294 self._new_lines = 0 295 self._last_line = 0 296 self._first_write = True 297 self._last_identifier = 0 298 self._indentation = 0 299 300 def fail(self, msg, lineno): 301 raise TemplateAssertionError(msg, lineno, self.name, self.filename) 302 303 def temporary_identifier(self): 304 self._last_identifier += 1 305 return 't_%d' % self._last_identifier 306 307 def buffer(self, frame): 308 frame.buffer = self.temporary_identifier() 309 self.writeline('%s = []' % frame.buffer) 310 311 def return_buffer_contents(self, frame): 312 if frame.eval_ctx.volatile: 313 self.writeline('if context.eval_ctx.autoescape:') 314 self.indent() 315 self.writeline('return Markup(concat(%s))' % frame.buffer) 316 self.outdent() 317 self.writeline('else:') 318 self.indent() 319 self.writeline('return concat(%s)' % frame.buffer) 320 self.outdent() 321 elif frame.eval_ctx.autoescape: 322 self.writeline('return Markup(concat(%s))' % frame.buffer) 323 else: 324 self.writeline('return concat(%s)' % frame.buffer) 325 326 def indent(self): 327 self._indentation += 1 328 329 def outdent(self, step = 1): 330 self._indentation -= step 331 332 def start_write(self, frame, node = None): 333 if frame.buffer is None: 334 self.writeline('yield ', node) 335 else: 336 self.writeline('%s.append(' % frame.buffer, node) 337 338 def end_write(self, frame): 339 if frame.buffer is not None: 340 self.write(')') 341 342 def simple_write(self, s, frame, node = None): 343 self.start_write(frame, node) 344 self.write(s) 345 self.end_write(frame) 346 347 def blockvisit(self, nodes, frame): 348 if frame.buffer is None: 349 self.writeline('if 0: yield None') 350 else: 351 self.writeline('pass') 352 try: 353 for node in nodes: 354 self.visit(node, frame) 355 356 except CompilerExit: 357 pass 358 359 def write(self, x): 360 if self._new_lines: 361 if not self._first_write: 362 self.stream.write('\n' * self._new_lines) 363 self.code_lineno += self._new_lines 364 if self._write_debug_info is not None: 365 self.debug_info.append((self._write_debug_info, self.code_lineno)) 366 self._write_debug_info = None 367 self._first_write = False 368 self.stream.write(' ' * self._indentation) 369 self._new_lines = 0 370 self.stream.write(x) 371 372 def writeline(self, x, node = None, extra = 0): 373 self.newline(node, extra) 374 self.write(x) 375 376 def newline(self, node = None, extra = 0): 377 self._new_lines = max(self._new_lines, 1 + extra) 378 if node is not None and node.lineno != self._last_line: 379 self._write_debug_info = node.lineno 380 self._last_line = node.lineno 381 382 def signature(self, node, frame, extra_kwargs = None): 383 kwarg_workaround = False 384 for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()): 385 if is_python_keyword(kwarg): 386 kwarg_workaround = True 387 break 388 389 for arg in node.args: 390 self.write(', ') 391 self.visit(arg, frame) 392 393 if not kwarg_workaround: 394 for kwarg in node.kwargs: 395 self.write(', ') 396 self.visit(kwarg, frame) 397 398 if extra_kwargs is not None: 399 for key, value in extra_kwargs.iteritems(): 400 self.write(', %s=%s' % (key, value)) 401 402 if node.dyn_args: 403 self.write(', *') 404 self.visit(node.dyn_args, frame) 405 if kwarg_workaround: 406 if node.dyn_kwargs is not None: 407 self.write(', **dict({') 408 else: 409 self.write(', **{') 410 for kwarg in node.kwargs: 411 self.write('%r: ' % kwarg.key) 412 self.visit(kwarg.value, frame) 413 self.write(', ') 414 415 if extra_kwargs is not None: 416 for key, value in extra_kwargs.iteritems(): 417 self.write('%r: %s, ' % (key, value)) 418 419 if node.dyn_kwargs is not None: 420 self.write('}, **') 421 self.visit(node.dyn_kwargs, frame) 422 self.write(')') 423 else: 424 self.write('}') 425 elif node.dyn_kwargs is not None: 426 self.write(', **') 427 self.visit(node.dyn_kwargs, frame) 428 429 def pull_locals(self, frame): 430 for name in frame.identifiers.undeclared: 431 self.writeline('l_%s = context.resolve(%r)' % (name, name)) 432 433 def pull_dependencies(self, nodes): 434 visitor = DependencyFinderVisitor() 435 for node in nodes: 436 visitor.visit(node) 437 438 for dependency in ('filters', 'tests'): 439 mapping = getattr(self, dependency) 440 for name in getattr(visitor, dependency): 441 if name not in mapping: 442 mapping[name] = self.temporary_identifier() 443 self.writeline('%s = environment.%s[%r]' % (mapping[name], dependency, name)) 444 445 def unoptimize_scope(self, frame): 446 if frame.identifiers.declared: 447 self.writeline('%sdummy(%s)' % (unoptimize_before_dead_code and 'if 0: ' or '', ', '.join(('l_' + name for name in frame.identifiers.declared)))) 448 449 def push_scope(self, frame, extra_vars = ()): 450 aliases = {} 451 for name in frame.find_shadowed(extra_vars): 452 aliases[name] = ident = self.temporary_identifier() 453 self.writeline('%s = l_%s' % (ident, name)) 454 455 to_declare = set() 456 for name in frame.identifiers.declared_locally: 457 if name not in aliases: 458 to_declare.add('l_' + name) 459 460 if to_declare: 461 self.writeline(' = '.join(to_declare) + ' = missing') 462 return aliases 463 464 def pop_scope(self, aliases, frame): 465 for name, alias in aliases.iteritems(): 466 self.writeline('l_%s = %s' % (name, alias)) 467 468 to_delete = set() 469 for name in frame.identifiers.declared_locally: 470 if name not in aliases: 471 to_delete.add('l_' + name) 472 473 if to_delete: 474 self.writeline(' = '.join(to_delete) + ' = missing') 475 476 def function_scoping(self, node, frame, children = None, find_special = True): 477 if children is None: 478 children = node.iter_child_nodes() 479 children = list(children) 480 func_frame = frame.inner() 481 func_frame.inspect(children) 482 overriden_closure_vars = func_frame.identifiers.undeclared & func_frame.identifiers.declared & (func_frame.identifiers.declared_locally | func_frame.identifiers.declared_parameter) 483 if overriden_closure_vars: 484 self.fail("It's not possible to set and access variables derived from an outer scope! (affects: %s)" % ', '.join(sorted(overriden_closure_vars)), node.lineno) 485 func_frame.identifiers.undeclared -= func_frame.identifiers.undeclared & func_frame.identifiers.declared 486 if not find_special: 487 return func_frame 488 func_frame.accesses_kwargs = False 489 func_frame.accesses_varargs = False 490 func_frame.accesses_caller = False 491 func_frame.arguments = args = [ 'l_' + x.name for x in node.args ] 492 undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs')) 493 if 'caller' in undeclared: 494 func_frame.accesses_caller = True 495 func_frame.identifiers.add_special('caller') 496 args.append('l_caller') 497 if 'kwargs' in undeclared: 498 func_frame.accesses_kwargs = True 499 func_frame.identifiers.add_special('kwargs') 500 args.append('l_kwargs') 501 if 'varargs' in undeclared: 502 func_frame.accesses_varargs = True 503 func_frame.identifiers.add_special('varargs') 504 args.append('l_varargs') 505 return func_frame 506 507 def macro_body(self, node, frame, children = None): 508 frame = self.function_scoping(node, frame, children) 509 frame.require_output_check = False 510 args = frame.arguments 511 if 'loop' in frame.identifiers.declared: 512 args = args + ['l_loop=l_loop'] 513 self.writeline('def macro(%s):' % ', '.join(args), node) 514 self.indent() 515 self.buffer(frame) 516 self.pull_locals(frame) 517 self.blockvisit(node.body, frame) 518 self.return_buffer_contents(frame) 519 self.outdent() 520 return frame 521 522 def macro_def(self, node, frame): 523 arg_tuple = ', '.join((repr(x.name) for x in node.args)) 524 name = getattr(node, 'name', None) 525 if len(node.args) == 1: 526 arg_tuple += ',' 527 self.write('Macro(environment, macro, %r, (%s), (' % (name, arg_tuple)) 528 for arg in node.defaults: 529 self.visit(arg, frame) 530 self.write(', ') 531 532 self.write('), %r, %r, %r)' % (bool(frame.accesses_kwargs), bool(frame.accesses_varargs), bool(frame.accesses_caller))) 533 534 def position(self, node): 535 rv = 'line %d' % node.lineno 536 if self.name is not None: 537 rv += ' in ' + repr(self.name) 538 return rv 539 540 def visit_Template(self, node, frame = None): 541 eval_ctx = EvalContext(self.environment, self.name) 542 from jinja2.runtime import __all__ as exported 543 self.writeline('from __future__ import division') 544 self.writeline('from jinja2.runtime import ' + ', '.join(exported)) 545 if not unoptimize_before_dead_code: 546 self.writeline('dummy = lambda *x: None') 547 envenv = not self.defer_init and ', environment=environment' or '' 548 have_extends = node.find(nodes.Extends) is not None 549 for block in node.find_all(nodes.Block): 550 if block.name in self.blocks: 551 self.fail('block %r defined twice' % block.name, block.lineno) 552 self.blocks[block.name] = block 553 554 for import_ in node.find_all(nodes.ImportedName): 555 if import_.importname not in self.import_aliases: 556 imp = import_.importname 557 self.import_aliases[imp] = alias = self.temporary_identifier() 558 if '.' in imp: 559 module, obj = imp.rsplit('.', 1) 560 self.writeline('from %s import %s as %s' % (module, obj, alias)) 561 else: 562 self.writeline('import %s as %s' % (imp, alias)) 563 564 self.writeline('name = %r' % self.name) 565 self.writeline('def root(context%s):' % envenv, extra=1) 566 frame = Frame(eval_ctx) 567 frame.inspect(node.body) 568 frame.toplevel = frame.rootlevel = True 569 frame.require_output_check = have_extends and not self.has_known_extends 570 self.indent() 571 if have_extends: 572 self.writeline('parent_template = None') 573 if 'self' in find_undeclared(node.body, ('self',)): 574 frame.identifiers.add_special('self') 575 self.writeline('l_self = TemplateReference(context)') 576 self.pull_locals(frame) 577 self.pull_dependencies(node.body) 578 self.blockvisit(node.body, frame) 579 self.outdent() 580 if have_extends: 581 if not self.has_known_extends: 582 self.indent() 583 self.writeline('if parent_template is not None:') 584 self.indent() 585 self.writeline('for event in parent_template.root_render_func(context):') 586 self.indent() 587 self.writeline('yield event') 588 self.outdent(2 + (not self.has_known_extends)) 589 for name, block in self.blocks.iteritems(): 590 block_frame = Frame(eval_ctx) 591 block_frame.inspect(block.body) 592 block_frame.block = name 593 self.writeline('def block_%s(context%s):' % (name, envenv), block, 1) 594 self.indent() 595 undeclared = find_undeclared(block.body, ('self', 'super')) 596 if 'self' in undeclared: 597 block_frame.identifiers.add_special('self') 598 self.writeline('l_self = TemplateReference(context)') 599 if 'super' in undeclared: 600 block_frame.identifiers.add_special('super') 601 self.writeline('l_super = context.super(%r, block_%s)' % (name, name)) 602 self.pull_locals(block_frame) 603 self.pull_dependencies(block.body) 604 self.blockvisit(block.body, block_frame) 605 self.outdent() 606 607 self.writeline('blocks = {%s}' % ', '.join(('%r: block_%s' % (x, x) for x in self.blocks)), extra=1) 608 self.writeline('debug_info = %r' % '&'.join(('%s=%s' % x for x in self.debug_info))) 609 610 def visit_Block(self, node, frame): 611 level = 1 612 if frame.toplevel: 613 if self.has_known_extends: 614 return 615 if self.extends_so_far > 0: 616 self.writeline('if parent_template is None:') 617 self.indent() 618 level += 1 619 context = node.scoped and 'context.derived(locals())' or 'context' 620 self.writeline('for event in context.blocks[%r][0](%s):' % (node.name, context), node) 621 self.indent() 622 self.simple_write('event', frame) 623 self.outdent(level) 624 625 def visit_Extends(self, node, frame): 626 if not frame.toplevel: 627 self.fail('cannot use extend from a non top-level scope', node.lineno) 628 if self.extends_so_far > 0: 629 if not self.has_known_extends: 630 self.writeline('if parent_template is not None:') 631 self.indent() 632 self.writeline('raise TemplateRuntimeError(%r)' % 'extended multiple times') 633 self.outdent() 634 if self.has_known_extends: 635 raise CompilerExit() 636 self.writeline('parent_template = environment.get_template(', node) 637 self.visit(node.template, frame) 638 self.write(', %r)' % self.name) 639 self.writeline('for name, parent_block in parent_template.blocks.%s():' % dict_item_iter) 640 self.indent() 641 self.writeline('context.blocks.setdefault(name, []).append(parent_block)') 642 self.outdent() 643 if frame.rootlevel: 644 self.has_known_extends = True 645 self.extends_so_far += 1 646 647 def visit_Include(self, node, frame): 648 if node.with_context: 649 self.unoptimize_scope(frame) 650 if node.ignore_missing: 651 self.writeline('try:') 652 self.indent() 653 func_name = 'get_or_select_template' 654 if isinstance(node.template, nodes.Const): 655 if isinstance(node.template.value, basestring): 656 func_name = 'get_template' 657 elif isinstance(node.template.value, (tuple, list)): 658 func_name = 'select_template' 659 elif isinstance(node.template, (nodes.Tuple, nodes.List)): 660 func_name = 'select_template' 661 self.writeline('template = environment.%s(' % func_name, node) 662 self.visit(node.template, frame) 663 self.write(', %r)' % self.name) 664 if node.ignore_missing: 665 self.outdent() 666 self.writeline('except TemplateNotFound:') 667 self.indent() 668 self.writeline('pass') 669 self.outdent() 670 self.writeline('else:') 671 self.indent() 672 if node.with_context: 673 self.writeline('for event in template.root_render_func(template.new_context(context.parent, True, locals())):') 674 else: 675 self.writeline('for event in template.module._body_stream:') 676 self.indent() 677 self.simple_write('event', frame) 678 self.outdent() 679 if node.ignore_missing: 680 self.outdent() 681 682 def visit_Import(self, node, frame): 683 if node.with_context: 684 self.unoptimize_scope(frame) 685 self.writeline('l_%s = ' % node.target, node) 686 if frame.toplevel: 687 self.write('context.vars[%r] = ' % node.target) 688 self.write('environment.get_template(') 689 self.visit(node.template, frame) 690 self.write(', %r).' % self.name) 691 if node.with_context: 692 self.write('make_module(context.parent, True, locals())') 693 else: 694 self.write('module') 695 if frame.toplevel and not node.target.startswith('_'): 696 self.writeline('context.exported_vars.discard(%r)' % node.target) 697 frame.assigned_names.add(node.target) 698 699 def visit_FromImport(self, node, frame): 700 self.newline(node) 701 self.write('included_template = environment.get_template(') 702 self.visit(node.template, frame) 703 self.write(', %r).' % self.name) 704 if node.with_context: 705 self.write('make_module(context.parent, True)') 706 else: 707 self.write('module') 708 var_names = [] 709 discarded_names = [] 710 for name in node.names: 711 if isinstance(name, tuple): 712 name, alias = name 713 else: 714 alias = name 715 self.writeline('l_%s = getattr(included_template, %r, missing)' % (alias, name)) 716 self.writeline('if l_%s is missing:' % alias) 717 self.indent() 718 self.writeline('l_%s = environment.undefined(%r %% included_template.__name__, name=%r)' % (alias, 'the template %%r (imported on %s) does not export the requested name %s' % (self.position(node), repr(name)), name)) 719 self.outdent() 720 if frame.toplevel: 721 var_names.append(alias) 722 if not alias.startswith('_'): 723 discarded_names.append(alias) 724 frame.assigned_names.add(alias) 725 726 if var_names: 727 if len(var_names) == 1: 728 name = var_names[0] 729 self.writeline('context.vars[%r] = l_%s' % (name, name)) 730 else: 731 self.writeline('context.vars.update({%s})' % ', '.join(('%r: l_%s' % (name, name) for name in var_names))) 732 if discarded_names: 733 if len(discarded_names) == 1: 734 self.writeline('context.exported_vars.discard(%r)' % discarded_names[0]) 735 else: 736 self.writeline('context.exported_vars.difference_update((%s))' % ', '.join(map(repr, discarded_names))) 737 738 def visit_For(self, node, frame): 739 children = node.iter_child_nodes(exclude=('iter',)) 740 if node.recursive: 741 loop_frame = self.function_scoping(node, frame, children, find_special=False) 742 else: 743 loop_frame = frame.inner() 744 loop_frame.inspect(children) 745 extended_loop = node.recursive or 'loop' in find_undeclared(node.iter_child_nodes(only=('body',)), ('loop',)) 746 if not node.recursive: 747 aliases = self.push_scope(loop_frame, ('loop',)) 748 else: 749 self.writeline('def loop(reciter, loop_render_func):', node) 750 self.indent() 751 self.buffer(loop_frame) 752 aliases = {} 753 if extended_loop: 754 loop_frame.identifiers.add_special('loop') 755 for name in node.find_all(nodes.Name): 756 if name.ctx == 'store' and name.name == 'loop': 757 self.fail("Can't assign to special loop variable in for-loop target", name.lineno) 758 759 self.pull_locals(loop_frame) 760 if node.else_: 761 iteration_indicator = self.temporary_identifier() 762 self.writeline('%s = 1' % iteration_indicator) 763 if 'loop' not in aliases and 'loop' in find_undeclared(node.iter_child_nodes(only=('else_', 'test')), ('loop',)): 764 self.writeline("l_loop = environment.undefined(%r, name='loop')" % ("'loop' is undefined. the filter section of a loop as well as the else block don't have access to the special 'loop' variable of the current loop. Because there is no parent loop it's undefined. Happened in loop on %s" % self.position(node))) 765 self.writeline('for ', node) 766 self.visit(node.target, loop_frame) 767 self.write(extended_loop and ', l_loop in LoopContext(' or ' in ') 768 if extended_loop and node.test is not None: 769 self.write('(') 770 self.visit(node.target, loop_frame) 771 self.write(' for ') 772 self.visit(node.target, loop_frame) 773 self.write(' in ') 774 if node.recursive: 775 self.write('reciter') 776 else: 777 self.visit(node.iter, loop_frame) 778 self.write(' if (') 779 test_frame = loop_frame.copy() 780 self.visit(node.test, test_frame) 781 self.write('))') 782 elif node.recursive: 783 self.write('reciter') 784 else: 785 self.visit(node.iter, loop_frame) 786 if node.recursive: 787 self.write(', recurse=loop_render_func):') 788 else: 789 self.write(extended_loop and '):' or ':') 790 if not extended_loop and node.test is not None: 791 self.indent() 792 self.writeline('if not ') 793 self.visit(node.test, loop_frame) 794 self.write(':') 795 self.indent() 796 self.writeline('continue') 797 self.outdent(2) 798 self.indent() 799 self.blockvisit(node.body, loop_frame) 800 if node.else_: 801 self.writeline('%s = 0' % iteration_indicator) 802 self.outdent() 803 if node.else_: 804 self.writeline('if %s:' % iteration_indicator) 805 self.indent() 806 self.blockvisit(node.else_, loop_frame) 807 self.outdent() 808 if not node.recursive: 809 self.pop_scope(aliases, loop_frame) 810 if node.recursive: 811 self.return_buffer_contents(loop_frame) 812 self.outdent() 813 self.start_write(frame, node) 814 self.write('loop(') 815 self.visit(node.iter, frame) 816 self.write(', loop)') 817 self.end_write(frame) 818 819 def visit_If(self, node, frame): 820 if_frame = frame.soft() 821 self.writeline('if ', node) 822 self.visit(node.test, if_frame) 823 self.write(':') 824 self.indent() 825 self.blockvisit(node.body, if_frame) 826 self.outdent() 827 if node.else_: 828 self.writeline('else:') 829 self.indent() 830 self.blockvisit(node.else_, if_frame) 831 self.outdent() 832 833 def visit_Macro(self, node, frame): 834 macro_frame = self.macro_body(node, frame) 835 self.newline() 836 if frame.toplevel: 837 if not node.name.startswith('_'): 838 self.write('context.exported_vars.add(%r)' % node.name) 839 self.writeline('context.vars[%r] = ' % node.name) 840 self.write('l_%s = ' % node.name) 841 self.macro_def(node, macro_frame) 842 frame.assigned_names.add(node.name) 843 844 def visit_CallBlock(self, node, frame): 845 children = node.iter_child_nodes(exclude=('call',)) 846 call_frame = self.macro_body(node, frame, children) 847 self.writeline('caller = ') 848 self.macro_def(node, call_frame) 849 self.start_write(frame, node) 850 self.visit_Call(node.call, call_frame, forward_caller=True) 851 self.end_write(frame) 852 853 def visit_FilterBlock(self, node, frame): 854 filter_frame = frame.inner() 855 filter_frame.inspect(node.iter_child_nodes()) 856 aliases = self.push_scope(filter_frame) 857 self.pull_locals(filter_frame) 858 self.buffer(filter_frame) 859 self.blockvisit(node.body, filter_frame) 860 self.start_write(frame, node) 861 self.visit_Filter(node.filter, filter_frame) 862 self.end_write(frame) 863 self.pop_scope(aliases, filter_frame) 864 865 def visit_ExprStmt(self, node, frame): 866 self.newline(node) 867 self.visit(node.node, frame) 868 869 def visit_Output(self, node, frame): 870 if self.has_known_extends and frame.require_output_check: 871 return 872 if self.environment.finalize: 873 finalize = lambda x: unicode(self.environment.finalize(x)) 874 else: 875 finalize = unicode 876 outdent_later = False 877 if frame.require_output_check: 878 self.writeline('if parent_template is None:') 879 self.indent() 880 outdent_later = True 881 body = [] 882 for child in node.nodes: 883 try: 884 const = child.as_const(frame.eval_ctx) 885 except nodes.Impossible: 886 body.append(child) 887 continue 888 889 try: 890 if frame.eval_ctx.autoescape: 891 if hasattr(const, '__html__'): 892 const = const.__html__() 893 else: 894 const = escape(const) 895 const = finalize(const) 896 except Exception: 897 body.append(child) 898 continue 899 900 if body and isinstance(body[-1], list): 901 body[-1].append(const) 902 else: 903 body.append([const]) 904 905 if len(body) < 3 or frame.buffer is not None: 906 if frame.buffer is not None: 907 if len(body) == 1: 908 self.writeline('%s.append(' % frame.buffer) 909 else: 910 self.writeline('%s.extend((' % frame.buffer) 911 self.indent() 912 for item in body: 913 if isinstance(item, list): 914 val = repr(concat(item)) 915 if frame.buffer is None: 916 self.writeline('yield ' + val) 917 else: 918 self.writeline(val + ', ') 919 else: 920 if frame.buffer is None: 921 self.writeline('yield ', item) 922 else: 923 self.newline(item) 924 close = 1 925 if frame.eval_ctx.volatile: 926 self.write('(context.eval_ctx.autoescape and escape or to_string)(') 927 elif frame.eval_ctx.autoescape: 928 self.write('escape(') 929 else: 930 self.write('to_string(') 931 if self.environment.finalize is not None: 932 self.write('environment.finalize(') 933 close += 1 934 self.visit(item, frame) 935 self.write(')' * close) 936 if frame.buffer is not None: 937 self.write(', ') 938 939 if frame.buffer is not None: 940 self.outdent() 941 self.writeline(len(body) == 1 and ')' or '))') 942 else: 943 format = [] 944 arguments = [] 945 for item in body: 946 if isinstance(item, list): 947 format.append(concat(item).replace('%', '%%')) 948 else: 949 format.append('%s') 950 arguments.append(item) 951 952 self.writeline('yield ') 953 self.write(repr(concat(format)) + ' % (') 954 idx = -1 955 self.indent() 956 for argument in arguments: 957 self.newline(argument) 958 close = 0 959 if frame.eval_ctx.volatile: 960 self.write('(context.eval_ctx.autoescape and escape or to_string)(') 961 close += 1 962 elif frame.eval_ctx.autoescape: 963 self.write('escape(') 964 close += 1 965 if self.environment.finalize is not None: 966 self.write('environment.finalize(') 967 close += 1 968 self.visit(argument, frame) 969 self.write(')' * close + ', ') 970 971 self.outdent() 972 self.writeline(')') 973 if outdent_later: 974 self.outdent() 975 976 def visit_Assign(self, node, frame): 977 self.newline(node) 978 if frame.toplevel: 979 assignment_frame = frame.copy() 980 assignment_frame.toplevel_assignments = set() 981 else: 982 assignment_frame = frame 983 self.visit(node.target, assignment_frame) 984 self.write(' = ') 985 self.visit(node.node, frame) 986 if frame.toplevel: 987 public_names = [ x for x in assignment_frame.toplevel_assignments if not x.startswith('_') ] 988 if len(assignment_frame.toplevel_assignments) == 1: 989 name = next(iter(assignment_frame.toplevel_assignments)) 990 self.writeline('context.vars[%r] = l_%s' % (name, name)) 991 else: 992 self.writeline('context.vars.update({') 993 for idx, name in enumerate(assignment_frame.toplevel_assignments): 994 if idx: 995 self.write(', ') 996 self.write('%r: l_%s' % (name, name)) 997 998 self.write('})') 999 if public_names: 1000 if len(public_names) == 1: 1001 self.writeline('context.exported_vars.add(%r)' % public_names[0]) 1002 else: 1003 self.writeline('context.exported_vars.update((%s))' % ', '.join(map(repr, public_names))) 1004 1005 def visit_Name(self, node, frame): 1006 if node.ctx == 'store' and frame.toplevel: 1007 frame.toplevel_assignments.add(node.name) 1008 self.write('l_' + node.name) 1009 frame.assigned_names.add(node.name) 1010 1011 def visit_Const(self, node, frame): 1012 val = node.value 1013 if isinstance(val, float): 1014 self.write(str(val)) 1015 else: 1016 self.write(repr(val)) 1017 1018 def visit_TemplateData(self, node, frame): 1019 try: 1020 self.write(repr(node.as_const(frame.eval_ctx))) 1021 except nodes.Impossible: 1022 self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)' % node.data) 1023 1024 def visit_Tuple(self, node, frame): 1025 self.write('(') 1026 idx = -1 1027 for idx, item in enumerate(node.items): 1028 if idx: 1029 self.write(', ') 1030 self.visit(item, frame) 1031 1032 self.write(idx == 0 and ',)' or ')') 1033 1034 def visit_List(self, node, frame): 1035 self.write('[') 1036 for idx, item in enumerate(node.items): 1037 if idx: 1038 self.write(', ') 1039 self.visit(item, frame) 1040 1041 self.write(']') 1042 1043 def visit_Dict(self, node, frame): 1044 self.write('{') 1045 for idx, item in enumerate(node.items): 1046 if idx: 1047 self.write(', ') 1048 self.visit(item.key, frame) 1049 self.write(': ') 1050 self.visit(item.value, frame) 1051 1052 self.write('}') 1053 1054 def binop(operator, interceptable = True): 1055 1056 def visitor(self, node, frame): 1057 if self.environment.sandboxed and operator in self.environment.intercepted_binops: 1058 self.write('environment.call_binop(context, %r, ' % operator) 1059 self.visit(node.left, frame) 1060 self.write(', ') 1061 self.visit(node.right, frame) 1062 else: 1063 self.write('(') 1064 self.visit(node.left, frame) 1065 self.write(' %s ' % operator) 1066 self.visit(node.right, frame) 1067 self.write(')') 1068 1069 return visitor 1070 1071 def uaop(operator, interceptable = True): 1072 1073 def visitor(self, node, frame): 1074 if self.environment.sandboxed and operator in self.environment.intercepted_unops: 1075 self.write('environment.call_unop(context, %r, ' % operator) 1076 self.visit(node.node, frame) 1077 else: 1078 self.write('(' + operator) 1079 self.visit(node.node, frame) 1080 self.write(')') 1081 1082 return visitor 1083 1084 visit_Add = binop('+') 1085 visit_Sub = binop('-') 1086 visit_Mul = binop('*') 1087 visit_Div = binop('/') 1088 visit_FloorDiv = binop('//') 1089 visit_Pow = binop('**') 1090 visit_Mod = binop('%') 1091 visit_And = binop('and', interceptable=False) 1092 visit_Or = binop('or', interceptable=False) 1093 visit_Pos = uaop('+') 1094 visit_Neg = uaop('-') 1095 visit_Not = uaop('not ', interceptable=False) 1096 del binop 1097 del uaop 1098 1099 def visit_Concat(self, node, frame): 1100 if frame.eval_ctx.volatile: 1101 func_name = '(context.eval_ctx.volatile and markup_join or unicode_join)' 1102 elif frame.eval_ctx.autoescape: 1103 func_name = 'markup_join' 1104 else: 1105 func_name = 'unicode_join' 1106 self.write('%s((' % func_name) 1107 for arg in node.nodes: 1108 self.visit(arg, frame) 1109 self.write(', ') 1110 1111 self.write('))') 1112 1113 def visit_Compare(self, node, frame): 1114 self.visit(node.expr, frame) 1115 for op in node.ops: 1116 self.visit(op, frame) 1117 1118 def visit_Operand(self, node, frame): 1119 self.write(' %s ' % operators[node.op]) 1120 self.visit(node.expr, frame) 1121 1122 def visit_Getattr(self, node, frame): 1123 self.write('environment.getattr(') 1124 self.visit(node.node, frame) 1125 self.write(', %r)' % node.attr) 1126 1127 def visit_Getitem(self, node, frame): 1128 if isinstance(node.arg, nodes.Slice): 1129 self.visit(node.node, frame) 1130 self.write('[') 1131 self.visit(node.arg, frame) 1132 self.write(']') 1133 else: 1134 self.write('environment.getitem(') 1135 self.visit(node.node, frame) 1136 self.write(', ') 1137 self.visit(node.arg, frame) 1138 self.write(')') 1139 1140 def visit_Slice(self, node, frame): 1141 if node.start is not None: 1142 self.visit(node.start, frame) 1143 self.write(':') 1144 if node.stop is not None: 1145 self.visit(node.stop, frame) 1146 if node.step is not None: 1147 self.write(':') 1148 self.visit(node.step, frame) 1149 1150 def visit_Filter(self, node, frame): 1151 self.write(self.filters[node.name] + '(') 1152 func = self.environment.filters.get(node.name) 1153 if func is None: 1154 self.fail('no filter named %r' % node.name, node.lineno) 1155 if getattr(func, 'contextfilter', False): 1156 self.write('context, ') 1157 elif getattr(func, 'evalcontextfilter', False): 1158 self.write('context.eval_ctx, ') 1159 elif getattr(func, 'environmentfilter', False): 1160 self.write('environment, ') 1161 if node.node is not None: 1162 self.visit(node.node, frame) 1163 elif frame.eval_ctx.volatile: 1164 self.write('(context.eval_ctx.autoescape and Markup(concat(%s)) or concat(%s))' % (frame.buffer, frame.buffer)) 1165 elif frame.eval_ctx.autoescape: 1166 self.write('Markup(concat(%s))' % frame.buffer) 1167 else: 1168 self.write('concat(%s)' % frame.buffer) 1169 self.signature(node, frame) 1170 self.write(')') 1171 1172 def visit_Test(self, node, frame): 1173 self.write(self.tests[node.name] + '(') 1174 if node.name not in self.environment.tests: 1175 self.fail('no test named %r' % node.name, node.lineno) 1176 self.visit(node.node, frame) 1177 self.signature(node, frame) 1178 self.write(')') 1179 1180 def visit_CondExpr(self, node, frame): 1181 1182 def write_expr2(): 1183 if node.expr2 is not None: 1184 return self.visit(node.expr2, frame) 1185 self.write('environment.undefined(%r)' % ('the inline if-expression on %s evaluated to false and no else section was defined.' % self.position(node))) 1186 1187 if not have_condexpr: 1188 self.write('((') 1189 self.visit(node.test, frame) 1190 self.write(') and (') 1191 self.visit(node.expr1, frame) 1192 self.write(',) or (') 1193 write_expr2() 1194 self.write(',))[0]') 1195 else: 1196 self.write('(') 1197 self.visit(node.expr1, frame) 1198 self.write(' if ') 1199 self.visit(node.test, frame) 1200 self.write(' else ') 1201 write_expr2() 1202 self.write(')') 1203 1204 def visit_Call(self, node, frame, forward_caller = False): 1205 if self.environment.sandboxed: 1206 self.write('environment.call(context, ') 1207 else: 1208 self.write('context.call(') 1209 self.visit(node.node, frame) 1210 extra_kwargs = forward_caller and {'caller': 'caller'} or None 1211 self.signature(node, frame, extra_kwargs) 1212 self.write(')') 1213 1214 def visit_Keyword(self, node, frame): 1215 self.write(node.key + '=') 1216 self.visit(node.value, frame) 1217 1218 def visit_MarkSafe(self, node, frame): 1219 self.write('Markup(') 1220 self.visit(node.expr, frame) 1221 self.write(')') 1222 1223 def visit_MarkSafeIfAutoescape(self, node, frame): 1224 self.write('(context.eval_ctx.autoescape and Markup or identity)(') 1225 self.visit(node.expr, frame) 1226 self.write(')') 1227 1228 def visit_EnvironmentAttribute(self, node, frame): 1229 self.write('environment.' + node.name) 1230 1231 def visit_ExtensionAttribute(self, node, frame): 1232 self.write('environment.extensions[%r].%s' % (node.identifier, node.name)) 1233 1234 def visit_ImportedName(self, node, frame): 1235 self.write(self.import_aliases[node.importname]) 1236 1237 def visit_InternalName(self, node, frame): 1238 self.write(node.name) 1239 1240 def visit_ContextReference(self, node, frame): 1241 self.write('context') 1242 1243 def visit_Continue(self, node, frame): 1244 self.writeline('continue', node) 1245 1246 def visit_Break(self, node, frame): 1247 self.writeline('break', node) 1248 1249 def visit_Scope(self, node, frame): 1250 scope_frame = frame.inner() 1251 scope_frame.inspect(node.iter_child_nodes()) 1252 aliases = self.push_scope(scope_frame) 1253 self.pull_locals(scope_frame) 1254 self.blockvisit(node.body, scope_frame) 1255 self.pop_scope(aliases, scope_frame) 1256 1257 def visit_EvalContextModifier(self, node, frame): 1258 for keyword in node.options: 1259 self.writeline('context.eval_ctx.%s = ' % keyword.key) 1260 self.visit(keyword.value, frame) 1261 try: 1262 val = keyword.value.as_const(frame.eval_ctx) 1263 except nodes.Impossible: 1264 frame.eval_ctx.volatile = True 1265 else: 1266 setattr(frame.eval_ctx, keyword.key, val) 1267 1268 def visit_ScopedEvalContextModifier(self, node, frame): 1269 old_ctx_name = self.temporary_identifier() 1270 safed_ctx = frame.eval_ctx.save() 1271 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name) 1272 self.visit_EvalContextModifier(node, frame) 1273 for child in node.body: 1274 self.visit(child, frame) 1275 1276 frame.eval_ctx.revert(safed_ctx) 1277 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)