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