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, name=getattr.attrname) 127 result.expr = self.dispatch(getattr.expr) 128 return result 129 130 def visitKeyword(self, keyword): 131 result = Keyword(keyword, name=keyword.name) 132 result.expr = self.dispatch(keyword.expr) 133 return result 134 135 def visitGlobal(self, global_): 136 result = Global(global_, names=global_.names) 137 return result 138 139 def visitImport(self, import_): 140 result = Assign(import_) 141 code = [] 142 for path, alias in import_.names: 143 importer = Import(name=path) 144 top = alias or path.split(".")[0] 145 code.append(StoreName(expr=importer, name=top)) 146 result.code = code 147 return result 148 149 def visitFrom(self, from_): 150 result = Assign(from_) 151 code = [] 152 code.append(StoreTemp(expr=Import(name=from_.modname))) 153 for name, alias in from_.names: 154 code.append(StoreName(expr=LoadAttr(expr=LoadTemp(), name=name), name=(alias or name))) 155 result.code = code 156 return result 157 158 def visitName(self, name): 159 result = LoadName(name, name=name.name) 160 return result 161 162 def visitConst(self, const): 163 if not self.constants.has_key(const.value): 164 self.constants[const.value] = Constant(name=repr(const.value), value=const.value) 165 result = LoadRef(ref=self.constants[const.value]) 166 return result 167 168 def visitReturn(self, return_): 169 result = Return(return_) 170 result.expr = self.dispatch(return_.value) 171 return result 172 173 def visitBreak(self, break_): 174 result = Return(break_) 175 return result 176 177 def visitContinue(self, continue_): 178 result = Invoke(continue_, same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 179 result.expr = LoadRef(ref=self.current_subprograms[-1]) 180 return result 181 182 def visitRaise(self, raise_): 183 result = Raise(raise_, expr=self.dispatch(raise_.expr1), traceback=None) 184 if raise_.expr2 is not None: 185 result.args = [self.dispatch(raise_.expr2)] 186 if raise_.expr3 is not None: 187 result.traceback = self.dispatch(raise_.expr3) 188 return result 189 190 def _visitBuiltin(self, builtin, name): 191 result = Invoke(builtin, expr=LoadName(name=name), args=self.dispatches(builtin.nodes), star=None, dstar=None) 192 return result 193 194 def visitTuple(self, tuple): 195 return self._visitBuiltin(tuple, "tuple") 196 197 def visitList(self, list): 198 return self._visitBuiltin(list, "list") 199 200 def visitDict(self, dict): 201 result = Invoke(dict, expr=LoadName(name="dict"), star=None, dstar=None) 202 args = [] 203 for key, value in dict.items: 204 tuple = Invoke(expr=LoadName(name="tuple"), star=None, dstar=None) 205 tuple.args = [self.dispatch(key), self.dispatch(value)] 206 args.append(tuple) 207 result.args = args 208 return result 209 210 # Logical and comparison operations plus chained statements. 211 212 def visitIf(self, if_): 213 214 """ 215 Make conditionals for each test from an 'if_' AST node, adding the body 216 and putting each subsequent test as part of the conditional's else 217 section. 218 219 Convert... 220 221 If (test/body) 222 (test/body) 223 ... 224 (else/body) 225 226 ...to: 227 228 Conditional (test) -> (body) 229 (else) -> Conditional (test) -> (body) 230 (else) -> ... 231 """ 232 233 234 results = nodes = [] 235 236 for compare, stmt in if_.tests: 237 # Produce something like... 238 # expr.__true__() ? body 239 test = Conditional(test=Invoke(expr=LoadAttr(expr=self.dispatch(compare), name="__true__"), args=[], star=None, dstar=None)) 240 test.body = self.dispatch(stmt) 241 nodes.append(test) 242 nodes = test.else_ = [] 243 244 # Add the compound statement from any else clause to the end. 245 246 if if_.else_ is not None: 247 nodes += self.dispatch(if_.else_) 248 249 result = results[0] 250 return result 251 252 def visitTryExcept(self, tryexcept): 253 254 """ 255 Make conditionals for each handler associated with a 'tryexcept' node. 256 257 Convert... 258 259 TryExcept (body) 260 (else) 261 (spec/assign/stmt) 262 ... 263 264 ...to: 265 266 Try (body) 267 (else) 268 (handler) -> Conditional (test) -> (stmt) 269 (else) -> Conditional (test) -> (stmt) 270 (else) -> ... 271 """ 272 273 result = Try(tryexcept, body=[], else_=[], finally_=[]) 274 275 if tryexcept.body is not None: 276 result.body = self.dispatch(tryexcept.body) 277 if tryexcept.else_ is not None: 278 result.else_ = self.dispatch(tryexcept.else_) 279 280 results = nodes = [] 281 for spec, assign, stmt in tryexcept.handlers: 282 283 # If no specification exists, produce an unconditional block. 284 285 if spec is None: 286 nodes += self.dispatch(stmt) 287 288 # Produce something like... 289 # isinstance(<exc>, <spec>) 290 291 else: 292 new_spec = self.dispatch(spec) 293 test = Conditional(test=Invoke(expr=LoadName(name="isinstance"), args=[LoadExc(), new_spec], star=None, dstar=None)) 294 test.body = [] 295 296 if assign is not None: 297 test.body.append(Assign(code=[StoreTemp(expr=LoadExc()), self.dispatch(assign), ReleaseTemp()])) 298 299 # Always return from conditional sections. 300 301 test.body += self.dispatch(stmt) + [Return()] 302 nodes.append(test) 303 nodes = test.else_ = [] 304 305 # Add a raise operation to deal with unhandled exceptions. 306 307 nodes.append(Raise(expr=LoadExc())) 308 309 result.handler = results 310 return result 311 312 comparison_methods = { 313 "==" : "__eq__", "!=" : "__ne__", "<" : "__lt__", "<=" : "__le__", 314 ">=" : "__ge__", ">" : "__gt__", "is" : None, "is not" : None 315 } 316 317 def visitCompare(self, compare): 318 319 """ 320 Make a subprogram for the 'compare' node and record its contents inside 321 the subprogram. Convert... 322 323 Compare (expr) 324 (name/node) 325 ... 326 327 ...to: 328 329 Subprogram -> Conditional (test) -> (body) 330 (else) -> Conditional (test) -> (body) 331 (else) -> ... 332 """ 333 334 subprogram = Subprogram(name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 335 self.current_subprograms.append(subprogram) 336 337 # In the subprogram, make instructions which invoke a method on the 338 # first operand of each operand pair and, if appropriate, return with 339 # the value from that method. 340 341 last = compare.ops[-1] 342 previous = self.dispatch(compare.expr) 343 results = nodes = [] 344 345 for op in compare.ops: 346 op_name, node = op 347 expr = self.dispatch(node) 348 349 # Identify the operation and produce the appropriate method call. 350 351 method_name = self.comparison_methods[op_name] 352 if method_name: 353 invocation = Invoke(expr=LoadAttr(expr=previous, name=method_name), args=[expr], star=None, dstar=None) 354 elif op_name == "is": 355 invocation = Invoke(expr=LoadName(name="__is__"), args=[previous, expr], star=None, dstar=None) 356 elif op_name == "is not": 357 invocation = Not(expr=Invoke(expr=LoadName(name="__is__"), args=[previous, expr], star=None, dstar=None)) 358 else: 359 raise NotImplementedError, op_name 360 nodes.append(StoreTemp(expr=invocation)) 361 362 # Return from the subprogram where the test is not satisfied. 363 364 if op is not last: 365 test = Conditional(test=Not(expr=LoadTemp()), body=[Return(expr=LoadTemp())]) 366 nodes.append(test) 367 368 # Put subsequent operations in the else section of this conditional. 369 370 nodes = test.else_ = [ReleaseTemp()] 371 372 # For the last operation, return the result. 373 374 else: 375 nodes.append(Return(expr=LoadTemp())) 376 377 previous = expr 378 379 # Finish the subprogram definition. 380 381 subprogram.code = results 382 383 self.current_subprograms.pop() 384 self.subprograms.append(subprogram) 385 386 # Make an invocation of the subprogram. 387 388 result = Invoke(compare, same_frame=1, star=None, dstar=None, args=[]) 389 result.expr = LoadRef(ref=subprogram) 390 return result 391 392 def visitAnd(self, and_): 393 394 """ 395 Make a subprogram for the 'and_' node and record its contents inside the 396 subprogram. Convert... 397 398 And (test) 399 (test) 400 ... 401 402 ...to: 403 404 Subprogram -> Conditional (test) -> Return ... 405 (else) -> Conditional (test) -> Return ... 406 (else) -> ... 407 """ 408 409 subprogram = Subprogram(name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 410 self.current_subprograms.append(subprogram) 411 412 # In the subprogram, make instructions which store each operand, test 413 # for each operand's truth status, and if appropriate return from the 414 # subprogram with the value of the operand. 415 416 last = and_.nodes[-1] 417 results = nodes = [] 418 419 for node in and_.nodes: 420 expr = self.dispatch(node) 421 422 # Return from the subprogram where the test is not satisfied. 423 424 if node is not last: 425 nodes.append(StoreTemp(expr=expr)) 426 invocation = Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), args=[], star=None, dstar=None) 427 test = Conditional(test=Not(expr=invocation), body=[Return(expr=LoadTemp())]) 428 nodes.append(test) 429 430 # Put subsequent operations in the else section of this conditional. 431 432 nodes = test.else_ = [ReleaseTemp()] 433 434 # For the last operation, return the result. 435 436 else: 437 nodes.append(Return(expr=expr)) 438 439 # Finish the subprogram definition. 440 441 subprogram.code = results 442 443 self.current_subprograms.pop() 444 self.subprograms.append(subprogram) 445 446 # Make an invocation of the subprogram. 447 448 result = Invoke(and_, same_frame=1, star=None, dstar=None, args=[]) 449 result.expr = LoadRef(ref=subprogram) 450 return result 451 452 def visitOr(self, or_): 453 454 """ 455 Make a subprogram for the 'or_' node and record its contents inside the 456 subprogram. Convert... 457 458 Or (test) 459 (test) 460 ... 461 462 ...to: 463 464 Subprogram -> Conditional (test) -> Return ... 465 (else) -> Conditional (test) -> Return ... 466 (else) -> ... 467 """ 468 469 subprogram = Subprogram(name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 470 self.current_subprograms.append(subprogram) 471 472 # In the subprogram, make instructions which store each operand, test 473 # for each operand's truth status, and if appropriate return from the 474 # subprogram with the value of the operand. 475 476 last = or_.nodes[-1] 477 results = nodes = [] 478 479 for node in or_.nodes: 480 expr = self.dispatch(node) 481 482 # Return from the subprogram where the test is satisfied. 483 484 if node is not last: 485 nodes.append(StoreTemp(expr=expr)) 486 invocation = Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), args=[], star=None, dstar=None) 487 test = Conditional(test=invocation, body=[Return(expr=LoadTemp())]) 488 nodes.append(test) 489 490 # Put subsequent operations in the else section of this conditional. 491 492 nodes = test.else_ = [ReleaseTemp()] 493 494 # For the last operation, return the result. 495 496 else: 497 nodes.append(Return(expr=expr)) 498 499 # Finish the subprogram definition. 500 501 subprogram.code = results 502 503 self.current_subprograms.pop() 504 self.subprograms.append(subprogram) 505 506 # Make an invocation of the subprogram. 507 508 result = Invoke(or_, same_frame=1, star=None, dstar=None, args=[]) 509 result.expr = LoadRef(ref=subprogram) 510 return result 511 512 def visitNot(self, not_): 513 result = Not(not_, expr=Invoke(expr=LoadAttr(expr=self.dispatch(not_.expr), name="__true__"), args=[], star=None, dstar=None)) 514 return result 515 516 # Operators. 517 518 def visitUnaryAdd(self, unaryadd): 519 return Invoke(unaryadd, expr=LoadAttr(expr=self.dispatch(unaryadd.expr), name="__pos__"), args=[], star=None, dstar=None) 520 521 def visitUnarySub(self, unarysub): 522 return Invoke(unarysub, expr=LoadAttr(expr=self.dispatch(unarysub.expr), name="__neg__"), args=[], star=None, dstar=None) 523 524 def visitInvert(self, invert): 525 return Invoke(invert, expr=LoadAttr(expr=self.dispatch(invert.expr), name="__invert__"), args=[], star=None, dstar=None) 526 527 def visitAdd(self, add): 528 529 # NOTE: Strictly one of the choices must be evaluated, never more than one. 530 531 result = Choice(add) 532 result.choices = [ 533 Invoke(expr=LoadAttr(expr=self.dispatch(add.left), name="__add__"), args=[self.dispatch(add.right)], star=None, dstar=None), 534 Invoke(expr=LoadAttr(expr=self.dispatch(add.right), name="__radd__"), args=[self.dispatch(add.left)], star=None, dstar=None) 535 ] 536 return result 537 538 # Assignments. 539 540 augassign_methods = { 541 "+=" : "__iadd__", "-=" : "__isub__", "*=" : "__imul__", "/=" : "__idiv__", 542 "%=" : "__imod__", "**=" : "__ipow__", "<<=" : "__ilshift__", ">>=" : "__irshift__", 543 "&=" : "__iand__", "^=" : "__ixor__", "|=" : "__ior__" 544 } 545 546 def visitAugAssign(self, augassign): 547 result = Assign(augassign) 548 expr = self.dispatch(augassign.expr) 549 550 # Simple augmented assignment: name += expr 551 552 if isinstance(augassign.node, compiler.ast.Name): 553 name = augassign.node 554 node = self.dispatch(name) 555 get_incremented = StoreTemp( 556 expr=Invoke(expr=LoadAttr(expr=node, name=self.augassign_methods[augassign.op]), args=[expr], star=None, dstar=None) 557 ) 558 store = StoreName(expr=LoadTemp(), name=name.name) 559 result.code = [get_incremented, store, ReleaseTemp()] 560 561 # Complicated augmented assignment: lvalue.attr += expr 562 563 elif isinstance(augassign.node, compiler.ast.Getattr): 564 565 # <lvalue> -> setattr(<lvalue>, getattr(<lvalue>, "attr").__xxx__(expr)) 566 567 getattr = augassign.node 568 store_expr = StoreTemp(index="expr", expr=self.dispatch(getattr.expr)) 569 node_attr = LoadAttr(expr=LoadTemp(index="expr"), name=getattr.attrname) 570 get_incremented = StoreTemp( 571 expr=Invoke(expr=LoadAttr(expr=node_attr, name=self.augassign_methods[augassign.op]), args=[expr], star=None, dstar=None) 572 ) 573 store = StoreAttr(expr=LoadTemp(), lvalue=LoadTemp(index="expr"), name=getattr.attrname) 574 result.code = [store_expr, get_incremented, store, ReleaseTemp(index="expr"), ReleaseTemp()] 575 576 # Complicated augassign using slices: lvalue[lower:upper] += expr 577 578 elif isinstance(augassign.node, compiler.ast.Slice): 579 580 # <lvalue>, <lower>, <upper> -> <lvalue>.__setslice__(<lower>, <upper>, <lvalue>.__getslice__(<lower>, <upper>).__xxx__(expr)) 581 582 slice = augassign.node 583 store_expr = StoreTemp(index="expr", expr=self.dispatch(slice.expr)) 584 store_lower = StoreTemp(index="lower", expr=self.dispatch_or_none(slice.lower)) 585 store_upper = StoreTemp(index="upper", expr=self.dispatch_or_none(slice.upper)) 586 node_slice = self._visitSlice(slice, LoadTemp(index="expr"), LoadTemp(index="lower"), LoadTemp(index="upper"), "OP_APPLY") 587 get_incremented = StoreTemp( 588 expr=Invoke(expr=LoadAttr(expr=node_slice, name=self.augassign_methods[augassign.op]), args=[expr], star=None, dstar=None) 589 ) 590 store = self._visitSlice(slice, LoadTemp(index="expr"), LoadTemp(index="lower"), LoadTemp(index="upper"), "OP_ASSIGN", LoadTemp()) 591 result.code = [store_expr, store_lower, store_upper, get_incremented, store, 592 ReleaseTemp(index="expr"), ReleaseTemp(index="lower"), ReleaseTemp(index="upper"), ReleaseTemp()] 593 594 # Complicated augassign using subscripts: lvalue[subs] += expr 595 596 elif isinstance(augassign.node, compiler.ast.Subscript): 597 598 # <lvalue>, <subs> -> <lvalue>.__setitem__(<subs>, <lvalue>.__getitem__(<subs>).__xxx__(expr)) 599 600 subscript = augassign.node 601 store_expr = StoreTemp(index="expr", expr=self.dispatch(subscript.expr)) 602 subs = self._visitSubscriptSubs(subscript.subs) 603 store_subs = StoreTemp(index="subs", expr=subs) 604 node_subscript = self._visitSubscript(subscript, LoadTemp(index="expr"), LoadTemp(index="subs"), "OP_APPLY") 605 get_incremented = StoreTemp( 606 expr=Invoke(expr=LoadAttr(expr=node_subscript, name=self.augassign_methods[augassign.op]), args=[expr], star=None, dstar=None) 607 ) 608 store = self._visitSubscript(subscript, LoadTemp(index="expr"), LoadTemp(index="subs"), "OP_ASSIGN", LoadTemp()) 609 result.code = [store_expr, store_subs, get_incremented, store, ReleaseTemp(index="expr"), ReleaseTemp(index="subs"), ReleaseTemp()] 610 611 else: 612 raise NotImplementedError, augassign.node.__class__ 613 614 return result 615 616 def visitAssign(self, assign): 617 result = Assign(assign) 618 store = StoreTemp(expr=self.dispatch(assign.expr)) 619 release = ReleaseTemp() 620 result.code = [store] + self.dispatches(assign.nodes, 0) + [release] 621 return result 622 623 def visitAssList(self, asslist, in_sequence=0): 624 if not in_sequence: 625 expr = LoadTemp() 626 else: 627 expr = Invoke(expr=LoadAttr(expr=LoadTemp(), name="next"), star=None, dstar=None, args=[]) 628 result = Assign(asslist) 629 store = StoreTemp(expr=Invoke(expr=LoadAttr(name="__iter__", expr=expr), star=None, dstar=None, args=[])) 630 release = ReleaseTemp() 631 result.code = [store] + self.dispatches(asslist.nodes, 1) + [release] 632 return result 633 634 visitAssTuple = visitAssList 635 636 def _visitAssNameOrAttr(self, node, in_sequence): 637 if not in_sequence: 638 return LoadTemp() 639 else: 640 return Invoke(expr=LoadAttr(expr=LoadTemp(), name="next"), star=None, dstar=None, args=[]) 641 642 def visitAssName(self, assname, in_sequence=0): 643 expr = self._visitAssNameOrAttr(assname, in_sequence) 644 result = StoreName(assname, name=assname.name, expr=expr) 645 return result 646 647 def visitAssAttr(self, assattr, in_sequence=0): 648 expr = self._visitAssNameOrAttr(assattr, in_sequence) 649 lvalue = self.dispatch(assattr.expr) 650 result = StoreAttr(assattr, name=assattr.attrname, lvalue=lvalue, expr=expr) 651 return result 652 653 def _visitSlice(self, slice, expr, lower, upper, flags, value=None): 654 if flags == "OP_ASSIGN": 655 args = [value] 656 result = Invoke(expr=LoadAttr(expr=expr, name="__setslice__"), star=None, dstar=None, args=[]) 657 elif flags == "OP_APPLY": 658 args = [] 659 result = Invoke(expr=LoadAttr(expr=expr, name="__getslice__"), star=None, dstar=None, args=[]) 660 elif flags == "OP_DELETE": 661 args = [] 662 result = Invoke(expr=LoadAttr(expr=expr, name="__delslice__"), star=None, dstar=None, args=[]) 663 else: 664 raise NotImplementedError, flags 665 666 # Add the dimensions. 667 668 args.insert(0, lower) 669 args.insert(1, upper) 670 671 result.original = slice 672 result.args = args 673 return result 674 675 def visitSlice(self, slice, in_sequence=0): 676 value = self._visitAssNameOrAttr(slice, in_sequence) 677 return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower), 678 self.dispatch_or_none(slice.upper), slice.flags, value) 679 680 def _visitSubscript(self, subscript, expr, subs, flags, value=None): 681 if flags == "OP_ASSIGN": 682 args = [value] 683 result = Invoke(expr=LoadAttr(expr=expr, name="__setitem__"), star=None, dstar=None, args=[]) 684 elif flags == "OP_APPLY": 685 args = [] 686 result = Invoke(expr=LoadAttr(expr=expr, name="__getitem__"), star=None, dstar=None, args=[]) 687 elif flags == "OP_DELETE": 688 args = [] 689 result = Invoke(expr=LoadAttr(expr=expr, name="__delitem__"), star=None, dstar=None, args=[]) 690 else: 691 raise NotImplementedError, flags 692 693 # Add the dimensions. 694 695 args.insert(0, subs) 696 697 result.original = subscript 698 result.args = args 699 return result 700 701 def _visitSubscriptSubs(self, subs): 702 if len(subs) == 1: 703 return self.dispatch(subs[0]) 704 else: 705 return Invoke(expr=LoadName(name="tuple"), args=self.dispatches(subs), star=None, dstar=None) 706 707 def visitSubscript(self, subscript, in_sequence=0): 708 value = self._visitAssNameOrAttr(subscript, in_sequence) 709 subs = self._visitSubscriptSubs(subscript.subs) 710 return self._visitSubscript(subscript, self.dispatch(subscript.expr), subs, subscript.flags, value) 711 712 # Invocation and subprogram transformations. 713 714 def visitClass(self, class_): 715 structure = Class(name=class_.name, bases=self.dispatches(class_.bases)) 716 self.structures.append(structure) 717 718 # Make a subprogram which initialises the class structure. 719 720 subprogram = Subprogram(name=None, structure=structure, params=[], star=None, dstar=None) 721 self.current_subprograms.append(subprogram) 722 723 # The class is initialised using the code found inside. 724 725 subprogram.code = self.dispatch(class_.code) + [Return()] 726 727 self.current_subprograms.pop() 728 self.subprograms.append(subprogram) 729 730 # Make a definition of the class associating it with a name. 731 732 result = Assign(class_) 733 store = StoreName(name=class_.name, expr=LoadRef(ref=structure)) 734 init = Invoke(expr=LoadRef(ref=subprogram), args=[], star=None, dstar=None) 735 result.code = [store, init] 736 return result 737 738 def _visitFunction(self, function, subprogram): 739 740 """ 741 A common function generator which transforms the given 'function' node 742 and initialises the given 'subprogram' appropriately. 743 """ 744 745 # Discover star and dstar parameters. 746 747 if function.flags & 4 != 0: 748 has_star = 1 749 else: 750 has_star = 0 751 if function.flags & 8 != 0: 752 has_dstar = 1 753 else: 754 has_dstar = 0 755 756 # Discover the number of defaults and positional parameters. 757 758 ndefaults = len(function.defaults) 759 npositional = len(function.argnames) - has_star - has_dstar 760 761 # Produce star and dstar parameters with appropriate defaults. 762 763 if has_star: 764 star = (function.argnames[npositional], Invoke(expr=LoadName(name="list"), args=[], star=None, dstar=None)) 765 else: 766 star = None 767 if has_dstar: 768 dstar = (function.argnames[npositional + has_star], Invoke(expr=LoadName(name="dict"), args=[], star=None, dstar=None)) 769 else: 770 dstar = None 771 772 params = [] 773 for i in range(0, npositional - ndefaults): 774 params.append((function.argnames[i], None)) 775 776 # NOTE: Fix/process defaults. 777 778 for i in range(0, ndefaults): 779 default = function.defaults[i] 780 if default is not None: 781 params.append((function.argnames[npositional - ndefaults + i], self.dispatch(default))) 782 else: 783 params.append((function.argnames[npositional - ndefaults + i], default)) 784 785 subprogram.params = params 786 subprogram.star = star 787 subprogram.dstar = dstar 788 self.subprograms.append(subprogram) 789 790 def visitFunction(self, function): 791 792 # Make a subprogram for the function and record it outside the main 793 # tree. 794 795 subprogram = Subprogram(function, name=function.name, acquire_locals=0, returns_value=1, star=None, dstar=None) 796 self.current_subprograms.append(subprogram) 797 subprogram.code = self.dispatch(function.code) + [Return()] 798 self.current_subprograms.pop() 799 self._visitFunction(function, subprogram) 800 801 # Make a definition of the function associating it with a name. 802 803 result = StoreName(name=function.name, expr=LoadRef(ref=subprogram)) 804 return result 805 806 def visitLambda(self, lambda_): 807 808 # Make a subprogram for the function and record it outside the main 809 # tree. 810 811 subprogram = Subprogram(name=None, acquire_locals=0, returns_value=1, star=None, dstar=None) 812 self.current_subprograms.append(subprogram) 813 subprogram.code = [Return(expr=self.dispatch(lambda_.code))] 814 self.current_subprograms.pop() 815 self._visitFunction(lambda_, subprogram) 816 817 # Get the subprogram reference to the lambda. 818 819 return LoadRef(lambda_, ref=subprogram) 820 821 def visitCallFunc(self, callfunc): 822 result = Invoke(callfunc, same_frame=0, star=None, dstar=None) 823 result.args = self.dispatches(callfunc.args) 824 if callfunc.star_args is not None: 825 result.star = self.dispatch(callfunc.star_args) 826 if callfunc.dstar_args is not None: 827 result.dstar = self.dispatch(callfunc.dstar_args) 828 result.expr = self.dispatch(callfunc.node) 829 return result 830 831 def visitWhile(self, while_): 832 833 """ 834 Make a subprogram for the 'while' node and record its contents inside the 835 subprogram. Convert... 836 837 While (test) -> (body) 838 (else) 839 840 ...to: 841 842 Subprogram -> Conditional (test) -> (body) -> Invoke subprogram 843 (else) -> Conditional (test) -> Return ... 844 (else) -> ... 845 """ 846 847 subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 848 self.current_subprograms.append(subprogram) 849 850 # Include a conditional statement in the subprogram. 851 852 test = Conditional(else_=[]) 853 test.test = Invoke(expr=LoadAttr(expr=self.dispatch(while_.test), name="__true__"), args=[], star=None, dstar=None) 854 855 # Inside the conditional, add a recursive invocation to the subprogram 856 # if the test condition was satisfied. 857 858 continuation = Invoke(same_frame=1, star=None, dstar=None, args=[]) 859 continuation.expr = LoadRef(ref=subprogram) 860 861 # Return within the main section of the loop. 862 863 test.body = self.dispatch(while_.body) + [continuation, Return()] 864 865 # Provide the else section, if present, along with an explicit return. 866 867 if while_.else_ is not None: 868 test.else_ = self.dispatch(while_.else_) + [Return()] 869 870 # Finish the subprogram definition. 871 872 subprogram.code = [test] 873 874 self.current_subprograms.pop() 875 self.subprograms.append(subprogram) 876 877 # Make an invocation of the subprogram. 878 879 result = Invoke(while_, same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 880 result.expr = LoadRef(ref=subprogram) 881 return result 882 883 def visitFor(self, for_): 884 885 """ 886 Make a subprogram for the 'for_' node and record its contents inside the 887 subprogram. Convert... 888 889 For (assign) 890 (body) 891 (else) 892 893 ...to: 894 895 Assign (assign #1) 896 Invoke -> Subprogram -> Try (body) -> (assign #2) 897 (body) 898 Invoke subprogram 899 (handler) -> ... 900 (else) -> ... 901 """ 902 903 subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 904 self.current_subprograms.append(subprogram) 905 906 # Always return from conditional sections/subprograms. 907 908 if for_.else_ is not None: 909 else_stmt = self.dispatch(for_.else_) + [Return()] 910 else: 911 else_stmt = [Return()] 912 913 # Wrap the assignment in a try...except statement. 914 915 try_except = Try(body=[], else_=[], finally_=[]) 916 test = Conditional( 917 test=Invoke(expr=LoadName(name="isinstance"), args=[LoadExc(), LoadName(name="StopIteration")], star=None, dstar=None), 918 body=else_stmt, 919 else_=[Raise(expr=LoadExc())]) 920 try_except.handler = [test] 921 922 assign = Assign() 923 assign.code = [ 924 StoreTemp(expr=Invoke(expr=LoadAttr(expr=LoadTemp(), name="next"), args=[], star=None, dstar=None)), 925 self.dispatch(for_.assign), 926 ReleaseTemp() 927 ] 928 929 # Inside the conditional, add a recursive invocation to the subprogram 930 # if the test condition was satisfied. 931 932 continuation = Invoke(same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 933 continuation.expr = LoadRef(ref=subprogram) 934 try_except.body = [assign] + self.dispatch(for_.body) + [continuation] 935 subprogram.code = [try_except, Return()] 936 937 # Finish the subprogram definition. 938 939 self.subprograms.append(subprogram) 940 self.current_subprograms.pop() 941 942 # Obtain an iterator for the sequence involved. 943 # Then, make an invocation of the subprogram. 944 945 result = Assign(for_) 946 result.code = [ 947 StoreTemp(expr=Invoke(expr=LoadAttr(name="__iter__", expr=self.dispatch(for_.list)), args=[], star=None, dstar=None)), 948 Invoke(expr=LoadRef(ref=subprogram), same_frame=1, produces_result=0, star=None, dstar=None, args=[]), 949 ReleaseTemp() 950 ] 951 return result 952 953 # Exception node transformations. 954 955 def visitTryFinally(self, tryfinally): 956 result = Try(tryfinally, body=[], else_=[], finally_=[]) 957 if tryfinally.body is not None: 958 result.body = self.dispatch(tryfinally.body) 959 if tryfinally.final is not None: 960 result.finally_ = self.dispatch(tryfinally.final) 961 return result 962 963 # vim: tabstop=4 expandtab shiftwidth=4