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