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