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