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