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 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 44 class Simplifier(Visitor): 45 46 """ 47 A simplifying visitor for AST nodes. 48 49 Covered: And, AssAttr, AssList, AssName, AssTuple, Assign, AugAssign, Break, 50 CallFunc, Class, Compare, Const, Continue, Dict, Discard, For, 51 From, Function, Getattr, Global, If, Import, Invert, Keyword, 52 Lambda, List, Module, Name, Not, Or, Pass, Raise, Return, Slice, 53 Stmt, Subscript, TryExcept, TryFinally, Tuple, While, UnaryAdd, 54 UnarySub. 55 56 Missing: Add, Assert, Backquote, Bitand, Bitor, Bitxor, Decorators, Div, 57 Ellipsis, Exec, FloorDiv, LeftShift, ListComp, ListCompFor, 58 ListCompIf, Mod, Mul, Power, Print, Printnl, RightShift, Sliceobj, 59 Sub, 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.builtins = builtins # Whether the builtins are being processed. 76 77 # Convenience attributes. 78 79 self.subnames = {} 80 81 # For compiler package mechanisms. 82 83 self.visitor = self 84 85 def process(self, node): 86 result = self.dispatch(node) 87 result.simplifier = self 88 return result 89 90 def dispatch_or_none(self, node, *args): 91 if node is not None: 92 return self.dispatch(node, *args) 93 else: 94 return LoadName(node, name="None") 95 96 # Placeholder or deletion transformations. 97 98 def visitStmt(self, stmt): 99 return self.dispatches(stmt.nodes) 100 101 def visitPass(self, pass_): 102 return Pass(pass_, 1) 103 104 def visitDiscard(self, discard): 105 return self.dispatch(discard.expr) 106 107 # Relatively trivial transformations. 108 109 def visitModule(self, module): 110 111 """ 112 Process the given 'module', producing a Module object which contains the 113 resulting program nodes. 114 """ 115 116 result = Module(module, 1, name="module") 117 module_code = self.dispatch(module.node) 118 119 # NOTE: Constant initialisation necessary for annotation but perhaps 120 # NOTE: redundant in the program. 121 122 init_code = [] 123 for value, constant in self.constants.items(): 124 init_code.append( 125 StoreAttr(module, 126 lvalue=LoadRef(module, ref=constant), 127 name="__class__", 128 expr=LoadName(module, name=constant.typename) 129 ) 130 ) 131 132 # NOTE: Hack to ensure correct initialisation of constants. 133 134 if self.builtins: 135 result.code = module_code + init_code 136 else: 137 result.code = init_code + module_code 138 return result 139 140 def visitGetattr(self, getattr): 141 result = LoadAttr(getattr, 1, 142 name=getattr.attrname, 143 expr=self.dispatch(getattr.expr) 144 ) 145 return result 146 147 def visitKeyword(self, keyword): 148 result = Keyword(keyword, 1, 149 name=keyword.name, 150 expr=self.dispatch(keyword.expr) 151 ) 152 return result 153 154 def visitGlobal(self, global_): 155 result = Global(global_, 1, 156 names=global_.names 157 ) 158 return result 159 160 def visitImport(self, import_): 161 result = Assign(import_, 1) 162 code = [] 163 for path, alias in import_.names: 164 importer = Import(import_, name=path) 165 top = alias or path.split(".")[0] 166 code.append(StoreName(import_, expr=importer, name=top)) 167 result.code = code 168 return result 169 170 def visitFrom(self, from_): 171 result = Assign(from_, 1) 172 code = [] 173 code.append(StoreTemp(from_, expr=Import(from_, name=from_.modname))) 174 for name, alias in from_.names: 175 code.append( 176 StoreName(from_, 177 expr=LoadAttr(from_, 178 expr=LoadTemp(from_), 179 name=name), 180 name=(alias or name) 181 ) 182 ) 183 code.append(ReleaseTemp(from_)) 184 result.code = code 185 return result 186 187 def visitName(self, name): 188 result = LoadName(name, 1, name=name.name) 189 return result 190 191 def visitConst(self, const): 192 if not self.constants.has_key(const.value): 193 self.constants[const.value] = Constant(const, name=repr(const.value), value=const.value) 194 result = LoadRef(const, 1, ref=self.constants[const.value]) 195 return result 196 197 def visitReturn(self, return_): 198 result = Return(return_, 1, 199 expr=self.dispatch(return_.value) 200 ) 201 return result 202 203 def visitBreak(self, break_): 204 result = Return(break_, 1) 205 return result 206 207 def visitContinue(self, continue_): 208 result = InvokeBlock(continue_, 1, 209 expr=LoadRef(continue_, ref=self.current_subprograms[-1]) 210 ) 211 return result 212 213 def visitRaise(self, raise_): 214 result = Raise(raise_, 1, expr=self.dispatch(raise_.expr1), traceback=None) 215 if raise_.expr2 is not None: 216 result.args = [self.dispatch(raise_.expr2)] 217 if raise_.expr3 is not None: 218 result.traceback = self.dispatch(raise_.expr3) 219 return result 220 221 def _visitBuiltin(self, builtin, name): 222 result = InvokeFunction(builtin, 1, expr=LoadName(builtin, name=name), args=self.dispatches(builtin.nodes), star=None, dstar=None) 223 return result 224 225 def visitTuple(self, tuple): 226 return self._visitBuiltin(tuple, "tuple") 227 228 def visitList(self, list): 229 return self._visitBuiltin(list, "list") 230 231 def visitDict(self, dict): 232 result = InvokeFunction(dict, 1, expr=LoadName(dict, name="dict"), star=None, dstar=None) 233 args = [] 234 for key, value in dict.items: 235 tuple = InvokeFunction(dict, expr=LoadName(dict, name="tuple"), star=None, dstar=None) 236 tuple.set_args([self.dispatch(key), self.dispatch(value)]) 237 args.append(tuple) 238 result.set_args(args) 239 return result 240 241 # Logical and comparison operations plus chained statements. 242 243 def visitIf(self, if_): 244 245 """ 246 Make conditionals for each test from an 'if_' AST node, adding the body 247 and putting each subsequent test as part of the conditional's else 248 section. 249 250 Convert... 251 252 If (test/body) 253 (test/body) 254 ... 255 (else/body) 256 257 ...to: 258 259 Conditional (test) -> (body) 260 (else) -> Conditional (test) -> (body) 261 (else) -> ... 262 """ 263 264 265 results = nodes = [] 266 267 # Produce something like... 268 # expr.__true__() ? body 269 270 first = 1 271 for compare, stmt in if_.tests: 272 273 # Set the first as the defining node. 274 275 test = Conditional(if_, first, 276 test=InvokeFunction(if_, 277 expr=LoadAttr(if_, 278 expr=self.dispatch(compare), 279 name="__true__" 280 ), 281 args=[], 282 star=None, 283 dstar=None) 284 ) 285 test.body = self.dispatch(stmt) 286 nodes.append(test) 287 nodes = test.else_ = [] 288 first = 0 289 290 # Add the compound statement from any else clause to the end. 291 292 if if_.else_ is not None: 293 nodes += self.dispatch(if_.else_) 294 295 result = results[0] 296 return result 297 298 def visitTryExcept(self, tryexcept): 299 300 """ 301 Make conditionals for each handler associated with a 'tryexcept' node. 302 303 Convert... 304 305 TryExcept (body) 306 (else) 307 (spec/assign/stmt) 308 ... 309 310 ...to: 311 312 Try (body) 313 (else) 314 (handler) -> Conditional (test) -> (stmt) 315 (body) -> ... 316 (else) -> Conditional (test) -> (stmt) 317 (body) -> ... 318 (else) -> ... 319 """ 320 321 result = Try(tryexcept, 1, body=[], else_=[], finally_=[]) 322 323 if tryexcept.body is not None: 324 result.body = self.dispatch(tryexcept.body) 325 if tryexcept.else_ is not None: 326 result.else_ = self.dispatch(tryexcept.else_) 327 328 results = nodes = [] 329 for spec, assign, stmt in tryexcept.handlers: 330 331 # If no specification exists, produce an unconditional block. 332 333 if spec is None: 334 nodes += self.dispatch(stmt) 335 336 # Produce something like... 337 # isinstance(<exc>, <spec>) 338 339 else: 340 new_spec = self.dispatch(spec) 341 test = Conditional(tryexcept, 342 test=InvokeFunction(tryexcept, 343 expr=LoadName(tryexcept, name="isinstance"), 344 args=[LoadExc(tryexcept), new_spec], 345 star=None, 346 dstar=None) 347 ) 348 test.body = [] 349 350 if assign is not None: 351 test.body.append( 352 Assign(tryexcept, 353 code=[ 354 StoreTemp(expr=LoadExc(tryexcept)), 355 self.dispatch(assign), 356 ReleaseTemp(tryexcept) 357 ] 358 ) 359 ) 360 361 # Always return from conditional sections. 362 363 test.body += self.dispatch(stmt) + [Return(tryexcept)] 364 nodes.append(test) 365 nodes = test.else_ = [] 366 367 # Add a raise operation to deal with unhandled exceptions. 368 369 nodes.append( 370 Raise(tryexcept, 371 expr=LoadExc(tryexcept)) 372 ) 373 374 result.handler = results 375 return result 376 377 comparison_methods = { 378 "==" : "__eq__", "!=" : "__ne__", "<" : "__lt__", "<=" : "__le__", 379 ">=" : "__ge__", ">" : "__gt__", "is" : None, "is not" : None 380 } 381 382 def visitCompare(self, compare): 383 384 """ 385 Make a subprogram for the 'compare' node and record its contents inside 386 the subprogram. Convert... 387 388 Compare (expr) 389 (name/node) 390 ... 391 392 ...to: 393 394 Subprogram -> Conditional (test) -> (body) 395 (else) -> Conditional (test) -> (body) 396 (else) -> ... 397 """ 398 399 subprogram = Subprogram(compare, name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 400 self.current_subprograms.append(subprogram) 401 402 # In the subprogram, make instructions which invoke a method on the 403 # first operand of each operand pair and, if appropriate, return with 404 # the value from that method. 405 406 last = compare.ops[-1] 407 previous = self.dispatch(compare.expr) 408 results = nodes = [] 409 410 for op in compare.ops: 411 op_name, node = op 412 expr = self.dispatch(node) 413 414 # Identify the operation and produce the appropriate method call. 415 416 method_name = self.comparison_methods[op_name] 417 if method_name: 418 invocation = InvokeFunction(compare, 419 expr=LoadAttr(compare, 420 expr=previous, 421 name=method_name), 422 args=[expr], 423 star=None, 424 dstar=None) 425 426 elif op_name == "is": 427 invocation = InvokeFunction(compare, 428 expr=LoadName(compare, name="__is__"), 429 args=[previous, expr], 430 star=None, 431 dstar=None) 432 433 elif op_name == "is not": 434 invocation = Not(compare, 435 expr=InvokeFunction(compare, 436 expr=LoadName(compare, name="__is__"), 437 args=[previous, expr], 438 star=None, 439 dstar=None) 440 ) 441 else: 442 raise NotImplementedError, op_name 443 444 nodes.append(StoreTemp(compare, expr=invocation)) 445 446 # Return from the subprogram where the test is not satisfied. 447 448 if op is not last: 449 nodes.append( 450 Conditional(compare, 451 test=Not(compare, expr=LoadTemp(compare)), 452 body=[Return(compare, expr=LoadTemp(compare))]) 453 ) 454 455 # Put subsequent operations in the else section of this conditional. 456 457 nodes = test.else_ = [ReleaseTemp(compare)] 458 459 # For the last operation, return the result. 460 461 else: 462 nodes.append( 463 Return(compare, expr=LoadTemp(compare, release=1)) 464 ) 465 466 previous = expr 467 468 # Finish the subprogram definition. 469 470 subprogram.code = results 471 472 self.current_subprograms.pop() 473 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 474 475 # Make an invocation of the subprogram. 476 477 result = InvokeBlock(compare, 1, produces_result=1) 478 result.expr = LoadRef(compare, ref=subprogram) 479 return result 480 481 def visitAnd(self, and_): 482 483 """ 484 Make a subprogram for the 'and_' node and record its contents inside the 485 subprogram. Convert... 486 487 And (test) 488 (test) 489 ... 490 491 ...to: 492 493 Subprogram -> Conditional (test) -> Return ... 494 (else) -> Conditional (test) -> Return ... 495 (else) -> ... 496 """ 497 498 subprogram = Subprogram(and_, name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 499 self.current_subprograms.append(subprogram) 500 501 # In the subprogram, make instructions which store each operand, test 502 # for each operand's truth status, and if appropriate return from the 503 # subprogram with the value of the operand. 504 505 last = and_.nodes[-1] 506 results = nodes = [] 507 508 for node in and_.nodes: 509 expr = self.dispatch(node) 510 511 # Return from the subprogram where the test is not satisfied. 512 513 if node is not last: 514 nodes.append(StoreTemp(and_, expr=expr)) 515 invocation = InvokeFunction(and_, expr=LoadAttr(and_, expr=LoadTemp(and_), name="__true__"), args=[], star=None, dstar=None) 516 test = Conditional(and_, test=Not(and_, expr=invocation), body=[Return(and_, expr=LoadTemp(and_))]) 517 nodes.append(test) 518 519 # Put subsequent operations in the else section of this conditional. 520 521 nodes = test.else_ = [ReleaseTemp(and_)] 522 523 # For the last operation, return the result. 524 525 else: 526 nodes.append(Return(and_, expr=expr)) 527 528 # Finish the subprogram definition. 529 530 subprogram.code = results 531 532 self.current_subprograms.pop() 533 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 534 535 # Make an invocation of the subprogram. 536 537 result = InvokeBlock(and_, 1, produces_result=1) 538 result.expr = LoadRef(and_, ref=subprogram) 539 return result 540 541 def visitOr(self, or_): 542 543 """ 544 Make a subprogram for the 'or_' node and record its contents inside the 545 subprogram. Convert... 546 547 Or (test) 548 (test) 549 ... 550 551 ...to: 552 553 Subprogram -> Conditional (test) -> Return ... 554 (else) -> Conditional (test) -> Return ... 555 (else) -> ... 556 """ 557 558 subprogram = Subprogram(or_, name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 559 self.current_subprograms.append(subprogram) 560 561 # In the subprogram, make instructions which store each operand, test 562 # for each operand's truth status, and if appropriate return from the 563 # subprogram with the value of the operand. 564 565 last = or_.nodes[-1] 566 results = nodes = [] 567 568 for node in or_.nodes: 569 expr = self.dispatch(node) 570 571 # Return from the subprogram where the test is satisfied. 572 573 if node is not last: 574 nodes.append(StoreTemp(or_, expr=expr)) 575 invocation = InvokeFunction(or_, expr=LoadAttr(or_, expr=LoadTemp(or_), name="__true__"), args=[], star=None, dstar=None) 576 test = Conditional(or_, test=invocation, body=[Return(or_, expr=LoadTemp(or_))]) 577 nodes.append(test) 578 579 # Put subsequent operations in the else section of this conditional. 580 581 nodes = test.else_ = [ReleaseTemp(or_)] 582 583 # For the last operation, return the result. 584 585 else: 586 nodes.append( 587 Return(or_, expr=expr) 588 ) 589 590 # Finish the subprogram definition. 591 592 subprogram.code = results 593 594 self.current_subprograms.pop() 595 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 596 597 # Make an invocation of the subprogram. 598 599 result = InvokeBlock(or_, 1, produces_result=1) 600 result.expr = LoadRef(or_, ref=subprogram) 601 return result 602 603 def visitNot(self, not_): 604 result = Not(not_, 1, expr=InvokeFunction(not_, expr=LoadAttr(not_, expr=self.dispatch(not_.expr), name="__true__"), args=[], star=None, dstar=None)) 605 return result 606 607 # Operators. 608 609 def visitUnaryAdd(self, unaryadd): 610 return InvokeFunction(unaryadd, 1, expr=LoadAttr(unaryadd, expr=self.dispatch(unaryadd.expr), name="__pos__"), args=[], star=None, dstar=None) 611 612 def visitUnarySub(self, unarysub): 613 return InvokeFunction(unarysub, 1, expr=LoadAttr(unarysub, expr=self.dispatch(unarysub.expr), name="__neg__"), args=[], star=None, dstar=None) 614 615 def visitInvert(self, invert): 616 return InvokeFunction(invert, 1, expr=LoadAttr(invert, expr=self.dispatch(invert.expr), name="__invert__"), args=[], star=None, dstar=None) 617 618 def visitAdd(self, add): 619 620 """ 621 Emulate the current mechanisms by producing nodes as follows: 622 623 Try (body) -> x.__add__(y) 624 (else) 625 (handler) -> Conditional (test) -> isinstance(exc, TypeError) 626 (body) -> y.__radd__(x) 627 (else) 628 """ 629 630 result = Try(add, 1, 631 body=[ 632 InvokeFunction(add, 633 expr=LoadAttr(add, expr=self.dispatch(add.left), name="__add__"), 634 args=[self.dispatch(add.right)], 635 star=None, 636 dstar=None) 637 ], 638 else_=[], 639 finally_=[], 640 handler=[ 641 Conditional(add, 642 test=InvokeFunction(add, 643 expr=LoadName(add, name="isinstance"), 644 args=[LoadExc(add), LoadName(add, name="TypeError")], 645 star=None, 646 dstar=None), 647 body=[ 648 InvokeFunction(add, 649 expr=LoadAttr(add, expr=self.dispatch(add.right), name="__radd__"), 650 args=[self.dispatch(add.left)], 651 star=None, 652 dstar=None) 653 ], 654 else_=[] 655 ) 656 ] 657 ) 658 659 return result 660 661 # Assignments. 662 663 augassign_methods = { 664 "+=" : "__iadd__", "-=" : "__isub__", "*=" : "__imul__", "/=" : "__idiv__", 665 "%=" : "__imod__", "**=" : "__ipow__", "<<=" : "__ilshift__", ">>=" : "__irshift__", 666 "&=" : "__iand__", "^=" : "__ixor__", "|=" : "__ior__" 667 } 668 669 def visitAugAssign(self, augassign): 670 result = Assign(augassign, 1) 671 expr = self.dispatch(augassign.expr) 672 673 # Simple augmented assignment: name += expr 674 675 if isinstance(augassign.node, compiler.ast.Name): 676 result.code = [ 677 StoreTemp(augassign, 678 expr=InvokeFunction(augassign, 679 args=[expr], 680 star=None, 681 dstar=None, 682 expr=LoadAttr(augassign, 683 expr=self.dispatch(augassign.node), 684 name=self.augassign_methods[augassign.op] 685 ) 686 ) 687 ), 688 StoreName(augassign, 689 expr=LoadTemp(augassign), 690 name=augassign.node.name), 691 ReleaseTemp(augassign) 692 ] 693 694 # Complicated augmented assignment: lvalue.attr += expr 695 696 elif isinstance(augassign.node, compiler.ast.Getattr): 697 698 # <lvalue> -> setattr(<lvalue>, getattr(<lvalue>, "attr").__xxx__(expr)) 699 700 result.code = [ 701 StoreTemp(augassign, 702 index="expr", 703 expr=self.dispatch(augassign.node.expr) 704 ), 705 StoreTemp(augassign, 706 expr=InvokeFunction(augassign, 707 args=[expr], star=None, dstar=None, 708 expr=LoadAttr(augassign, 709 expr=LoadAttr(augassign, 710 expr=LoadTemp(augassign, index="expr"), 711 name=augassign.node.attrname 712 ), 713 name=self.augassign_methods[augassign.op] 714 ) 715 ) 716 ), 717 StoreAttr(augassign, 718 expr=LoadTemp(augassign), 719 lvalue=LoadTemp(augassign, index="expr"), 720 name=augassign.node.attrname 721 ), 722 ReleaseTemp(augassign, index="expr"), 723 ReleaseTemp(augassign) 724 ] 725 726 # Complicated augassign using slices: lvalue[lower:upper] += expr 727 728 elif isinstance(augassign.node, compiler.ast.Slice): 729 730 # <lvalue>, <lower>, <upper> -> <lvalue>.__setslice__(<lower>, <upper>, <lvalue>.__getslice__(<lower>, <upper>).__xxx__(expr)) 731 732 result.code = [ 733 StoreTemp(augassign, 734 index="expr", 735 expr=self.dispatch(augassign.node.expr) 736 ), 737 StoreTemp(augassign, 738 index="lower", 739 expr=self.dispatch_or_none(augassign.node.lower) 740 ), 741 StoreTemp(augassign, 742 index="upper", 743 expr=self.dispatch_or_none(augassign.node.upper) 744 ), 745 StoreTemp(augassign, 746 expr=InvokeFunction(augassign, 747 args=[expr], star=None, dstar=None, 748 expr=LoadAttr(augassign, 749 expr=self._visitSlice( 750 augassign.node, 751 LoadTemp(augassign, index="expr"), 752 LoadTemp(augassign, index="lower"), 753 LoadTemp(augassign, index="upper"), 754 "OP_APPLY"), 755 name=self.augassign_methods[augassign.op] 756 ) 757 ) 758 ), 759 self._visitSlice( 760 augassign.node, 761 LoadTemp(augassign, index="expr"), 762 LoadTemp(augassign, index="lower"), 763 LoadTemp(augassign, index="upper"), 764 "OP_ASSIGN", 765 LoadTemp(augassign) 766 ), 767 ReleaseTemp(augassign, index="expr"), 768 ReleaseTemp(augassign, index="lower"), 769 ReleaseTemp(augassign, index="upper"), 770 ReleaseTemp(augassign) 771 ] 772 773 # Complicated augassign using subscripts: lvalue[subs] += expr 774 775 elif isinstance(augassign.node, compiler.ast.Subscript): 776 777 # <lvalue>, <subs> -> <lvalue>.__setitem__(<subs>, <lvalue>.__getitem__(<subs>).__xxx__(expr)) 778 779 result.code = [ 780 StoreTemp(augassign, index="expr", expr=self.dispatch(augassign.node.expr)), 781 StoreTemp(augassign, index="subs", expr=self._visitSubscriptSubs(augassign.node, augassign.node.subs)), 782 StoreTemp(augassign, 783 expr=InvokeFunction(augassign, 784 args=[expr], star=None, dstar=None, 785 expr=LoadAttr(augassign, 786 expr=self._visitSubscript( 787 augassign.node, 788 LoadTemp(augassign, index="expr"), 789 LoadTemp(augassign, index="subs"), 790 "OP_APPLY" 791 ), 792 name=self.augassign_methods[augassign.op] 793 ) 794 ) 795 ), 796 self._visitSubscript( 797 augassign.node, 798 LoadTemp(augassign, index="expr"), 799 LoadTemp(augassign, index="subs"), 800 "OP_ASSIGN", 801 LoadTemp(augassign) 802 ), 803 ReleaseTemp(augassign, index="expr"), 804 ReleaseTemp(augassign, index="subs"), 805 ReleaseTemp(augassign) 806 ] 807 808 else: 809 raise NotImplementedError, augassign.node.__class__ 810 811 return result 812 813 def visitAssign(self, assign): 814 result = Assign(assign, 1) 815 store = StoreTemp(assign, expr=self.dispatch(assign.expr)) 816 release = ReleaseTemp(assign) 817 result.code = [store] + self.dispatches(assign.nodes, 0) + [release] 818 return result 819 820 def visitAssList(self, asslist, in_sequence=0): 821 if not in_sequence: 822 expr = LoadTemp(asslist) 823 else: 824 expr = InvokeFunction(asslist, expr=LoadAttr(asslist, expr=LoadTemp(asslist), name="next"), star=None, dstar=None, args=[]) 825 result = Assign(asslist, 1) 826 store = StoreTemp(asslist, expr=InvokeFunction(asslist, expr=LoadAttr(asslist, name="__iter__", expr=expr), star=None, dstar=None, args=[])) 827 release = ReleaseTemp(asslist) 828 result.code = [store] + self.dispatches(asslist.nodes, 1) + [release] 829 return result 830 831 visitAssTuple = visitAssList 832 833 def _visitAssNameOrAttr(self, node, in_sequence): 834 if not in_sequence: 835 return LoadTemp(node) 836 else: 837 return InvokeFunction(node, expr=LoadAttr(node, expr=LoadTemp(node), name="next"), star=None, dstar=None, args=[]) 838 839 def visitAssName(self, assname, in_sequence=0): 840 expr = self._visitAssNameOrAttr(assname, in_sequence) 841 result = StoreName(assname, 1, name=assname.name, expr=expr) 842 return result 843 844 def visitAssAttr(self, assattr, in_sequence=0): 845 expr = self._visitAssNameOrAttr(assattr, in_sequence) 846 lvalue = self.dispatch(assattr.expr) 847 result = StoreAttr(assattr, 1, name=assattr.attrname, lvalue=lvalue, expr=expr) 848 return result 849 850 def _visitSlice(self, slice, expr, lower, upper, flags, value=None): 851 if flags == "OP_ASSIGN": 852 args = [value] 853 result = InvokeFunction(slice, 1, expr=LoadAttr(slice, expr=expr, name="__setslice__"), star=None, dstar=None, args=[]) 854 elif flags == "OP_APPLY": 855 args = [] 856 result = InvokeFunction(slice, 1, expr=LoadAttr(slice, expr=expr, name="__getslice__"), star=None, dstar=None, args=[]) 857 elif flags == "OP_DELETE": 858 args = [] 859 result = InvokeFunction(slice, 1, expr=LoadAttr(slice, expr=expr, name="__delslice__"), star=None, dstar=None, args=[]) 860 else: 861 raise NotImplementedError, flags 862 863 # Add the dimensions. 864 865 args.insert(0, lower) 866 args.insert(1, upper) 867 868 result.original = slice 869 result.set_args(args) 870 return result 871 872 def visitSlice(self, slice, in_sequence=0): 873 return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower), 874 self.dispatch_or_none(slice.upper), slice.flags, self._visitAssNameOrAttr(slice, in_sequence)) 875 876 def _visitSubscript(self, subscript, expr, subs, flags, value=None): 877 if flags == "OP_ASSIGN": 878 args = [value] 879 result = InvokeFunction(subscript, 1, expr=LoadAttr(subscript, expr=expr, name="__setitem__"), star=None, dstar=None, args=[]) 880 elif flags == "OP_APPLY": 881 args = [] 882 result = InvokeFunction(subscript, 1, expr=LoadAttr(subscript, expr=expr, name="__getitem__"), star=None, dstar=None, args=[]) 883 elif flags == "OP_DELETE": 884 args = [] 885 result = InvokeFunction(subscript, 1, expr=LoadAttr(subscript, expr=expr, name="__delitem__"), star=None, dstar=None, args=[]) 886 else: 887 raise NotImplementedError, flags 888 889 # Add the dimensions. 890 891 args.insert(0, subs) 892 893 result.original = subscript 894 result.set_args(args) 895 return result 896 897 def _visitSubscriptSubs(self, node, subs): 898 if len(subs) == 1: 899 return self.dispatch(subs[0]) 900 else: 901 return InvokeFunction(node, 1, 902 expr=LoadName(node, name="tuple"), 903 args=self.dispatches(subs), 904 star=None, 905 dstar=None) 906 907 def visitSubscript(self, subscript, in_sequence=0): 908 return self._visitSubscript( 909 subscript, self.dispatch(subscript.expr), self._visitSubscriptSubs(subscript, subscript.subs), subscript.flags, 910 self._visitAssNameOrAttr(subscript, in_sequence) 911 ) 912 913 # Invocation and subprogram transformations. 914 915 def visitClass(self, class_): 916 structure = Class(class_, name=class_.name, bases=self.dispatches(class_.bases)) 917 self.structures.append(structure) 918 919 # Make a subprogram which initialises the class structure. 920 921 subprogram = Subprogram(class_, name=None, structure=structure, params=[], star=None, dstar=None) 922 self.current_subprograms.append(subprogram) 923 924 # The class is initialised using the code found inside. 925 926 subprogram.code = self.dispatch(class_.code) + [Return(class_)] 927 928 self.current_subprograms.pop() 929 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 930 931 # Make a definition of the class associating it with a name. 932 933 result = Assign(class_, 934 code=[ 935 StoreName(class_, 1, # defines the class 936 name=class_.name, 937 expr=LoadRef(class_, ref=structure) 938 ), 939 InvokeBlock(class_, 940 expr=LoadRef(class_, ref=subprogram) 941 ) 942 ] 943 ) 944 return result 945 946 def _visitFunction(self, function, subprogram): 947 948 """ 949 A common function generator which transforms the given 'function' node 950 and initialises the given 'subprogram' appropriately. 951 """ 952 953 # Discover star and dstar parameters. 954 955 if function.flags & 4 != 0: 956 has_star = 1 957 else: 958 has_star = 0 959 if function.flags & 8 != 0: 960 has_dstar = 1 961 else: 962 has_dstar = 0 963 964 # Discover the number of defaults and positional parameters. 965 966 ndefaults = len(function.defaults) 967 npositional = len(function.argnames) - has_star - has_dstar 968 969 # Produce star and dstar parameters with appropriate defaults. 970 971 if has_star: 972 star = ( 973 function.argnames[npositional], 974 InvokeFunction(function, expr=LoadName(function, name="list"), args=[], star=None, dstar=None) 975 ) 976 else: 977 star = None 978 if has_dstar: 979 dstar = ( 980 function.argnames[npositional + has_star], 981 InvokeFunction(function, expr=LoadName(function, name="dict"), args=[], star=None, dstar=None) 982 ) 983 else: 984 dstar = None 985 986 params = [] 987 for i in range(0, npositional - ndefaults): 988 params.append((function.argnames[i], None)) 989 990 # NOTE: Fix/process defaults. 991 992 for i in range(0, ndefaults): 993 default = function.defaults[i] 994 if default is not None: 995 params.append((function.argnames[npositional - ndefaults + i], self.dispatch(default))) 996 else: 997 params.append((function.argnames[npositional - ndefaults + i], default)) 998 999 subprogram.params = params 1000 subprogram.star = star 1001 subprogram.dstar = dstar 1002 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1003 1004 def visitFunction(self, function): 1005 1006 # Make a subprogram for the function and record it outside the main 1007 # tree. 1008 1009 subprogram = Subprogram(function, name=function.name, acquire_locals=0, returns_value=1, star=None, dstar=None) 1010 self.current_subprograms.append(subprogram) 1011 subprogram.code = self.dispatch(function.code) + [Return(function)] 1012 self.current_subprograms.pop() 1013 self._visitFunction(function, subprogram) 1014 1015 # Make a definition of the function associating it with a name. 1016 1017 result = StoreName(function, 1, name=function.name, expr=LoadRef(function, ref=subprogram)) 1018 return result 1019 1020 def visitLambda(self, lambda_): 1021 1022 # Make a subprogram for the function and record it outside the main 1023 # tree. 1024 1025 subprogram = Subprogram(lambda_, name=None, acquire_locals=0, returns_value=1, star=None, dstar=None) 1026 self.current_subprograms.append(subprogram) 1027 subprogram.code = [Return(lambda_, expr=self.dispatch(lambda_.code))] 1028 self.current_subprograms.pop() 1029 self._visitFunction(lambda_, subprogram) 1030 1031 # Get the subprogram reference to the lambda. 1032 1033 return LoadRef(lambda_, 1, ref=subprogram) 1034 1035 def visitCallFunc(self, callfunc): 1036 result = InvokeFunction(callfunc, 1, star=None, dstar=None, args=self.dispatches(callfunc.args)) 1037 if callfunc.star_args is not None: 1038 result.star = self.dispatch(callfunc.star_args) 1039 if callfunc.dstar_args is not None: 1040 result.dstar = self.dispatch(callfunc.dstar_args) 1041 result.expr = self.dispatch(callfunc.node) 1042 return result 1043 1044 def visitWhile(self, while_): 1045 1046 """ 1047 Make a subprogram for the 'while' node and record its contents inside the 1048 subprogram. Convert... 1049 1050 While (test) -> (body) 1051 (else) 1052 1053 ...to: 1054 1055 Subprogram -> Conditional (test) -> (body) -> Invoke subprogram 1056 (else) -> Conditional (test) -> Return ... 1057 (else) -> ... 1058 """ 1059 1060 subprogram = Subprogram(while_, name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 1061 self.current_subprograms.append(subprogram) 1062 1063 # Include a conditional statement in the subprogram. 1064 1065 test = Conditional(while_, else_=[]) 1066 test.test = InvokeFunction(while_, expr=LoadAttr(while_, expr=self.dispatch(while_.test), name="__true__"), args=[], star=None, dstar=None) 1067 1068 # Inside the conditional, add a recursive invocation to the subprogram 1069 # if the test condition was satisfied. 1070 1071 continuation = InvokeBlock(while_) 1072 continuation.expr = LoadRef(while_, ref=subprogram) 1073 1074 # Return within the main section of the loop. 1075 1076 test.body = self.dispatch(while_.body) + [continuation, Return(while_)] 1077 1078 # Provide the else section, if present, along with an explicit return. 1079 1080 if while_.else_ is not None: 1081 test.else_ = self.dispatch(while_.else_) + [Return(while_)] 1082 1083 # Finish the subprogram definition. 1084 1085 subprogram.code = [test] 1086 1087 self.current_subprograms.pop() 1088 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1089 1090 # Make an invocation of the subprogram. 1091 1092 result = InvokeBlock(while_, 1) 1093 result.expr = LoadRef(while_, ref=subprogram) 1094 return result 1095 1096 def visitFor(self, for_): 1097 1098 """ 1099 Make a subprogram for the 'for_' node and record its contents inside the 1100 subprogram. Convert... 1101 1102 For (assign) 1103 (body) 1104 (else) 1105 1106 ...to: 1107 1108 Assign (assign #1) 1109 Invoke -> Subprogram -> Try (body) -> (assign #2) 1110 (body) 1111 Invoke subprogram 1112 (handler) -> ... 1113 (else) -> ... 1114 """ 1115 1116 subprogram = Subprogram(for_, name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 1117 self.current_subprograms.append(subprogram) 1118 1119 # Always return from conditional sections/subprograms. 1120 1121 if for_.else_ is not None: 1122 else_stmt = self.dispatch(for_.else_) + [Return(for_)] 1123 else: 1124 else_stmt = [Return(for_)] 1125 1126 # Wrap the assignment in a try...except statement. 1127 1128 try_except = Try(for_, body=[], else_=[], finally_=[]) 1129 test = Conditional(for_, 1130 test=InvokeFunction(for_, 1131 expr=LoadName(for_, name="isinstance"), 1132 args=[LoadExc(for_), LoadName(for_, name="StopIteration")], 1133 star=None, 1134 dstar=None), 1135 body=else_stmt, 1136 else_=[Raise(for_, expr=LoadExc(for_))]) 1137 try_except.handler = [test] 1138 1139 assign = Assign(for_, 1140 code=[ 1141 StoreTemp(for_, expr=InvokeFunction(for_, expr=LoadAttr(for_, expr=LoadTemp(for_), name="next"), args=[], star=None, dstar=None)), 1142 self.dispatch(for_.assign), 1143 ReleaseTemp(for_) 1144 ]) 1145 1146 # Inside the conditional, add a recursive invocation to the subprogram 1147 # if the test condition was satisfied. 1148 1149 continuation = InvokeBlock(for_) 1150 continuation.expr = LoadRef(for_, ref=subprogram) 1151 try_except.body = [assign] + self.dispatch(for_.body) + [continuation] 1152 subprogram.code = [try_except, Return(for_)] 1153 1154 # Finish the subprogram definition. 1155 1156 self.current_subprograms.pop() 1157 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1158 1159 # Obtain an iterator for the sequence involved. 1160 # Then, make an invocation of the subprogram. 1161 1162 result = Assign(for_, 1) 1163 result.code = [ 1164 StoreTemp(for_, 1165 expr=InvokeFunction(for_, 1166 expr=LoadAttr(for_, 1167 name="__iter__", 1168 expr=self.dispatch(for_.list) 1169 ), 1170 args=[], 1171 star=None, 1172 dstar=None 1173 ) 1174 ), 1175 InvokeBlock(for_, expr=LoadRef(for_, ref=subprogram)), 1176 ReleaseTemp(for_) 1177 ] 1178 return result 1179 1180 # Exception node transformations. 1181 1182 def visitTryFinally(self, tryfinally): 1183 result = Try(tryfinally, 1, body=[], else_=[], finally_=[]) 1184 if tryfinally.body is not None: 1185 result.body = self.dispatch(tryfinally.body) 1186 if tryfinally.final is not None: 1187 result.finally_ = self.dispatch(tryfinally.final) 1188 return result 1189 1190 # Convenience functions. 1191 1192 def simplify(filename, builtins=0): 1193 1194 """ 1195 Simplify the module stored in the file with the given 'filename'. If the 1196 optional 'builtins' parameter is set to a true value (the default being a 1197 false value), then the module is considered as the builtins module. 1198 """ 1199 1200 simplifier = Simplifier(builtins) 1201 module = compiler.parseFile(filename) 1202 simplified = simplifier.process(module) 1203 compiler.misc.set_filename(filename, module) 1204 return simplified 1205 1206 # vim: tabstop=4 expandtab shiftwidth=4