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