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, expr=LoadAttr(compare, expr=previous, name=method_name), args=[expr], star=None, dstar=None) 408 elif op_name == "is": 409 invocation = InvokeFunction(compare, expr=LoadName(compare, name="__is__"), args=[previous, expr], star=None, dstar=None) 410 elif op_name == "is not": 411 invocation = Not(compare, expr=InvokeFunction(compare, expr=LoadName(compare, name="__is__"), args=[previous, expr], star=None, dstar=None)) 412 else: 413 raise NotImplementedError, op_name 414 nodes.append(StoreTemp(compare, expr=invocation)) 415 416 # Return from the subprogram where the test is not satisfied. 417 418 if op is not last: 419 test = Conditional(compare, test=Not(compare, expr=LoadTemp(compare)), body=[Return(compare, expr=LoadTemp(compare))]) 420 nodes.append(test) 421 422 # Put subsequent operations in the else section of this conditional. 423 424 nodes = test.else_ = [ReleaseTemp(compare)] 425 426 # For the last operation, return the result. 427 428 else: 429 nodes.append(Return(compare, expr=LoadTemp(compare))) 430 431 previous = expr 432 433 # Finish the subprogram definition. 434 435 subprogram.code = results 436 437 self.current_subprograms.pop() 438 self.subprograms.append(subprogram); self.subnames[subprogram.full_name] = subprogram 439 440 # Make an invocation of the subprogram. 441 442 result = InvokeBlock(compare, produces_result=1) 443 result.expr = LoadRef(compare, ref=subprogram) 444 return result 445 446 def visitAnd(self, and_): 447 448 """ 449 Make a subprogram for the 'and_' node and record its contents inside the 450 subprogram. Convert... 451 452 And (test) 453 (test) 454 ... 455 456 ...to: 457 458 Subprogram -> Conditional (test) -> Return ... 459 (else) -> Conditional (test) -> Return ... 460 (else) -> ... 461 """ 462 463 subprogram = Subprogram(and_, name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 464 self.current_subprograms.append(subprogram) 465 466 # In the subprogram, make instructions which store each operand, test 467 # for each operand's truth status, and if appropriate return from the 468 # subprogram with the value of the operand. 469 470 last = and_.nodes[-1] 471 results = nodes = [] 472 473 for node in and_.nodes: 474 expr = self.dispatch(node) 475 476 # Return from the subprogram where the test is not satisfied. 477 478 if node is not last: 479 nodes.append(StoreTemp(and_, expr=expr)) 480 invocation = InvokeFunction(and_, expr=LoadAttr(and_, expr=LoadTemp(and_), name="__true__"), args=[], star=None, dstar=None) 481 test = Conditional(and_, test=Not(and_, expr=invocation), body=[Return(and_, expr=LoadTemp(and_))]) 482 nodes.append(test) 483 484 # Put subsequent operations in the else section of this conditional. 485 486 nodes = test.else_ = [ReleaseTemp(and_)] 487 488 # For the last operation, return the result. 489 490 else: 491 nodes.append(Return(and_, expr=expr)) 492 493 # Finish the subprogram definition. 494 495 subprogram.code = results 496 497 self.current_subprograms.pop() 498 self.subprograms.append(subprogram); self.subnames[subprogram.full_name] = subprogram 499 500 # Make an invocation of the subprogram. 501 502 result = InvokeBlock(and_, produces_result=1) 503 result.expr = LoadRef(and_, ref=subprogram) 504 return result 505 506 def visitOr(self, or_): 507 508 """ 509 Make a subprogram for the 'or_' node and record its contents inside the 510 subprogram. Convert... 511 512 Or (test) 513 (test) 514 ... 515 516 ...to: 517 518 Subprogram -> Conditional (test) -> Return ... 519 (else) -> Conditional (test) -> Return ... 520 (else) -> ... 521 """ 522 523 subprogram = Subprogram(or_, name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 524 self.current_subprograms.append(subprogram) 525 526 # In the subprogram, make instructions which store each operand, test 527 # for each operand's truth status, and if appropriate return from the 528 # subprogram with the value of the operand. 529 530 last = or_.nodes[-1] 531 results = nodes = [] 532 533 for node in or_.nodes: 534 expr = self.dispatch(node) 535 536 # Return from the subprogram where the test is satisfied. 537 538 if node is not last: 539 nodes.append(StoreTemp(or_, expr=expr)) 540 invocation = InvokeFunction(or_, expr=LoadAttr(or_, expr=LoadTemp(or_), name="__true__"), args=[], star=None, dstar=None) 541 test = Conditional(or_, test=invocation, body=[Return(or_, expr=LoadTemp(or_))]) 542 nodes.append(test) 543 544 # Put subsequent operations in the else section of this conditional. 545 546 nodes = test.else_ = [ReleaseTemp(or_)] 547 548 # For the last operation, return the result. 549 550 else: 551 nodes.append( 552 Return(or_, expr=expr) 553 ) 554 555 # Finish the subprogram definition. 556 557 subprogram.code = results 558 559 self.current_subprograms.pop() 560 self.subprograms.append(subprogram); self.subnames[subprogram.full_name] = subprogram 561 562 # Make an invocation of the subprogram. 563 564 result = InvokeBlock(or_, produces_result=1) 565 result.expr = LoadRef(or_, ref=subprogram) 566 return result 567 568 def visitNot(self, not_): 569 result = Not(not_, expr=InvokeFunction(not_, expr=LoadAttr(not_, expr=self.dispatch(not_.expr), name="__true__"), args=[], star=None, dstar=None)) 570 return result 571 572 # Operators. 573 574 def visitUnaryAdd(self, unaryadd): 575 return InvokeFunction(unaryadd, expr=LoadAttr(unaryadd, expr=self.dispatch(unaryadd.expr), name="__pos__"), args=[], star=None, dstar=None) 576 577 def visitUnarySub(self, unarysub): 578 return InvokeFunction(unarysub, expr=LoadAttr(unarysub, expr=self.dispatch(unarysub.expr), name="__neg__"), args=[], star=None, dstar=None) 579 580 def visitInvert(self, invert): 581 return InvokeFunction(invert, expr=LoadAttr(invert, expr=self.dispatch(invert.expr), name="__invert__"), args=[], star=None, dstar=None) 582 583 def visitAdd(self, add): 584 585 """ 586 Emulate the current mechanisms by producing nodes as follows: 587 588 Try (body) -> x.__add__(y) 589 (else) 590 (handler) -> Conditional (test) -> isinstance(exc, TypeError) 591 (body) -> y.__radd__(x) 592 (else) 593 """ 594 595 result = Try(add, 596 body=[ 597 InvokeFunction(add, 598 expr=LoadAttr(add, expr=self.dispatch(add.left), name="__add__"), 599 args=[self.dispatch(add.right)], 600 star=None, 601 dstar=None) 602 ], 603 else_=[], 604 finally_=[], 605 handler=[ 606 Conditional(add, 607 test=InvokeFunction(add, 608 expr=LoadName(add, name="isinstance"), 609 args=[LoadExc(add), LoadName(add, name="TypeError")], 610 star=None, 611 dstar=None), 612 body=[ 613 InvokeFunction(add, 614 expr=LoadAttr(add, expr=self.dispatch(add.right), name="__radd__"), 615 args=[self.dispatch(add.left)], 616 star=None, 617 dstar=None) 618 ], 619 else_=[] 620 ) 621 ] 622 ) 623 624 return result 625 626 # Assignments. 627 628 augassign_methods = { 629 "+=" : "__iadd__", "-=" : "__isub__", "*=" : "__imul__", "/=" : "__idiv__", 630 "%=" : "__imod__", "**=" : "__ipow__", "<<=" : "__ilshift__", ">>=" : "__irshift__", 631 "&=" : "__iand__", "^=" : "__ixor__", "|=" : "__ior__" 632 } 633 634 def visitAugAssign(self, augassign): 635 result = Assign(augassign) 636 expr = self.dispatch(augassign.expr) 637 638 # Simple augmented assignment: name += expr 639 640 if isinstance(augassign.node, compiler.ast.Name): 641 result.code = [ 642 StoreTemp(augassign, 643 expr=InvokeFunction(augassign, 644 args=[expr], 645 star=None, 646 dstar=None, 647 expr=LoadAttr(augassign, 648 expr=self.dispatch(augassign.node), 649 name=self.augassign_methods[augassign.op] 650 ) 651 ) 652 ), 653 StoreName(augassign, 654 expr=LoadTemp(augassign), 655 name=augassign.node.name), 656 ReleaseTemp(augassign) 657 ] 658 659 # Complicated augmented assignment: lvalue.attr += expr 660 661 elif isinstance(augassign.node, compiler.ast.Getattr): 662 663 # <lvalue> -> setattr(<lvalue>, getattr(<lvalue>, "attr").__xxx__(expr)) 664 665 result.code = [ 666 StoreTemp(augassign, 667 index="expr", 668 expr=self.dispatch(augassign.node.expr) 669 ), 670 StoreTemp(augassign, 671 expr=InvokeFunction(augassign, 672 args=[expr], star=None, dstar=None, 673 expr=LoadAttr(augassign, 674 expr=LoadAttr(augassign, 675 expr=LoadTemp(augassign, index="expr"), 676 name=augassign.node.attrname 677 ), 678 name=self.augassign_methods[augassign.op] 679 ) 680 ) 681 ), 682 StoreAttr(augassign, 683 expr=LoadTemp(augassign), 684 lvalue=LoadTemp(augassign, index="expr"), 685 name=augassign.node.attrname 686 ), 687 ReleaseTemp(augassign, index="expr"), 688 ReleaseTemp(augassign) 689 ] 690 691 # Complicated augassign using slices: lvalue[lower:upper] += expr 692 693 elif isinstance(augassign.node, compiler.ast.Slice): 694 695 # <lvalue>, <lower>, <upper> -> <lvalue>.__setslice__(<lower>, <upper>, <lvalue>.__getslice__(<lower>, <upper>).__xxx__(expr)) 696 697 result.code = [ 698 StoreTemp(augassign, 699 index="expr", 700 expr=self.dispatch(augassign.node.expr) 701 ), 702 StoreTemp(augassign, 703 index="lower", 704 expr=self.dispatch_or_none(augassign.node.lower) 705 ), 706 StoreTemp(augassign, 707 index="upper", 708 expr=self.dispatch_or_none(augassign.node.upper) 709 ), 710 StoreTemp(augassign, 711 expr=InvokeFunction(augassign, 712 args=[expr], star=None, dstar=None, 713 expr=LoadAttr(augassign, 714 expr=self._visitSlice( 715 augassign.node, 716 LoadTemp(augassign, index="expr"), 717 LoadTemp(augassign, index="lower"), 718 LoadTemp(augassign, index="upper"), 719 "OP_APPLY"), 720 name=self.augassign_methods[augassign.op] 721 ) 722 ) 723 ), 724 self._visitSlice( 725 augassign.node, 726 LoadTemp(augassign, index="expr"), 727 LoadTemp(augassign, index="lower"), 728 LoadTemp(augassign, index="upper"), 729 "OP_ASSIGN", 730 LoadTemp(augassign) 731 ), 732 ReleaseTemp(augassign, index="expr"), 733 ReleaseTemp(augassign, index="lower"), 734 ReleaseTemp(augassign, index="upper"), 735 ReleaseTemp(augassign) 736 ] 737 738 # Complicated augassign using subscripts: lvalue[subs] += expr 739 740 elif isinstance(augassign.node, compiler.ast.Subscript): 741 742 # <lvalue>, <subs> -> <lvalue>.__setitem__(<subs>, <lvalue>.__getitem__(<subs>).__xxx__(expr)) 743 744 result.code = [ 745 StoreTemp(augassign, index="expr", expr=self.dispatch(augassign.node.expr)), 746 StoreTemp(augassign, index="subs", expr=self._visitSubscriptSubs(augassign.node.subs)), 747 StoreTemp(augassign, 748 expr=InvokeFunction(augassign, 749 args=[expr], star=None, dstar=None, 750 expr=LoadAttr(augassign, 751 expr=self._visitSubscript( 752 augassign.node, 753 LoadTemp(augassign, index="expr"), 754 LoadTemp(augassign, index="subs"), 755 "OP_APPLY" 756 ), 757 name=self.augassign_methods[augassign.op] 758 ) 759 ) 760 ), 761 self._visitSubscript( 762 augassign.node, 763 LoadTemp(augassign, index="expr"), 764 LoadTemp(augassign, index="subs"), 765 "OP_ASSIGN", 766 LoadTemp(augassign) 767 ), 768 ReleaseTemp(augassign, index="expr"), 769 ReleaseTemp(augassign, index="subs"), 770 ReleaseTemp(augassign) 771 ] 772 773 else: 774 raise NotImplementedError, augassign.node.__class__ 775 776 return result 777 778 def visitAssign(self, assign): 779 result = Assign(assign) 780 store = StoreTemp(assign, expr=self.dispatch(assign.expr)) 781 release = ReleaseTemp(assign) 782 result.code = [store] + self.dispatches(assign.nodes, 0) + [release] 783 return result 784 785 def visitAssList(self, asslist, in_sequence=0): 786 if not in_sequence: 787 expr = LoadTemp(asslist) 788 else: 789 expr = InvokeFunction(asslist, expr=LoadAttr(asslist, expr=LoadTemp(asslist), name="next"), star=None, dstar=None, args=[]) 790 result = Assign(asslist) 791 store = StoreTemp(asslist, expr=InvokeFunction(asslist, expr=LoadAttr(asslist, name="__iter__", expr=expr), star=None, dstar=None, args=[])) 792 release = ReleaseTemp(asslist) 793 result.code = [store] + self.dispatches(asslist.nodes, 1) + [release] 794 return result 795 796 visitAssTuple = visitAssList 797 798 def _visitAssNameOrAttr(self, node, in_sequence): 799 if not in_sequence: 800 return LoadTemp(node) 801 else: 802 return InvokeFunction(node, expr=LoadAttr(node, expr=LoadTemp(node), name="next"), star=None, dstar=None, args=[]) 803 804 def visitAssName(self, assname, in_sequence=0): 805 expr = self._visitAssNameOrAttr(assname, in_sequence) 806 result = StoreName(assname, name=assname.name, expr=expr) 807 return result 808 809 def visitAssAttr(self, assattr, in_sequence=0): 810 expr = self._visitAssNameOrAttr(assattr, in_sequence) 811 lvalue = self.dispatch(assattr.expr) 812 result = StoreAttr(assattr, name=assattr.attrname, lvalue=lvalue, expr=expr) 813 return result 814 815 def _visitSlice(self, slice, expr, lower, upper, flags, value=None): 816 if flags == "OP_ASSIGN": 817 args = [value] 818 result = InvokeFunction(slice, expr=LoadAttr(slice, expr=expr, name="__setslice__"), star=None, dstar=None, args=[]) 819 elif flags == "OP_APPLY": 820 args = [] 821 result = InvokeFunction(slice, expr=LoadAttr(slice, expr=expr, name="__getslice__"), star=None, dstar=None, args=[]) 822 elif flags == "OP_DELETE": 823 args = [] 824 result = InvokeFunction(slice, expr=LoadAttr(slice, expr=expr, name="__delslice__"), star=None, dstar=None, args=[]) 825 else: 826 raise NotImplementedError, flags 827 828 # Add the dimensions. 829 830 args.insert(0, lower) 831 args.insert(1, upper) 832 833 result.original = slice 834 result.set_args(args) 835 return result 836 837 def visitSlice(self, slice, in_sequence=0): 838 return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower), 839 self.dispatch_or_none(slice.upper), slice.flags, self._visitAssNameOrAttr(slice, in_sequence)) 840 841 def _visitSubscript(self, subscript, expr, subs, flags, value=None): 842 if flags == "OP_ASSIGN": 843 args = [value] 844 result = InvokeFunction(subscript, expr=LoadAttr(subscript, expr=expr, name="__setitem__"), star=None, dstar=None, args=[]) 845 elif flags == "OP_APPLY": 846 args = [] 847 result = InvokeFunction(subscript, expr=LoadAttr(subscript, expr=expr, name="__getitem__"), star=None, dstar=None, args=[]) 848 elif flags == "OP_DELETE": 849 args = [] 850 result = InvokeFunction(subscript, expr=LoadAttr(subscript, expr=expr, name="__delitem__"), star=None, dstar=None, args=[]) 851 else: 852 raise NotImplementedError, flags 853 854 # Add the dimensions. 855 856 args.insert(0, subs) 857 858 result.original = subscript 859 result.set_args(args) 860 return result 861 862 def _visitSubscriptSubs(self, subs): 863 if len(subs) == 1: 864 return self.dispatch(subs[0]) 865 else: 866 return InvokeFunction(subs, expr=LoadName(subs, name="tuple"), args=self.dispatches(subs), star=None, dstar=None) 867 868 def visitSubscript(self, subscript, in_sequence=0): 869 return self._visitSubscript( 870 subscript, self.dispatch(subscript.expr), self._visitSubscriptSubs(subscript.subs), subscript.flags, 871 self._visitAssNameOrAttr(subscript, in_sequence) 872 ) 873 874 # Invocation and subprogram transformations. 875 876 def visitClass(self, class_): 877 structure = Class(class_, name=class_.name, bases=self.dispatches(class_.bases)) 878 self.structures.append(structure) 879 880 # Make a subprogram which initialises the class structure. 881 882 subprogram = Subprogram(class_, name=None, structure=structure, params=[], star=None, dstar=None) 883 self.current_subprograms.append(subprogram) 884 885 # The class is initialised using the code found inside. 886 887 subprogram.code = self.dispatch(class_.code) + [Return(class_)] 888 889 self.current_subprograms.pop() 890 self.subprograms.append(subprogram); self.subnames[subprogram.full_name] = subprogram 891 892 # Make a definition of the class associating it with a name. 893 894 result = Assign(class_, 895 code=[ 896 StoreName(class_, 897 name=class_.name, 898 expr=LoadRef(class_, ref=structure) 899 ), 900 InvokeBlock(class_, 901 expr=LoadRef(class_, ref=subprogram) 902 ) 903 ] 904 ) 905 return result 906 907 def _visitFunction(self, function, subprogram): 908 909 """ 910 A common function generator which transforms the given 'function' node 911 and initialises the given 'subprogram' appropriately. 912 """ 913 914 # Discover star and dstar parameters. 915 916 if function.flags & 4 != 0: 917 has_star = 1 918 else: 919 has_star = 0 920 if function.flags & 8 != 0: 921 has_dstar = 1 922 else: 923 has_dstar = 0 924 925 # Discover the number of defaults and positional parameters. 926 927 ndefaults = len(function.defaults) 928 npositional = len(function.argnames) - has_star - has_dstar 929 930 # Produce star and dstar parameters with appropriate defaults. 931 932 if has_star: 933 star = (function.argnames[npositional], InvokeFunction(function, expr=LoadName(function, name="list"), args=[], star=None, dstar=None)) 934 else: 935 star = None 936 if has_dstar: 937 dstar = (function.argnames[npositional + has_star], InvokeFunction(function, expr=LoadName(function, name="dict"), args=[], star=None, dstar=None)) 938 else: 939 dstar = None 940 941 params = [] 942 for i in range(0, npositional - ndefaults): 943 params.append((function.argnames[i], None)) 944 945 # NOTE: Fix/process defaults. 946 947 for i in range(0, ndefaults): 948 default = function.defaults[i] 949 if default is not None: 950 params.append((function.argnames[npositional - ndefaults + i], self.dispatch(default))) 951 else: 952 params.append((function.argnames[npositional - ndefaults + i], default)) 953 954 subprogram.params = params 955 subprogram.star = star 956 subprogram.dstar = dstar 957 self.subprograms.append(subprogram); self.subnames[subprogram.full_name] = subprogram 958 959 def visitFunction(self, function): 960 961 # Make a subprogram for the function and record it outside the main 962 # tree. 963 964 subprogram = Subprogram(function, name=function.name, acquire_locals=0, returns_value=1, star=None, dstar=None) 965 self.current_subprograms.append(subprogram) 966 subprogram.code = self.dispatch(function.code) + [Return(function)] 967 self.current_subprograms.pop() 968 self._visitFunction(function, subprogram) 969 970 # Make a definition of the function associating it with a name. 971 972 result = StoreName(function, name=function.name, expr=LoadRef(function, ref=subprogram)) 973 return result 974 975 def visitLambda(self, lambda_): 976 977 # Make a subprogram for the function and record it outside the main 978 # tree. 979 980 subprogram = Subprogram(lambda_, name=None, acquire_locals=0, returns_value=1, star=None, dstar=None) 981 self.current_subprograms.append(subprogram) 982 subprogram.code = [Return(lambda_, expr=self.dispatch(lambda_.code))] 983 self.current_subprograms.pop() 984 self._visitFunction(lambda_, subprogram) 985 986 # Get the subprogram reference to the lambda. 987 988 return LoadRef(lambda_, ref=subprogram) 989 990 def visitCallFunc(self, callfunc): 991 result = InvokeFunction(callfunc, star=None, dstar=None, args=self.dispatches(callfunc.args)) 992 if callfunc.star_args is not None: 993 result.star = self.dispatch(callfunc.star_args) 994 if callfunc.dstar_args is not None: 995 result.dstar = self.dispatch(callfunc.dstar_args) 996 result.expr = self.dispatch(callfunc.node) 997 return result 998 999 def visitWhile(self, while_): 1000 1001 """ 1002 Make a subprogram for the 'while' node and record its contents inside the 1003 subprogram. Convert... 1004 1005 While (test) -> (body) 1006 (else) 1007 1008 ...to: 1009 1010 Subprogram -> Conditional (test) -> (body) -> Invoke subprogram 1011 (else) -> Conditional (test) -> Return ... 1012 (else) -> ... 1013 """ 1014 1015 subprogram = Subprogram(while_, name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 1016 self.current_subprograms.append(subprogram) 1017 1018 # Include a conditional statement in the subprogram. 1019 1020 test = Conditional(while_, else_=[]) 1021 test.test = InvokeFunction(while_, expr=LoadAttr(while_, expr=self.dispatch(while_.test), name="__true__"), args=[], star=None, dstar=None) 1022 1023 # Inside the conditional, add a recursive invocation to the subprogram 1024 # if the test condition was satisfied. 1025 1026 continuation = InvokeBlock(while_) 1027 continuation.expr = LoadRef(while_, ref=subprogram) 1028 1029 # Return within the main section of the loop. 1030 1031 test.body = self.dispatch(while_.body) + [continuation, Return(while_)] 1032 1033 # Provide the else section, if present, along with an explicit return. 1034 1035 if while_.else_ is not None: 1036 test.else_ = self.dispatch(while_.else_) + [Return(while_)] 1037 1038 # Finish the subprogram definition. 1039 1040 subprogram.code = [test] 1041 1042 self.current_subprograms.pop() 1043 self.subprograms.append(subprogram); self.subnames[subprogram.full_name] = subprogram 1044 1045 # Make an invocation of the subprogram. 1046 1047 result = InvokeBlock(while_) 1048 result.expr = LoadRef(while_, ref=subprogram) 1049 return result 1050 1051 def visitFor(self, for_): 1052 1053 """ 1054 Make a subprogram for the 'for_' node and record its contents inside the 1055 subprogram. Convert... 1056 1057 For (assign) 1058 (body) 1059 (else) 1060 1061 ...to: 1062 1063 Assign (assign #1) 1064 Invoke -> Subprogram -> Try (body) -> (assign #2) 1065 (body) 1066 Invoke subprogram 1067 (handler) -> ... 1068 (else) -> ... 1069 """ 1070 1071 subprogram = Subprogram(for_, name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 1072 self.current_subprograms.append(subprogram) 1073 1074 # Always return from conditional sections/subprograms. 1075 1076 if for_.else_ is not None: 1077 else_stmt = self.dispatch(for_.else_) + [Return(for_)] 1078 else: 1079 else_stmt = [Return(for_)] 1080 1081 # Wrap the assignment in a try...except statement. 1082 1083 try_except = Try(for_, body=[], else_=[], finally_=[]) 1084 test = Conditional(for_, 1085 test=InvokeFunction(for_, 1086 expr=LoadName(for_, name="isinstance"), 1087 args=[LoadExc(for_), LoadName(for_, name="StopIteration")], 1088 star=None, 1089 dstar=None), 1090 body=else_stmt, 1091 else_=[Raise(for_, expr=LoadExc(for_))]) 1092 try_except.handler = [test] 1093 1094 assign = Assign(for_, 1095 code=[ 1096 StoreTemp(for_, expr=InvokeFunction(for_, expr=LoadAttr(for_, expr=LoadTemp(for_), name="next"), args=[], star=None, dstar=None)), 1097 self.dispatch(for_.assign), 1098 ReleaseTemp(for_) 1099 ]) 1100 1101 # Inside the conditional, add a recursive invocation to the subprogram 1102 # if the test condition was satisfied. 1103 1104 continuation = InvokeBlock(for_) 1105 continuation.expr = LoadRef(for_, ref=subprogram) 1106 try_except.body = [assign] + self.dispatch(for_.body) + [continuation] 1107 subprogram.code = [try_except, Return(for_)] 1108 1109 # Finish the subprogram definition. 1110 1111 self.current_subprograms.pop() 1112 self.subprograms.append(subprogram); self.subnames[subprogram.full_name] = subprogram 1113 1114 # Obtain an iterator for the sequence involved. 1115 # Then, make an invocation of the subprogram. 1116 1117 result = Assign(for_) 1118 result.code = [ 1119 StoreTemp(for_, expr=InvokeFunction(for_, expr=LoadAttr(for_, name="__iter__", expr=self.dispatch(for_.list)), args=[], star=None, dstar=None)), 1120 InvokeBlock(for_, expr=LoadRef(for_, ref=subprogram)), 1121 ReleaseTemp(for_) 1122 ] 1123 return result 1124 1125 # Exception node transformations. 1126 1127 def visitTryFinally(self, tryfinally): 1128 result = Try(tryfinally, body=[], else_=[], finally_=[]) 1129 if tryfinally.body is not None: 1130 result.body = self.dispatch(tryfinally.body) 1131 if tryfinally.final is not None: 1132 result.finally_ = self.dispatch(tryfinally.final) 1133 return result 1134 1135 # Convenience functions. 1136 1137 def simplify(filename, builtins=0): 1138 1139 """ 1140 Simplify the module stored in the file with the given 'filename'. If the 1141 optional 'builtins' parameter is set to a true value (the default being a 1142 false value), then the module is considered as the builtins module. 1143 """ 1144 1145 simplifier = Simplifier(builtins) 1146 module = compiler.parseFile(filename) 1147 simplified = simplifier.process(module) 1148 compiler.misc.set_filename(filename, module) 1149 return simplified 1150 1151 # vim: tabstop=4 expandtab shiftwidth=4