1 #!/usr/bin/env python 2 3 """ 4 Simplify AST structures for easier type propagation and analysis. The code in 5 this module processes AST trees originating from the compiler module and 6 produces a result tree consisting of instruction-oriented program nodes. 7 8 Some of the simplified nodes will be altered by the fixnames module, principally 9 LoadName and StoreName nodes which, in the case of globals and builtins, will be 10 changed to LoadAttr and StoreAttr respectively. 11 12 -------- 13 14 Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk> 15 16 This program is free software; you can redistribute it and/or modify it under 17 the terms of the GNU General Public License as published by the Free Software 18 Foundation; either version 3 of the License, or (at your option) any later 19 version. 20 21 This program is distributed in the hope that it will be useful, but WITHOUT 22 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 23 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 24 details. 25 26 You should have received a copy of the GNU General Public License along with 27 this program. If not, see <http://www.gnu.org/licenses/>. 28 29 -------- 30 31 To use this module, the easiest approach is to use the simplify function: 32 33 simplify(filename) 34 35 The more complicated approach involves first instantiating a Simplifier object: 36 37 simplifier = Simplifier() 38 39 Then, applying the simplifier to an AST tree: 40 41 module = compiler.parseFile(filename) 42 simplifier.process(module) 43 """ 44 45 from simplify.simplified import * 46 import compiler.ast 47 import os 48 49 class Simplifier(Visitor): 50 51 """ 52 A simplifying visitor for AST nodes. 53 54 Covered: Add, And, Assert, AssAttr, AssList, AssName, AssTuple, Assign, 55 AugAssign, Bitand, Break, CallFunc, Class, Compare, Const, 56 Continue, Dict, Discard, Div, FloorDiv, For, From, Function, 57 Getattr, Global, If, Import, Invert, Keyword, Lambda, List, 58 ListComp, ListCompFor, ListCompIf, Mod, Module, Mul, Name, Not, Or, 59 Pass, Power, Print, Printnl, Raise, Return, Slice, Sliceobj, Stmt, 60 Sub, Subscript, TryExcept, TryFinally, Tuple, While, UnaryAdd, 61 UnarySub. 62 63 Missing: Backquote, Bitor, Bitxor, Decorators, Ellipsis, Exec, LeftShift, 64 RightShift, Yield. 65 """ 66 67 def __init__(self, builtins=0): 68 69 """ 70 Initialise the simplifier with the optional 'builtins' parameter 71 indicating whether the module contains the built-in classes and 72 functions. 73 """ 74 75 Visitor.__init__(self) 76 self.subprograms = [] # Subprograms outside the tree. 77 self.structures = [] # Structures/classes. 78 self.constants = {} # Constants. 79 self.current_subprograms = [] # Current subprograms being processed. 80 self.current_structures = [] # Current structures being processed. 81 self.within_class = 0 # Whether a class is being defined. 82 self.builtins = builtins # Whether the builtins are being processed. 83 84 # Convenience attributes. 85 86 self.subnames = {} 87 88 # For compiler package mechanisms. 89 90 self.visitor = self 91 92 def process(self, module, name): 93 94 """ 95 Process the 'module' having the given 'name'. Return the simplified node 96 representing the 'module'. 97 """ 98 99 result = self.dispatch(module, name) 100 result.simplifier = self 101 return result 102 103 def dispatch_or_none(self, node, *args): 104 105 """ 106 Dispatch to a handler for 'node', returning the result, or if 'node' is 107 None then return a node which loads None in the simplified program. 108 """ 109 110 if node is not None: 111 return self.dispatch(node, *args) 112 else: 113 return LoadName(node, name="None") 114 115 # Top-level transformation. 116 117 def visitModule(self, module, name=None): 118 119 """ 120 Process the given 'module', producing a Module object which contains the 121 resulting program nodes. If the optional 'name' is provided, the 'name' 122 attribute is set on the Module object using a value other than None. 123 """ 124 125 result = self.module = Module(module, 1, name=name) 126 result.code = [] 127 128 # Add an initialiser for the module name first for non-builtins. 129 130 if self.builtins: 131 result.code += self.dispatch(module.node) 132 133 result.code += [ 134 StoreName(name="__name__", expr=self._visitConst(None, name)) 135 ] 136 137 # Add an initialiser for the module name last for builtins. 138 139 if not self.builtins: 140 result.code += self.dispatch(module.node) 141 return result 142 143 # Node transformations. 144 145 def visitAdd(self, add): 146 return self._visitBinary(add, "__add__", "__radd__") 147 148 def visitAnd(self, and_): 149 150 """ 151 Make a subprogram for the 'and_' node and record its contents inside the 152 subprogram. Convert... 153 154 And (test) 155 (test) 156 ... 157 158 ...to: 159 160 Subprogram -> Conditional (test) -> ReturnFromBlock ... 161 (else) -> Conditional (test) -> ReturnFromBlock ... 162 (else) -> ... 163 """ 164 165 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) 166 self.current_subprograms.append(subprogram) 167 168 # In the subprogram, make instructions which store each operand, test 169 # for each operand's truth status, and if appropriate return from the 170 # subprogram with the value of the operand. 171 172 last = and_.nodes[-1] 173 results = nodes = [] 174 175 for node in and_.nodes: 176 expr = self.dispatch(node) 177 178 # Return from the subprogram where the test is not satisfied. 179 180 if node is not last: 181 nodes += [ 182 StoreTemp(expr=expr), 183 Conditional( 184 test=self._visitNot(LoadTemp()), 185 body=[ 186 ReturnFromBlock( 187 expr=LoadTemp() 188 ) 189 ], 190 else_=[ 191 ReleaseTemp() 192 # Subsequent operations go here! 193 ] 194 ) 195 ] 196 197 # Put subsequent operations in the else section of this conditional. 198 199 nodes = nodes[-1].else_ 200 201 # For the last operation, return the result. 202 203 else: 204 nodes.append(ReturnFromBlock(expr=expr)) 205 206 # Finish the subprogram definition. 207 208 subprogram.code = results 209 210 self.current_subprograms.pop() 211 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 212 213 # Make an invocation of the subprogram. 214 215 result = InvokeRef(and_, 1, produces_result=1, ref=subprogram) 216 return result 217 218 def visitAssert(self, assert_): 219 if assert_.fail: 220 fail_args = [self.dispatch(assert_.fail)] 221 else: 222 fail_args = [] 223 224 result = Conditional(assert_, 1, 225 test=self.dispatch(assert_.test), 226 body=[], 227 else_=[ 228 Raise(assert_, 229 expr=InvokeFunction(assert_, 230 expr=LoadName(name="AssertionError"), 231 args=fail_args, 232 star=None, 233 dstar=None 234 ) 235 ) 236 ] 237 ) 238 239 # Make nice annotations for the viewer. 240 241 assert_._raises = result.else_[0].expr 242 return result 243 244 # Assignments. 245 246 def visitAssAttr(self, assattr, element=None): 247 expr = self._visitAssNameOrAttr(assattr, element) 248 lvalue = self.dispatch(assattr.expr) 249 result = StoreAttr(assattr, 1, name=assattr.attrname, lvalue=lvalue, expr=expr) 250 return result 251 252 def visitAssign(self, assign): 253 result = Assign(assign, 1) 254 store = StoreTemp(expr=self.dispatch(assign.expr)) 255 release = ReleaseTemp() 256 result.code = [store] + self.dispatches(assign.nodes) + [release] 257 return result 258 259 def visitAssList(self, asslist, element=None): 260 if element is None: 261 expr = LoadTemp() 262 else: 263 expr = LoadAttr(expr=LoadTemp(), name=("__value__%d" % element)) 264 result = Assign(asslist, 1) 265 result.code = [StoreTemp(expr=expr)] 266 for i, node in enumerate(asslist.nodes): 267 result.code.append(self.dispatch(node, i)) 268 result.code.append(ReleaseTemp()) 269 return result 270 271 visitAssTuple = visitAssList 272 273 def _visitAssNameOrAttr(self, node, element=None): 274 275 "Produce a suitable value for assignment from the given 'node'." 276 277 if element is None: 278 return LoadTemp() 279 else: 280 return LoadAttr(expr=LoadTemp(), name=("__value__%d" % element)) 281 282 def visitAssName(self, assname, element=None): 283 284 """ 285 Visit the 'assname' node, producing an appropriate StoreName simplified 286 node which if 'element' is None will store a temporary value; otherwise, 287 a special attribute will be obtained from the current temporary value in 288 order to attempt to support optimised sequence assignment. 289 """ 290 291 expr = self._visitAssNameOrAttr(assname, element) 292 result = StoreName(assname, 1, name=assname.name, expr=expr) 293 return result 294 295 augassign_methods = { 296 "+=" : "__iadd__", "-=" : "__isub__", "*=" : "__imul__", "/=" : "__idiv__", 297 "%=" : "__imod__", "**=" : "__ipow__", "<<=" : "__ilshift__", ">>=" : "__irshift__", 298 "&=" : "__iand__", "^=" : "__ixor__", "|=" : "__ior__" 299 } 300 301 def visitAugAssign(self, augassign): 302 303 """ 304 Convert the augmented assignment... 305 306 AugAssign (node) -> Name | Getattr | Slice | Subscript 307 (op) 308 (expr) 309 310 ...to: 311 312 Assign (code) -> StoreTemp (expr) -> InvokeFunction (expr) -> LoadAttr (expr) -> <name> 313 (name) -> <op> 314 StoreName (name) -> <name> 315 (expr) -> LoadTemp 316 ReleaseTemp 317 """ 318 319 result = Assign(augassign, 1) 320 expr = self.dispatch(augassign.expr) 321 322 # Simple augmented assignment: name += expr 323 324 if isinstance(augassign.node, compiler.ast.Name): 325 result.code = [ 326 StoreTemp( 327 expr=InvokeFunction( # referenced below 328 augassign, 329 args=[expr], 330 star=None, 331 dstar=None, 332 expr=LoadAttr( 333 expr=self.dispatch(augassign.node), 334 name=self.augassign_methods[augassign.op] 335 ) 336 ) 337 ), 338 StoreName( 339 expr=LoadTemp(), 340 name=augassign.node.name), 341 ReleaseTemp() 342 ] 343 344 # Make nice annotations for the viewer. 345 346 augassign._op_call = result.code[0].expr 347 348 # Complicated augmented assignment: lvalue.attr += expr 349 350 elif isinstance(augassign.node, compiler.ast.Getattr): 351 352 # <lvalue> -> setattr(<lvalue>, getattr(<lvalue>, "attr").__xxx__(expr)) 353 354 result.code = [ 355 StoreTemp( 356 index="expr", 357 expr=self.dispatch(augassign.node.expr) 358 ), 359 StoreTemp( 360 expr=InvokeFunction( # referenced below 361 augassign, 362 args=[expr], star=None, dstar=None, 363 expr=LoadAttr( 364 expr=LoadAttr(augassign.node, 1, 365 expr=LoadTemp(index="expr"), 366 name=augassign.node.attrname 367 ), 368 name=self.augassign_methods[augassign.op] 369 ) 370 ) 371 ), 372 StoreAttr( 373 expr=LoadTemp(), 374 lvalue=LoadTemp(index="expr"), 375 name=augassign.node.attrname 376 ), 377 ReleaseTemp(index="expr"), 378 ReleaseTemp() 379 ] 380 381 # Make nice annotations for the viewer. 382 383 augassign._op_call = result.code[1].expr 384 385 # Complicated augassign using slices: lvalue[lower:upper] += expr 386 387 elif isinstance(augassign.node, compiler.ast.Slice): 388 389 # <lvalue>, <lower>, <upper> -> <lvalue>.__setslice__(<lower>, <upper>, <lvalue>.__getslice__(<lower>, <upper>).__xxx__(expr)) 390 391 result.code = [ 392 StoreTemp( 393 index="expr", 394 expr=self.dispatch(augassign.node.expr) 395 ), 396 StoreTemp( 397 index="lower", 398 expr=self.dispatch_or_none(augassign.node.lower) 399 ), 400 StoreTemp( 401 index="upper", 402 expr=self.dispatch_or_none(augassign.node.upper) 403 ), 404 StoreTemp( 405 expr=InvokeFunction( # referenced below 406 augassign, 407 args=[expr], star=None, dstar=None, 408 expr=LoadAttr( 409 expr=self._visitSlice( 410 augassign.node, 411 LoadTemp(index="expr"), 412 LoadTemp(index="lower"), 413 LoadTemp(index="upper"), 414 "OP_APPLY"), 415 name=self.augassign_methods[augassign.op] 416 ) 417 ) 418 ), 419 self._visitSlice( 420 augassign.node, 421 LoadTemp(index="expr"), 422 LoadTemp(index="lower"), 423 LoadTemp(index="upper"), 424 "OP_ASSIGN", 425 LoadTemp() 426 ), 427 ReleaseTemp(index="expr"), 428 ReleaseTemp(index="lower"), 429 ReleaseTemp(index="upper"), 430 ReleaseTemp() 431 ] 432 433 # Make nice annotations for the viewer. 434 435 augassign._op_call = result.code[3].expr 436 437 # Complicated augassign using subscripts: lvalue[subs] += expr 438 439 elif isinstance(augassign.node, compiler.ast.Subscript): 440 441 # <lvalue>, <subs> -> <lvalue>.__setitem__(<subs>, <lvalue>.__getitem__(<subs>).__xxx__(expr)) 442 443 result.code = [ 444 StoreTemp(index="expr", expr=self.dispatch(augassign.node.expr)), 445 StoreTemp(index="subs", expr=self._visitSubscriptSubs(augassign.node, augassign.node.subs)), 446 StoreTemp( 447 expr=InvokeFunction( # referenced below 448 augassign, 449 args=[expr], star=None, dstar=None, 450 expr=LoadAttr( 451 expr=self._visitSubscript( 452 augassign.node, 453 LoadTemp(index="expr"), 454 LoadTemp(index="subs"), 455 "OP_APPLY" 456 ), 457 name=self.augassign_methods[augassign.op] 458 ) 459 ) 460 ), 461 self._visitSubscript( 462 augassign.node, 463 LoadTemp(index="expr"), 464 LoadTemp(index="subs"), 465 "OP_ASSIGN", 466 LoadTemp() 467 ), 468 ReleaseTemp(index="expr"), 469 ReleaseTemp(index="subs"), 470 ReleaseTemp() 471 ] 472 473 # Make nice annotations for the viewer. 474 475 augassign._op_call = result.code[2].expr 476 477 else: 478 raise NotImplementedError, augassign.node.__class__ 479 480 return result 481 482 def visitBitand(self, bitand): 483 484 """ 485 Make a subprogram for the 'bitand' node and record its contents inside the 486 subprogram. Convert... 487 488 Bitand (node) 489 (node) 490 ... 491 492 ...to: 493 494 Subprogram -> Conditional (test) -> ReturnFromBlock ... 495 (else) -> Conditional (test) -> ReturnFromBlock ... 496 (else) -> ... 497 """ 498 499 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) 500 self.current_subprograms.append(subprogram) 501 502 # In the subprogram, make instructions which store each operand, test 503 # for each operand's truth status, and if appropriate return from the 504 # subprogram with the value of the operand. 505 506 last = bitand.nodes[-1] 507 results = nodes = [] 508 509 # Start by storing the first operand. 510 511 nodes += [ 512 StoreTemp(expr=self.dispatch(bitand.nodes[0])) 513 ] 514 515 # For viewing purposes, record invocations on the AST node. 516 517 bitand._ops = [] 518 519 for node in bitand.nodes[1:]: 520 521 # Make a new AST-style node to wrap the operation program nodes. 522 523 new_op = Op("&", node) 524 bitand._ops.append(new_op) 525 526 # Generate the operation involving the previous result and the 527 # current operand. 528 529 expr = self._visitBinaryOp(new_op, LoadTemp(), self.dispatch(node), "__and__", "__rand__") 530 531 # Return from the subprogram where the test is not satisfied. 532 533 if node is not last: 534 nodes += [ 535 StoreTemp(expr=expr), 536 Conditional( 537 test=self._visitNot(LoadTemp()), 538 body=[ 539 ReturnFromBlock( 540 expr=LoadTemp() 541 ) 542 ], 543 else_=[ 544 # Subsequent operations go here! 545 ] 546 ) 547 ] 548 549 # Put subsequent operations in the else section of this conditional. 550 551 nodes = nodes[-1].else_ 552 553 # For the last operation, return the result. 554 555 else: 556 nodes.append(ReturnFromBlock(expr=expr)) 557 558 # Finish the subprogram definition. 559 560 subprogram.code = results 561 562 self.current_subprograms.pop() 563 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 564 565 # Make an invocation of the subprogram. 566 567 result = InvokeRef(bitand, 1, produces_result=1, ref=subprogram) 568 return result 569 570 def visitBreak(self, break_): 571 result = ReturnFromBlock(break_, 1) 572 return result 573 574 def visitCallFunc(self, callfunc): 575 result = InvokeFunction(callfunc, 1, star=None, dstar=None, args=self.dispatches(callfunc.args)) 576 if callfunc.star_args is not None: 577 result.star = self.dispatch(callfunc.star_args) 578 if callfunc.dstar_args is not None: 579 result.dstar = self.dispatch(callfunc.dstar_args) 580 result.expr = self.dispatch(callfunc.node) 581 return result 582 583 def visitClass(self, class_): 584 585 # Add "object" if the class is not "object" and has an empty bases list. 586 587 if class_.name != "object" and not class_.bases: 588 bases = [compiler.ast.Name("object")] 589 else: 590 bases = class_.bases 591 592 structure = get_class()(name=class_.name, module=self.module, bases=self.dispatches(bases)) 593 self.structures.append(structure) 594 within_class = self.within_class 595 self.within_class = 1 596 597 # Make a subprogram which initialises the class structure. 598 599 subprogram = Subprogram(name=None, module=self.module, structure=structure, params=[], star=None, dstar=None) 600 self.current_subprograms.append(subprogram) 601 self.current_structures.append(structure) # mostly for name construction 602 603 # The class is initialised using the code found inside. 604 605 subprogram.code = self.dispatch(class_.code) + [ReturnFromBlock()] 606 607 self.within_class = within_class 608 self.current_structures.pop() 609 self.current_subprograms.pop() 610 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 611 612 # Make a definition of the class associating it with a name. 613 614 result = Assign( 615 code=[ 616 StoreName(class_, 1, # defines the class 617 name=class_.name, 618 expr=LoadRef(ref=structure) 619 ), 620 InvokeRef( 621 class_, 622 share_locals=0, # override the local sharing usually in InvokeRef 623 ref=subprogram 624 ) 625 ] 626 ) 627 return result 628 629 comparison_methods = { 630 "==" : ("__eq__", "__ne__"), 631 "!=" : ("__ne__", "__eq__"), 632 "<" : ("__lt__", "__gt__"), 633 "<=" : ("__le__", "__ge__"), 634 ">=" : ("__ge__", "__le__"), 635 ">" : ("__gt__", "__lt__"), 636 "is" : None, 637 "is not" : None, 638 "in" : None, 639 "not in" : None 640 } 641 642 def visitCompare(self, compare): 643 644 """ 645 Make a subprogram for the 'compare' node and record its contents inside 646 the subprogram. Convert... 647 648 Compare (expr) 649 (name/node) 650 ... 651 652 ...to: 653 654 InvokeRef -> Subprogram -> Conditional (test) -> (body) 655 (else) -> Conditional (test) -> (body) 656 (else) -> ... 657 """ 658 659 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) 660 self.current_subprograms.append(subprogram) 661 662 # In the subprogram, make instructions which invoke a method on the 663 # first operand of each operand pair and, if appropriate, return with 664 # the value from that method. 665 666 last = compare.ops[-1] 667 previous = self.dispatch(compare.expr) 668 results = nodes = [] 669 670 # For viewing purposes, record invocations on the AST node. 671 672 compare._ops = [] 673 674 for op in compare.ops: 675 op_name, node = op 676 677 # Make a new AST-style node to wrap the operation program nodes. 678 679 new_op = Op(op_name, node) 680 compare._ops.append(new_op) 681 682 expr = self.dispatch(node) 683 684 # Identify the operation and produce the appropriate method call. 685 686 method_names = self.comparison_methods[op_name] 687 if method_names: 688 first_name, alternative_name = method_names 689 invocation = self._visitBinaryCompareOp(new_op, previous, expr, first_name, alternative_name) 690 691 elif op_name == "is": 692 invocation = InvokeFunction( 693 new_op, 1, 694 expr=LoadName(name="__is__"), 695 args=[previous, expr], 696 star=None, 697 dstar=None) 698 699 elif op_name == "is not": 700 invocation = Not( 701 new_op, 1, 702 expr=InvokeFunction( 703 new_op, 704 expr=LoadName(name="__is__"), 705 args=[previous, expr], 706 star=None, 707 dstar=None) 708 ) 709 710 elif op_name == "in": 711 invocation = InvokeFunction( 712 new_op, 1, 713 expr=LoadAttr( 714 expr=previous, 715 name="__contains__" 716 ), 717 args=[expr], 718 star=None, 719 dstar=None) 720 721 elif op_name == "not in": 722 invocation = Not( 723 new_op, 1, 724 expr=InvokeFunction( 725 new_op, 726 expr=LoadAttr( 727 expr=previous, 728 name="__contains__" 729 ), 730 args=[expr], 731 star=None, 732 dstar=None) 733 ) 734 735 else: 736 raise NotImplementedError, op_name 737 738 nodes.append(StoreTemp(expr=invocation)) 739 740 # Return from the subprogram where the test is not satisfied. 741 742 if op is not last: 743 nodes.append( 744 Conditional( 745 test=self._visitNot(LoadTemp()), 746 body=[ 747 ReturnFromBlock(expr=LoadTemp()) 748 ], 749 else_=[ 750 ReleaseTemp() 751 # Subsequent operations go here! 752 ] 753 ) 754 ) 755 756 # Put subsequent operations in the else section of this conditional. 757 758 nodes = nodes[-1].else_ 759 760 # For the last operation, return the result. 761 762 else: 763 nodes.append( 764 ReturnFromBlock(expr=LoadTemp(release=1)) 765 ) 766 767 previous = expr 768 769 # Finish the subprogram definition. 770 771 subprogram.code = results 772 773 self.current_subprograms.pop() 774 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 775 776 # Make an invocation of the subprogram. 777 778 result = InvokeRef(compare, 1, produces_result=1, ref=subprogram) 779 return result 780 781 def visitConst(self, const): 782 return self._visitConst(const, const.value) 783 784 def _visitConst(self, node, value): 785 key = "%s-%s" % (value.__class__.__name__, value) 786 if not self.constants.has_key(key): 787 self.constants[key] = Constant(name=repr(value), value=value) 788 if node is not None: 789 result = InvokeFunction(node, 1, expr=LoadName(name=self.constants[key].typename)) 790 else: 791 result = InvokeFunction(expr=LoadName(name=self.constants[key].typename)) 792 return result 793 794 def visitContinue(self, continue_): 795 result = InvokeRef(continue_, 1, ref=self.current_subprograms[-1]) 796 return result 797 798 def visitDict(self, dict): 799 result = InvokeFunction(dict, 1, expr=LoadName(name="dict")) 800 args = [] 801 for key, value in dict.items: 802 tuple = InvokeFunction(dict, expr=LoadName(name="tuple")) 803 tuple.set_args([self.dispatch(key), self.dispatch(value)]) 804 args.append(tuple) 805 result.set_args(args) 806 return result 807 808 def visitDiscard(self, discard): 809 return self.dispatch(discard.expr) 810 811 def visitDiv(self, div): 812 return self._visitBinary(div, "__div__", "__rdiv__") 813 814 def visitFloorDiv(self, floordiv): 815 return self._visitBinary(floordiv, "__floordiv__", "__rfloordiv__") 816 817 def visitFor(self, for_): 818 819 """ 820 Make a subprogram for the 'for_' node and record its contents inside the 821 subprogram. Convert... 822 823 For (assign) 824 (body) 825 (else) 826 827 ...to: 828 829 Assign (assign #1) 830 Invoke -> Subprogram -> Try (body) -> (assign #2) 831 (body) 832 Invoke subprogram 833 (handler) -> ... 834 (else) -> ... 835 """ 836 837 return self._visitFor(for_, self.dispatches(for_.body), for_.else_) 838 839 def _visitFor(self, node, body_stmt, else_=None): 840 841 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=0, params=[]) 842 self.current_subprograms.append(subprogram) 843 844 # Always return from conditional sections/subprograms. 845 846 if else_ is not None: 847 else_stmt = self.dispatch(else_) + [ReturnFromBlock()] 848 else: 849 else_stmt = [ReturnFromBlock()] 850 851 # Wrap the assignment in a try...except statement. 852 # Inside the body, add a recursive invocation to the subprogram. 853 854 subprogram.code = [ 855 Try( 856 body=[ 857 Assign( 858 code=[ 859 StoreTemp( 860 expr=InvokeFunction(node, 861 expr=LoadAttr( 862 expr=LoadTemp(), 863 name="next" 864 ) 865 ) 866 ), 867 self.dispatch(node.assign), 868 ReleaseTemp() 869 ]) 870 ] + body_stmt + [ 871 InvokeRef( 872 node, 873 ref=subprogram 874 ) 875 ], 876 handler=[ 877 Conditional( 878 test=InvokeFunction( 879 node, 880 expr=LoadName(name="isinstance"), 881 args=[LoadExc(), LoadName(name="StopIteration")], 882 star=None, 883 dstar=None), 884 body=else_stmt, 885 else_=[ 886 Raise( 887 expr=LoadExc() 888 ) 889 ] 890 ) 891 ], 892 else_=[], 893 finally_=[] 894 ), 895 ReturnFromBlock() 896 ] 897 898 # Finish the subprogram definition. 899 900 self.current_subprograms.pop() 901 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 902 903 # Obtain an iterator for the sequence involved. 904 # Then, make an invocation of the subprogram. 905 906 result = Assign(node, 1, 907 code=[ 908 StoreTemp( 909 expr=InvokeFunction( 910 node, 911 expr=LoadAttr( 912 name="__iter__", 913 expr=self.dispatch(node.list) 914 ) 915 ) 916 ), 917 InvokeRef(node, ref=subprogram), 918 ReleaseTemp() 919 ] 920 ) 921 922 # Make nice annotations for the viewer. 923 924 node._iter_call = result.code[0].expr 925 node._next_call = subprogram.code[0].body[0].code[0].expr 926 927 return result 928 929 def visitFrom(self, from_): 930 result = Assign(from_, 1) 931 code = [] 932 _names = [] 933 code.append( 934 StoreTemp( 935 expr=Import(name=from_.modname, alias=1) 936 ) 937 ) 938 from_._modname = code[-1].expr 939 for name, alias in from_.names: 940 code.append( 941 StoreName( 942 expr=LoadAttr( 943 expr=LoadTemp(), 944 name=name), 945 name=(alias or name) 946 ) 947 ) 948 _names.append(code[-1].expr) 949 code.append(ReleaseTemp()) 950 result.code = code 951 from_._names = _names 952 return result 953 954 def _visitFunction(self, function, subprogram): 955 956 """ 957 A common function generator which transforms the given 'function' node 958 and initialises the given 'subprogram' appropriately. 959 """ 960 961 # Discover star and dstar parameters. 962 963 if function.flags & 4 != 0: 964 has_star = 1 965 else: 966 has_star = 0 967 if function.flags & 8 != 0: 968 has_dstar = 1 969 else: 970 has_dstar = 0 971 972 # Discover the number of defaults and positional parameters. 973 974 ndefaults = len(function.defaults) 975 npositional = len(function.argnames) - has_star - has_dstar 976 977 # Produce star and dstar parameters with appropriate defaults. 978 979 if has_star: 980 star = ( 981 function.argnames[npositional], 982 self.dispatch(compiler.ast.List([])) 983 ) 984 else: 985 star = None 986 if has_dstar: 987 dstar = ( 988 function.argnames[npositional + has_star], 989 self.dispatch(compiler.ast.Dict([])) 990 ) 991 else: 992 dstar = None 993 994 params = [] 995 for i in range(0, npositional - ndefaults): 996 params.append((function.argnames[i], None)) 997 998 # Process defaults. 999 1000 for i in range(0, ndefaults): 1001 default = function.defaults[i] 1002 if default is not None: 1003 params.append((function.argnames[npositional - ndefaults + i], self.dispatch(default))) 1004 else: 1005 params.append((function.argnames[npositional - ndefaults + i], None)) 1006 1007 subprogram.params = params 1008 subprogram.star = star 1009 subprogram.dstar = dstar 1010 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1011 1012 def visitFunction(self, function): 1013 1014 """ 1015 Make a subprogram for the 'function' and record it outside the main 1016 tree. Produce something like the following: 1017 1018 StoreName (name) 1019 (expr) -> LoadRef (ref) -> Subprogram (params) 1020 (star) 1021 (dstar) 1022 """ 1023 1024 subprogram = Subprogram(function, name=function.name, module=self.module, structures=self.current_structures[:], 1025 internal=0, returns_value=1, star=None, dstar=None, is_method=self.within_class, original_def=function) 1026 1027 # Make nice annotations for the viewer. 1028 1029 function._subprogram = subprogram 1030 1031 self.current_subprograms.append(subprogram) 1032 within_class = self.within_class 1033 self.within_class = 0 1034 1035 subprogram.code = self.dispatch(function.code) + [ReturnFromFunction()] 1036 1037 self.within_class = within_class 1038 self.current_subprograms.pop() 1039 self._visitFunction(function, subprogram) 1040 1041 # Make a definition of the function associating it with a name. 1042 1043 result = StoreName(function, 1, name=function.name, expr=LoadRef(ref=subprogram)) 1044 return result 1045 1046 def visitGetattr(self, getattr): 1047 result = LoadAttr(getattr, 1, 1048 name=getattr.attrname, 1049 expr=self.dispatch(getattr.expr) 1050 ) 1051 return result 1052 1053 def visitGlobal(self, global_): 1054 result = Global(global_, 1, 1055 names=global_.names 1056 ) 1057 return result 1058 1059 def visitIf(self, if_): 1060 1061 """ 1062 Make conditionals for each test from an 'if_' AST node, adding the body 1063 and putting each subsequent test as part of the conditional's else 1064 section. 1065 1066 Convert... 1067 1068 If (test/body) 1069 (test/body) 1070 ... 1071 (else/body) 1072 1073 ...to: 1074 1075 Conditional (test) -> (body) 1076 (else) -> Conditional (test) -> (body) 1077 (else) -> ... 1078 """ 1079 1080 1081 results = nodes = [] 1082 1083 # Produce something like... 1084 # expr.__bool__() ? body 1085 1086 first = 1 1087 for compare, stmt in if_.tests: 1088 1089 # Set the first as the defining node. 1090 1091 test = Conditional(if_, first, 1092 test=InvokeFunction( 1093 if_, 1094 expr=LoadAttr( 1095 expr=self.dispatch(compare), 1096 name="__bool__" 1097 ), 1098 ) 1099 ) 1100 test.body = self.dispatch(stmt) 1101 nodes.append(test) 1102 nodes = test.else_ = [] 1103 first = 0 1104 1105 # Add the compound statement from any else clause to the end. 1106 1107 if if_.else_ is not None: 1108 nodes += self.dispatch(if_.else_) 1109 1110 result = results[0] 1111 return result 1112 1113 def visitImport(self, import_): 1114 result = Assign(import_, 1) 1115 code = [] 1116 _names = [] 1117 for path, alias in import_.names: 1118 importer = Import(name=path, alias=alias) 1119 top = alias or path.split(".")[0] 1120 code.append(StoreName(expr=importer, name=top)) 1121 _names.append(code[-1].expr) 1122 result.code = code 1123 import_._names = _names 1124 return result 1125 1126 def visitInvert(self, invert): 1127 return self._visitUnary(invert, "__invert__") 1128 1129 def visitKeyword(self, keyword): 1130 result = Keyword(keyword, 1, 1131 name=keyword.name, 1132 expr=self.dispatch(keyword.expr) 1133 ) 1134 return result 1135 1136 def visitLambda(self, lambda_): 1137 1138 # Make a subprogram for the function and record it outside the main 1139 # tree. 1140 1141 subprogram = Subprogram(lambda_, name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None, original_def=lambda_) 1142 1143 # Make nice annotations for the viewer. 1144 1145 lambda_._subprogram = subprogram 1146 1147 # Process the lambda contents. 1148 1149 self.current_subprograms.append(subprogram) 1150 subprogram.code = [ReturnFromFunction(expr=self.dispatch(lambda_.code))] 1151 self.current_subprograms.pop() 1152 self._visitFunction(lambda_, subprogram) 1153 1154 # Get the subprogram reference to the lambda. 1155 1156 return LoadRef(lambda_, 1, ref=subprogram) 1157 1158 def visitList(self, list): 1159 1160 # Make a subprogram for the list construction and record it outside the 1161 # main tree. 1162 1163 subprogram = Subprogram(list, name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None, original_def=list) 1164 self.current_subprograms.append(subprogram) 1165 1166 # Make nice annotations for the viewer. 1167 1168 list._subprogram = subprogram 1169 1170 subprogram.code=[ 1171 StoreTemp( 1172 expr=InvokeFunction( 1173 list, 1174 expr=LoadName( 1175 name="list" 1176 ), 1177 args=[], 1178 star=None, 1179 dstar=None 1180 ) 1181 ) 1182 ] 1183 1184 for node in list.nodes: 1185 subprogram.code.append( 1186 InvokeFunction( 1187 list, 1188 expr=LoadAttr( 1189 expr=LoadTemp(), 1190 name="append" 1191 ), 1192 args=[self.dispatch(node)], 1193 star=None, 1194 dstar=None 1195 ) 1196 ) 1197 1198 subprogram.code.append( 1199 ReturnFromBlock( 1200 expr=LoadTemp(release=1) 1201 ) 1202 ) 1203 1204 self.current_subprograms.pop() 1205 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1206 1207 # Make an invocation of the subprogram. 1208 1209 result = InvokeRef(list, 1, 1210 produces_result=1, 1211 ref=subprogram 1212 ) 1213 return result 1214 1215 def visitListComp(self, listcomp): 1216 1217 # Make a subprogram for the list comprehension and record it outside the 1218 # main tree. 1219 1220 subprogram = Subprogram(listcomp, name=None, module=self.module, internal=1, returns_value=1, star=None, dstar=None, original_def=listcomp) 1221 self.current_subprograms.append(subprogram) 1222 1223 # Make nice annotations for the viewer. 1224 1225 listcomp._subprogram = subprogram 1226 1227 # Add a temporary variable. 1228 # Produce for loops within the subprogram. 1229 # Return the result. 1230 1231 subprogram.code = [ 1232 StoreTemp( 1233 index="listcomp", 1234 expr=InvokeFunction( 1235 expr=LoadName(name="list"), 1236 args=[], 1237 star=None, 1238 dstar=None 1239 ) 1240 ) 1241 ] + self._visitListCompFor(listcomp, listcomp.quals) + [ 1242 ReturnFromBlock( 1243 expr=LoadTemp( 1244 index="listcomp", 1245 release=1 1246 ) 1247 ) 1248 ] 1249 1250 self.current_subprograms.pop() 1251 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1252 1253 # Make an invocation of the subprogram. 1254 1255 result = InvokeRef(listcomp, 1, 1256 produces_result=1, 1257 ref=subprogram 1258 ) 1259 return result 1260 1261 def _visitListCompFor(self, node, quals): 1262 qual = quals[0] 1263 if len(quals) > 1: 1264 body = self._visitListCompFor(node, quals[1:]) 1265 if qual.ifs: 1266 body = self._visitListCompIf(node, qual.ifs, body) 1267 elif qual.ifs: 1268 body = self._visitListCompIf(node, qual.ifs) 1269 else: 1270 body = self._visitListCompBody(node) 1271 return [self._visitFor(qual, body)] 1272 1273 def _visitListCompIf(self, node, ifs, expr=None): 1274 if_ = ifs[0] 1275 if len(ifs) > 1: 1276 body = self._visitListCompIf(node, ifs[1:], expr) 1277 elif expr is None: 1278 body = self._visitListCompBody(node) 1279 else: 1280 body = expr 1281 return [ 1282 Conditional(if_, 1, 1283 test=InvokeFunction( 1284 if_, 1285 expr=LoadAttr( 1286 expr=self.dispatch(if_.test), 1287 name="__bool__" 1288 ), 1289 ), 1290 body=body, 1291 else_=[] 1292 ) 1293 ] 1294 1295 def _visitListCompBody(self, node): 1296 return [ 1297 InvokeFunction( 1298 expr=LoadAttr( 1299 expr=LoadTemp(index="listcomp"), 1300 name="append" 1301 ), 1302 args=[self.dispatch(node.expr)], 1303 star=None, 1304 dstar=None 1305 ) 1306 ] 1307 1308 def visitMod(self, mod): 1309 return self._visitBinary(mod, "__mod__", "__rmod__") 1310 1311 def visitMul(self, mul): 1312 return self._visitBinary(mul, "__mul__", "__rmul__") 1313 1314 def visitName(self, name): 1315 result = LoadName(name, 1, name=name.name) 1316 return result 1317 1318 def _visitNot(self, expr, not_=None): 1319 invocation = InvokeFunction( 1320 not_, # NOTE: May need a real original node. 1321 expr=LoadAttr( 1322 expr=expr, 1323 name="__bool__" 1324 ), 1325 ) 1326 if not_ is not None: 1327 result = Not(not_, 1, expr=invocation) 1328 else: 1329 result = Not(expr=invocation) 1330 return result 1331 1332 def visitNot(self, not_): 1333 return self._visitNot(self.dispatch(not_.expr), not_) 1334 1335 def visitOr(self, or_): 1336 1337 """ 1338 Make a subprogram for the 'or_' node and record its contents inside the 1339 subprogram. Convert... 1340 1341 Or (test) 1342 (test) 1343 ... 1344 1345 ...to: 1346 1347 Subprogram -> Conditional (test) -> ReturnFromBlock ... 1348 (else) -> Conditional (test) -> ReturnFromBlock ... 1349 (else) -> ... 1350 """ 1351 1352 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) 1353 self.current_subprograms.append(subprogram) 1354 1355 # In the subprogram, make instructions which store each operand, test 1356 # for each operand's truth status, and if appropriate return from the 1357 # subprogram with the value of the operand. 1358 1359 last = or_.nodes[-1] 1360 results = nodes = [] 1361 1362 for node in or_.nodes: 1363 expr = self.dispatch(node) 1364 1365 # Return from the subprogram where the test is satisfied. 1366 1367 if node is not last: 1368 nodes.append(StoreTemp(expr=expr)) 1369 invocation = InvokeFunction(or_, expr=LoadAttr(expr=LoadTemp(), name="__bool__")) 1370 test = Conditional(test=invocation, body=[ReturnFromBlock(expr=LoadTemp())]) 1371 nodes.append(test) 1372 1373 # Put subsequent operations in the else section of this conditional. 1374 1375 nodes = test.else_ = [ReleaseTemp()] 1376 1377 # For the last operation, return the result. 1378 1379 else: 1380 nodes.append( 1381 ReturnFromBlock(expr=expr) 1382 ) 1383 1384 # Finish the subprogram definition. 1385 1386 subprogram.code = results 1387 1388 self.current_subprograms.pop() 1389 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1390 1391 # Make an invocation of the subprogram. 1392 1393 result = InvokeRef(or_, 1, 1394 produces_result=1, 1395 ref=subprogram 1396 ) 1397 return result 1398 1399 def visitPass(self, pass_): 1400 return Pass(pass_, 1) 1401 1402 def visitPower(self, power): 1403 return self._visitBinary(power, "__pow__", "__rpow__") 1404 1405 def visitPrint(self, print_): 1406 1407 """ 1408 Convert... 1409 1410 Print (dest) -> 1411 (nodes) 1412 1413 ...to: 1414 1415 StoreTemp (index) -> "print" 1416 (expr) -> LoadAttr (expr) -> (dest) 1417 (name) -> "write" 1418 InvokeFunction (expr) -> LoadTemp (index) -> "print" 1419 (args) -> [(node)] 1420 ReleaseTemp (index) -> "print" 1421 """ 1422 1423 if print_.dest is not None: 1424 dest = self.dispatch(print_.dest) 1425 else: 1426 dest = self.dispatch(compiler.ast.Name("stdout")) 1427 1428 result = Assign(print_, 1, 1429 code=[ 1430 StoreTemp( 1431 index="print", 1432 expr=LoadAttr( 1433 expr=dest, 1434 name="write" 1435 ) 1436 ) 1437 ] 1438 ) 1439 1440 for node in print_.nodes: 1441 result.code.append( 1442 InvokeFunction( 1443 print_, 1444 expr=LoadTemp(index="print"), 1445 args=[self.dispatch(node)], 1446 star=None, 1447 dstar=None 1448 ) 1449 ) 1450 1451 result.code.append( 1452 ReleaseTemp(index="print") 1453 ) 1454 1455 return result 1456 1457 def visitPrintnl(self, printnl): 1458 result = self.visitPrint(printnl) 1459 result.code.insert( 1460 len(result.code) - 1, 1461 InvokeFunction( 1462 printnl, 1463 expr=LoadTemp(index="print"), 1464 args=[self.dispatch(compiler.ast.Const("\n"))], 1465 star=None, 1466 dstar=None 1467 ) 1468 ) 1469 return result 1470 1471 def visitRaise(self, raise_): 1472 result = Raise(raise_, 1) 1473 if raise_.expr2 is None: 1474 result.expr = self.dispatch(raise_.expr1) 1475 else: 1476 result.expr = InvokeFunction( 1477 raise_, 1478 expr=self.dispatch(raise_.expr1), 1479 args=[self.dispatch(raise_.expr2)], 1480 star=None, 1481 dstar=None 1482 ) 1483 if raise_.expr3 is not None: 1484 result.traceback = self.dispatch(raise_.expr3) 1485 else: 1486 result.traceback = None 1487 return result 1488 1489 def visitReturn(self, return_): 1490 result = ReturnFromFunction(return_, 1, 1491 expr=self.dispatch(return_.value) 1492 ) 1493 return result 1494 1495 def _visitSlice(self, slice, expr, lower, upper, flags, value=None): 1496 if flags == "OP_ASSIGN": 1497 result = InvokeFunction(slice, 1, 1498 expr=LoadAttr( 1499 expr=expr, 1500 name="__setslice__" 1501 ), 1502 star=None, 1503 dstar=None, 1504 args=[lower, upper, value] 1505 ) 1506 elif flags == "OP_APPLY": 1507 args = [] 1508 result = InvokeFunction(slice, 1, 1509 expr=LoadAttr( 1510 expr=expr, 1511 name="__getslice__" 1512 ), 1513 star=None, 1514 dstar=None, 1515 args=[lower, upper] 1516 ) 1517 elif flags == "OP_DELETE": 1518 args = [] 1519 result = InvokeFunction(slice, 1, 1520 expr=LoadAttr( 1521 expr=expr, 1522 name="__delslice__" 1523 ), 1524 star=None, 1525 dstar=None, 1526 args=[lower, upper] 1527 ) 1528 else: 1529 raise NotImplementedError, flags 1530 1531 return result 1532 1533 def visitSlice(self, slice, element=None): 1534 return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower), 1535 self.dispatch_or_none(slice.upper), slice.flags, self._visitAssNameOrAttr(slice, element)) 1536 1537 def visitSliceobj(self, sliceobj): 1538 return InvokeFunction(sliceobj, 1, 1539 expr=LoadName(name="slice"), 1540 args=self.dispatches(sliceobj.nodes), 1541 star=None, 1542 dstar=None 1543 ) 1544 1545 def visitStmt(self, stmt): 1546 return self.dispatches(stmt.nodes) 1547 1548 def visitSub(self, sub): 1549 return self._visitBinary(sub, "__sub__", "__rsub__") 1550 1551 def _visitSubscript(self, subscript, expr, subs, flags, value=None): 1552 if flags == "OP_ASSIGN": 1553 result = InvokeFunction(subscript, 1, 1554 expr=LoadAttr( 1555 expr=expr, 1556 name="__setitem__" 1557 ), 1558 star=None, 1559 dstar=None, 1560 args=[subs, value] 1561 ) 1562 elif flags == "OP_APPLY": 1563 args = [] 1564 result = InvokeFunction(subscript, 1, 1565 expr=LoadAttr( 1566 expr=expr, 1567 name="__getitem__" 1568 ), 1569 star=None, 1570 dstar=None, 1571 args=[subs] 1572 ) 1573 elif flags == "OP_DELETE": 1574 args = [] 1575 result = InvokeFunction(subscript, 1, 1576 expr=LoadAttr( 1577 expr=expr, 1578 name="__delitem__" 1579 ), 1580 star=None, 1581 dstar=None, 1582 args=[subs] 1583 ) 1584 else: 1585 raise NotImplementedError, flags 1586 1587 return result 1588 1589 def _visitSubscriptSubs(self, node, subs): 1590 if len(subs) == 1: 1591 return self.dispatch(subs[0]) 1592 else: 1593 return InvokeFunction(node, 1, 1594 expr=LoadName(name="tuple"), 1595 args=self.dispatches(subs), 1596 star=None, 1597 dstar=None 1598 ) 1599 1600 def visitSubscript(self, subscript, element=None): 1601 return self._visitSubscript( 1602 subscript, self.dispatch(subscript.expr), self._visitSubscriptSubs(subscript, subscript.subs), subscript.flags, 1603 self._visitAssNameOrAttr(subscript, element) 1604 ) 1605 1606 def visitTryExcept(self, tryexcept): 1607 1608 """ 1609 Make conditionals for each handler associated with a 'tryexcept' node. 1610 1611 Convert... 1612 1613 TryExcept (body) 1614 (else) 1615 (spec/assign/stmt) 1616 ... 1617 1618 ...to: 1619 1620 Try (body) 1621 (else) 1622 (handler) -> Conditional (test) -> (stmt) 1623 (body) -> ResetExc ... 1624 (else) -> Conditional (test) -> (stmt) 1625 (body) -> ResetExc ... 1626 (else) -> ... 1627 """ 1628 1629 result = Try(tryexcept, 1, body=[], else_=[], finally_=[]) 1630 1631 if tryexcept.body is not None: 1632 result.body = self.dispatch(tryexcept.body) 1633 if tryexcept.else_ is not None: 1634 result.else_ = self.dispatch(tryexcept.else_) 1635 1636 results = nodes = [] 1637 catch_all = 0 1638 1639 for spec, assign, stmt in tryexcept.handlers: 1640 1641 # If no specification exists, produce an unconditional block. 1642 1643 if spec is None: 1644 nodes += self.dispatch(stmt) 1645 catch_all = 1 1646 1647 # Produce an exception value check. 1648 1649 else: 1650 test = Conditional( 1651 isolate_test=1, 1652 test=CheckType(expr=LoadExc(), choices=self._visitTryExcept(spec)) 1653 ) 1654 test.body = [] 1655 1656 if assign is not None: 1657 test.body.append( 1658 Assign( 1659 code=[ 1660 StoreTemp(expr=LoadExc()), 1661 self.dispatch(assign), 1662 ReleaseTemp() 1663 ] 1664 ) 1665 ) 1666 1667 test.body += [ResetExc()] + self.dispatch(stmt) 1668 nodes.append(test) 1669 nodes = test.else_ = [] 1670 1671 # Add a raise operation to deal with unhandled exceptions. 1672 1673 if not catch_all: 1674 nodes.append( 1675 Raise( 1676 expr=LoadExc()) 1677 ) 1678 1679 result.handler = results 1680 return result 1681 1682 def _visitTryExcept(self, spec): 1683 1684 "Return a list of nodes for the given exception type 'spec'." 1685 1686 if isinstance(spec, compiler.ast.Tuple): 1687 nodes = [] 1688 for node in spec.nodes: 1689 nodes += self._visitTryExcept(node) 1690 else: 1691 nodes = [self.dispatch(spec)] 1692 return nodes 1693 1694 def visitTryFinally(self, tryfinally): 1695 result = Try(tryfinally, 1, body=[], else_=[], finally_=[]) 1696 if tryfinally.body is not None: 1697 result.body = self.dispatch(tryfinally.body) 1698 if tryfinally.final is not None: 1699 result.finally_ = self.dispatch(tryfinally.final) 1700 return result 1701 1702 def visitTuple(self, tuple): 1703 1704 "Make a MakeTuple node containing the original 'tuple' contents." 1705 1706 result = MakeTuple(tuple, 1, 1707 nodes=self.dispatches(tuple.nodes) 1708 ) 1709 return result 1710 1711 def visitUnaryAdd(self, unaryadd): 1712 return self._visitUnary(unaryadd, "__pos__") 1713 1714 def visitUnarySub(self, unarysub): 1715 return self._visitUnary(unarysub, "__neg__") 1716 1717 def visitWhile(self, while_): 1718 1719 """ 1720 Make a subprogram for the 'while' node and record its contents inside the 1721 subprogram. Convert... 1722 1723 While (test) -> (body) 1724 (else) 1725 1726 ...to: 1727 1728 Subprogram -> Conditional (test) -> (body) -> Invoke subprogram 1729 (else) -> Conditional (test) -> ReturnFromBlock ... 1730 (else) -> ... 1731 """ 1732 1733 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=0, params=[], star=None, dstar=None) 1734 self.current_subprograms.append(subprogram) 1735 1736 # Include a conditional statement in the subprogram. 1737 # Inside the conditional, add a recursive invocation to the subprogram 1738 # if the test condition was satisfied. 1739 # Return within the main section of the loop. 1740 1741 test = Conditional( 1742 test=InvokeFunction( 1743 while_, 1744 expr=LoadAttr( 1745 expr=self.dispatch(while_.test), 1746 name="__bool__"), 1747 ), 1748 body=self.dispatch(while_.body) + [ 1749 InvokeRef( 1750 while_, 1751 ref=subprogram 1752 ), 1753 ReturnFromBlock() 1754 ], 1755 else_=[] 1756 ) 1757 1758 # Provide the else section, if present, along with an explicit return. 1759 1760 if while_.else_ is not None: 1761 test.else_ = self.dispatch(while_.else_) + [ReturnFromBlock()] 1762 1763 # Finish the subprogram definition. 1764 1765 subprogram.code = [test] 1766 1767 self.current_subprograms.pop() 1768 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1769 1770 # Make an invocation of the subprogram. 1771 1772 result = InvokeRef(while_, 1, ref=subprogram) 1773 1774 # Make nice annotations for the viewer. 1775 1776 while_._test_call = subprogram.code[0].test 1777 1778 return result 1779 1780 # NOTE: Not actually supported. 1781 # NOTE: Virtually the same as visitReturn... 1782 1783 def visitYield(self, yield_): 1784 result = Yield(yield_, 1, 1785 expr=self.dispatch(yield_.value) 1786 ) 1787 return result 1788 1789 # Convenience methods. 1790 1791 def _visitBinary(self, binary, left_name, right_name): 1792 return self._visitBinaryOp(binary, self.dispatch(binary.left), self.dispatch(binary.right), left_name, right_name) 1793 1794 def _visitBinaryCompareOp(self, binary, left, right, left_name, right_name): 1795 1796 """ 1797 Emulate the current mechanisms by producing nodes as follows: 1798 1799 InvokeRef -> Subprogram -> StoreTemp (expr) -> x.__lt__(y) 1800 Conditional (test) -> __is__(LoadTemp, NotImplemented) 1801 (body) -> ReleaseTemp 1802 StoreTemp (expr) -> y.__gt__(x) 1803 Conditional (test) -> __is__(LoadTemp, NotImplemented) 1804 (body) -> ReturnFromBlock (expr) -> False 1805 (else) -> ReturnFromBlock (expr) -> LoadTemp 1806 (else) -> ReturnFromBlock (expr) -> LoadTemp 1807 """ 1808 1809 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) 1810 self.current_subprograms.append(subprogram) 1811 1812 subprogram.code = [ 1813 StoreTemp( 1814 expr=left, 1815 index="left" 1816 ), 1817 StoreTemp( 1818 expr=right, 1819 index="right" 1820 ), 1821 StoreTemp( 1822 expr=InvokeFunction( 1823 binary, 1824 expr=LoadAttr( 1825 expr=LoadTemp(index="left"), 1826 name=left_name), 1827 args=[ 1828 LoadTemp(index="right") 1829 ], 1830 star=None, 1831 dstar=None) 1832 ), 1833 Conditional( 1834 isolate_test=1, 1835 test=CheckType( 1836 expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")] 1837 ), 1838 body=[ 1839 ReleaseTemp(), 1840 StoreTemp( 1841 expr=InvokeFunction( 1842 binary, 1843 expr=LoadAttr( 1844 expr=LoadTemp(index="right"), 1845 name=right_name), 1846 args=[ 1847 LoadTemp(index="left") 1848 ], 1849 star=None, 1850 dstar=None) 1851 ), 1852 Conditional( 1853 isolate_test=1, 1854 test=CheckType( 1855 expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")] 1856 ), 1857 body=[ 1858 ReturnFromBlock( 1859 expr=LoadName(name="False") 1860 ) 1861 ], 1862 else_=[ 1863 CheckType( 1864 inverted=1, expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")] 1865 ), 1866 ReturnFromBlock( 1867 expr=LoadTemp() 1868 ) 1869 ] 1870 ) 1871 ], 1872 else_=[ 1873 CheckType( 1874 inverted=1, expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")] 1875 ), 1876 ReturnFromBlock( 1877 expr=LoadTemp() 1878 ) 1879 ] 1880 ) 1881 ] 1882 1883 self.current_subprograms.pop() 1884 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1885 1886 result = InvokeRef( 1887 binary, 1888 produces_result=1, 1889 ref=subprogram 1890 ) 1891 1892 # Make nice annotations for the viewer. 1893 1894 binary._left_call = subprogram.code[2].expr 1895 binary._right_call = subprogram.code[3].body[1].expr 1896 1897 return result 1898 1899 def _visitBinaryOp(self, binary, left, right, left_name, right_name): 1900 1901 """ 1902 Emulate the current mechanisms by producing nodes as follows: 1903 1904 InvokeRef -> Subprogram -> Try (body) -> ReturnFromBlock (expr) -> x.__add__(y) 1905 (else) 1906 (handler) -> Conditional (test) -> CheckType (expr) -> LoadExc 1907 (choices) -> LoadName TypeError 1908 (body) -> ReturnFromBlock (expr) -> y.__radd__(x) 1909 (else) 1910 """ 1911 1912 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) 1913 self.current_subprograms.append(subprogram) 1914 1915 subprogram.code = [ 1916 StoreTemp( 1917 expr=left, 1918 index="left" 1919 ), 1920 StoreTemp( 1921 expr=right, 1922 index="right" 1923 ), 1924 Try(binary, 1, 1925 body=[ 1926 ReturnFromBlock( 1927 expr=InvokeFunction( 1928 binary, 1929 expr=LoadAttr(expr=LoadTemp(index="left"), name=left_name), 1930 args=[LoadTemp(index="right")], 1931 star=None, 1932 dstar=None) 1933 ) 1934 ], 1935 else_=[], 1936 finally_=[], 1937 handler=[ 1938 Conditional( 1939 test=CheckType(expr=LoadExc(), choices=[LoadName(name="TypeError")]), 1940 body=[ 1941 ReturnFromBlock( 1942 expr=InvokeFunction( 1943 binary, 1944 expr=LoadAttr(expr=LoadTemp(index="right"), name=right_name), 1945 args=[LoadTemp(index="left")], 1946 star=None, 1947 dstar=None) 1948 ) 1949 ], 1950 else_=[] 1951 ) 1952 ] 1953 ) 1954 ] 1955 1956 self.current_subprograms.pop() 1957 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1958 1959 result = InvokeRef( 1960 binary, 1961 produces_result=1, 1962 ref=subprogram 1963 ) 1964 1965 # Make nice annotations for the viewer. 1966 1967 binary._left_call = subprogram.code[2].body[0].expr 1968 binary._right_call = subprogram.code[2].handler[0].body[0].expr 1969 1970 return result 1971 1972 def _visitBuiltin(self, builtin, name): 1973 result = InvokeFunction(builtin, 1, expr=LoadName(name=name), args=self.dispatches(builtin.nodes)) 1974 return result 1975 1976 def _visitUnary(self, unary, name): 1977 result = InvokeFunction(unary, 1, 1978 expr=LoadAttr( 1979 expr=self.dispatch(unary.expr), 1980 name=name 1981 ) 1982 ) 1983 1984 # Make nice annotations for the viewer. 1985 1986 unary._unary_call = result 1987 1988 return result 1989 1990 # Convenience functions. 1991 1992 def simplify(filename, builtins=0, module_name=None): 1993 1994 """ 1995 Simplify the module stored in the file with the given 'filename'. 1996 1997 If the optional 'builtins' parameter is set to a true value (the default 1998 being a false value), then the module is considered as the builtins module. 1999 """ 2000 2001 simplifier = Simplifier(builtins) 2002 module = compiler.parseFile(filename) 2003 compiler.misc.set_filename(filename, module) 2004 if builtins: 2005 name = module_name or "__builtins__" 2006 else: 2007 path, ext = os.path.splitext(filename) 2008 path, name = os.path.split(path) 2009 name = module_name or name 2010 simplified = simplifier.process(module, name) 2011 return simplified 2012 2013 # vim: tabstop=4 expandtab shiftwidth=4