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): 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 55 def process(self, node): 56 self.visitor = self 57 return self.dispatch(node) 58 59 def dispatch_or_none(self, node, *args): 60 if node is not None: 61 return self.dispatch(node, *args) 62 else: 63 return LoadName(name="None") 64 65 # Placeholder or deletion transformations. 66 67 def visitStmt(self, stmt): 68 return self.dispatches(stmt.nodes) 69 70 def visitPass(self, pass_): 71 return Pass(pass_) 72 73 def visitDiscard(self, discard): 74 return self.dispatch(discard.expr) 75 76 # Relatively trivial transformations. 77 78 def visitModule(self, module): 79 self.result = Module(module) 80 self.result.code = self.dispatch(module.node) 81 return self.result 82 83 def visitGetattr(self, getattr): 84 result = LoadAttr(getattr, name=getattr.attrname) 85 result.expr = self.dispatch(getattr.expr) 86 return result 87 88 def visitKeyword(self, keyword): 89 result = Keyword(keyword, name=keyword.name) 90 result.expr = self.dispatch(keyword.expr) 91 return result 92 93 def visitGlobal(self, global_): 94 result = Global(global_, names=global_.names) 95 return result 96 97 def visitImport(self, import_): 98 result = Assign(import_) 99 code = [] 100 for path, alias in import_.names: 101 importer = Import(name=path) 102 top = alias or path.split(".")[0] 103 code.append(StoreName(expr=importer, name=top)) 104 result.code = code 105 return result 106 107 def visitFrom(self, from_): 108 result = Assign(from_) 109 code = [] 110 code.append(StoreTemp(expr=Import(name=from_.modname))) 111 for name, alias in from_.names: 112 code.append(StoreName(expr=LoadAttr(expr=LoadTemp(), name=name), name=(alias or name))) 113 result.code = code 114 return result 115 116 def visitName(self, name): 117 result = LoadName(name, name=name.name) 118 return result 119 120 def visitConst(self, const): 121 if not self.constants.has_key(const.value): 122 self.constants[const.value] = Constant(name=repr(const.value), value=const.value) 123 result = LoadRef(ref=self.constants[const.value]) 124 return result 125 126 def visitReturn(self, return_): 127 result = Return(return_) 128 result.expr = self.dispatch(return_.value) 129 return result 130 131 def visitBreak(self, break_): 132 result = Return(break_) 133 return result 134 135 def visitContinue(self, continue_): 136 result = Invoke(continue_, same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 137 result.expr = LoadRef(ref=self.current_subprograms[-1]) 138 return result 139 140 def visitRaise(self, raise_): 141 result = Raise(raise_, expr=self.dispatch(raise_.expr1), traceback=None) 142 if raise_.expr2 is not None: 143 result.args = [self.dispatch(raise_.expr2)] 144 if raise_.expr3 is not None: 145 result.traceback = self.dispatch(raise_.expr3) 146 return result 147 148 def _visitBuiltin(self, builtin, name): 149 result = Invoke(builtin, expr=LoadName(name=name)) 150 result.args = self.dispatches(builtin.nodes) 151 return result 152 153 def visitTuple(self, tuple): 154 return self._visitBuiltin(tuple, "tuple") 155 156 def visitList(self, list): 157 return self._visitBuiltin(list, "list") 158 159 def visitDict(self, dict): 160 result = Invoke(dict, expr=LoadName(name="dict")) 161 args = [] 162 for key, value in dict.items: 163 tuple = Invoke(expr=LoadName(name="tuple"), star=None, dstar=None) 164 tuple.args = [self.dispatch(key), self.dispatch(value)] 165 args.append(tuple) 166 result.args = args 167 return result 168 169 # Logical and comparison operations plus chained statements. 170 171 def visitIf(self, if_): 172 173 """ 174 Convert If(tests=..., else_=...) to: 175 176 Invoke -> Subprogram 177 Conditional (test) -> Invoke -> Subprogram (body) 178 Return 179 Conditional (test) -> Invoke -> Subprogram (body) 180 Return 181 ... 182 """ 183 184 # Make a subprogram for the statement and record it outside the main tree. 185 186 subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 187 self.current_subprograms.append(subprogram) 188 189 # In the subprogram, make conditionals for each test plus statement, 190 # adding a return onto the end of each statement block. 191 192 nodes = [] 193 for compare, stmt in if_.tests: 194 # Produce something like... 195 # expr.__true__() ? body 196 test = Conditional(else_=[], test=Invoke( 197 expr=LoadAttr(expr=self.dispatch(compare), name="__true__"), 198 args=[], star=None, dstar=None)) 199 200 body_subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 201 self.current_subprograms.append(body_subprogram) 202 203 body_subprogram.code = self.dispatch(stmt) + [Return()] 204 205 self.current_subprograms.pop() 206 self.subprograms.append(body_subprogram) 207 208 test.body = [Invoke(stmt, expr=LoadRef(ref=body_subprogram), same_frame=1, star=None, dstar=None, args=[]), Return()] 209 nodes.append(test) 210 211 # Add the compound statement from any else clause to the end. 212 213 if if_.else_ is not None: 214 else_subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 215 self.current_subprograms.append(else_subprogram) 216 217 else_subprogram.code = self.dispatch(if_.else_) + [Return()] 218 219 self.current_subprograms.pop() 220 self.subprograms.append(else_subprogram) 221 222 nodes.append(Invoke(stmt, expr=LoadRef(ref=else_subprogram), same_frame=1, star=None, dstar=None, args=[])) 223 224 subprogram.code = nodes 225 226 self.current_subprograms.pop() 227 self.subprograms.append(subprogram) 228 229 # Make an invocation of the subprogram. 230 231 result = Invoke(compare, same_frame=1, star=None, dstar=None, args=[]) 232 result.expr = LoadRef(ref=subprogram) 233 return result 234 235 def _visitTryExcept(self, tryexcept): 236 237 # Make a subprogram for the statement and record it outside the main tree. 238 239 subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 240 self.current_subprograms.append(subprogram) 241 242 # In the subprogram, make conditionals for each test plus statement, 243 # adding a return onto the end of each statement block. 244 245 nodes = [] 246 for spec, assign, stmt in tryexcept.handlers: 247 248 # If no specification exists, produce an unconditional block. 249 250 if spec is None: 251 nodes += self.dispatch(stmt) 252 253 # Produce something like... 254 # isinstance(<exc>, <spec>) 255 256 else: 257 new_spec = self.dispatch(spec) 258 test = Conditional(body=[], else_=[], test=Invoke(expr=LoadName(name="isinstance"), args=[LoadExc(), new_spec], star=None, dstar=None)) 259 if assign is not None: 260 test.body.append(Assign(code=[StoreTemp(expr=LoadExc()), self.dispatch(assign), ReleaseTemp()])) 261 test.body += self.dispatch(stmt) + [Return()] 262 nodes.append(test) 263 264 # Add a raise operation to deal with unhandled exceptions. 265 266 nodes.append(Raise(expr=LoadExc())) 267 subprogram.code = nodes 268 269 self.current_subprograms.pop() 270 self.subprograms.append(subprogram) 271 272 # Make an invocation of the subprogram. 273 274 result = Invoke(same_frame=1, star=None, dstar=None, args=[]) 275 result.expr = LoadRef(ref=subprogram) 276 return result 277 278 def visitTryExcept(self, tryexcept): 279 result = Try(tryexcept, body=[], else_=[], finally_=[]) 280 if tryexcept.body is not None: 281 result.body = self.dispatch(tryexcept.body) 282 if tryexcept.else_ is not None: 283 result.else_ = self.dispatch(tryexcept.else_) 284 result.handler = self._visitTryExcept(tryexcept) 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 # Make a subprogram for the expression and record it outside the main tree. 295 296 subprogram = Subprogram(name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 297 self.current_subprograms.append(subprogram) 298 299 # In the subprogram, make instructions which invoke a method on the 300 # first operand of each operand pair and, if appropriate, return with 301 # the value from that method. 302 303 nodes = [] 304 last = compare.ops[-1] 305 previous = self.dispatch(compare.expr) 306 for op in compare.ops: 307 op_name, node = op 308 expr = self.dispatch(node) 309 method_name = self.comparison_methods[op_name] 310 if method_name: 311 invocation = Invoke(expr=LoadAttr(expr=previous, name=method_name), args=[expr], star=None, dstar=None) 312 elif op_name == "is": 313 invocation = Invoke(expr=LoadName(name="__is__"), args=[previous, expr], star=None, dstar=None) 314 elif op_name == "is not": 315 invocation = Not(expr=Invoke(expr=LoadName(name="__is__"), args=[previous, expr], star=None, dstar=None)) 316 else: 317 raise NotImplementedError, op_name 318 nodes.append(StoreTemp(expr=invocation)) 319 if op is not last: 320 nodes.append(Conditional(test=Not(expr=LoadTemp()), body=[Return(expr=LoadTemp())])) 321 nodes.append(ReleaseTemp()) 322 else: 323 nodes.append(Return(expr=LoadTemp())) 324 previous = expr 325 subprogram.code = nodes 326 327 self.current_subprograms.pop() 328 self.subprograms.append(subprogram) 329 330 # Make an invocation of the subprogram. 331 332 result = Invoke(compare, same_frame=1, star=None, dstar=None, args=[]) 333 result.expr = LoadRef(ref=subprogram) 334 return result 335 336 def visitAnd(self, and_): 337 338 # Make a subprogram for the expression and record it outside the main tree. 339 340 subprogram = Subprogram(name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 341 self.current_subprograms.append(subprogram) 342 343 # In the subprogram, make instructions which store each operand, test 344 # for each operand's truth status, and if appropriate return from the 345 # subprogram with the value of the operand. 346 347 nodes = [] 348 last = and_.nodes[-1] 349 for node in and_.nodes: 350 expr = self.dispatch(node) 351 if node is not last: 352 nodes.append(StoreTemp(expr=expr)) 353 invocation = Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), args=[], star=None, dstar=None) 354 nodes.append(Conditional(test=Not(expr=invocation), body=[Return(expr=LoadTemp())])) 355 nodes.append(ReleaseTemp()) 356 else: 357 nodes.append(Return(expr=expr)) 358 subprogram.code = nodes 359 360 self.current_subprograms.pop() 361 self.subprograms.append(subprogram) 362 363 # Make an invocation of the subprogram. 364 365 result = Invoke(and_, same_frame=1, star=None, dstar=None, args=[]) 366 result.expr = LoadRef(ref=subprogram) 367 return result 368 369 def visitOr(self, or_): 370 371 # Make a subprogram for the expression and record it outside the main tree. 372 373 subprogram = Subprogram(name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 374 self.current_subprograms.append(subprogram) 375 376 # In the subprogram, make instructions which store each operand, test 377 # for each operand's truth status, and if appropriate return from the 378 # subprogram with the value of the operand. 379 380 nodes = [] 381 last = or_.nodes[-1] 382 for node in or_.nodes: 383 expr = self.dispatch(node) 384 if node is not last: 385 nodes.append(StoreTemp(expr=expr)) 386 invocation = Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), args=[], star=None, dstar=None) 387 nodes.append(Conditional(test=invocation, body=[Return(expr=LoadTemp())])) 388 nodes.append(ReleaseTemp()) 389 else: 390 nodes.append(Return(expr=expr)) 391 subprogram.code = nodes 392 393 self.current_subprograms.pop() 394 self.subprograms.append(subprogram) 395 396 # Make an invocation of the subprogram. 397 398 result = Invoke(or_, same_frame=1, star=None, dstar=None, args=[]) 399 result.expr = LoadRef(ref=subprogram) 400 return result 401 402 def visitNot(self, not_): 403 result = Not(not_, expr=Invoke(expr=LoadAttr(expr=self.dispatch(not_.expr), name="__true__"), 404 args=[], star=None, dstar=None)) 405 return result 406 407 # Operators. 408 409 def visitUnaryAdd(self, unaryadd): 410 return Invoke(unaryadd, expr=LoadAttr(expr=self.dispatch(unaryadd.expr), name="__pos__"), args=[]) 411 412 def visitUnarySub(self, unarysub): 413 return Invoke(unarysub, expr=LoadAttr(expr=self.dispatch(unarysub.expr), name="__neg__"), args=[]) 414 415 def visitInvert(self, invert): 416 return Invoke(invert, expr=LoadAttr(expr=self.dispatch(invert.expr), name="__invert__"), args=[]) 417 418 def visitAdd(self, add): 419 420 # NOTE: Strictly one of the choices must be evaluated, never more than one. 421 422 result = Choice(add) 423 result.choices = [ 424 Invoke(expr=LoadAttr(expr=self.dispatch(add.left), name="__add__"), args=[self.dispatch(add.right)]), 425 Invoke(expr=LoadAttr(expr=self.dispatch(add.right), name="__radd__"), args=[self.dispatch(add.left)]) 426 ] 427 return result 428 429 # Assignments. 430 431 augassign_methods = { 432 "+=" : "__iadd__", "-=" : "__isub__", "*=" : "__imul__", "/=" : "__idiv__", 433 "%=" : "__imod__", "**=" : "__ipow__", "<<=" : "__ilshift__", ">>=" : "__irshift__", 434 "&=" : "__iand__", "^=" : "__ixor__", "|=" : "__ior__" 435 } 436 437 def visitAugAssign(self, augassign): 438 result = Assign(augassign) 439 expr = self.dispatch(augassign.expr) 440 441 # Simple augmented assignment: name += expr 442 443 if isinstance(augassign.node, compiler.ast.Name): 444 name = augassign.node 445 node = self.dispatch(name) 446 get_incremented = StoreTemp( 447 expr=Invoke(expr=LoadAttr(expr=node, name=self.augassign_methods[augassign.op]), args=[expr]) 448 ) 449 store = StoreName(expr=LoadTemp(), name=name.name) 450 result.code = [get_incremented, store, ReleaseTemp()] 451 452 # Complicated augmented assignment: lvalue.attr += expr 453 454 elif isinstance(augassign.node, compiler.ast.Getattr): 455 456 # <lvalue> -> setattr(<lvalue>, getattr(<lvalue>, "attr").__xxx__(expr)) 457 458 getattr = augassign.node 459 store_expr = StoreTemp(index="expr", expr=self.dispatch(getattr.expr)) 460 node_attr = LoadAttr(expr=LoadTemp(index="expr"), name=getattr.attrname) 461 get_incremented = StoreTemp( 462 expr=Invoke(expr=LoadAttr(expr=node_attr, name=self.augassign_methods[augassign.op]), args=[expr]) 463 ) 464 store = StoreAttr(expr=LoadTemp(), lvalue=LoadTemp(index="expr"), name=getattr.attrname) 465 result.code = [store_expr, get_incremented, store, ReleaseTemp(index="expr"), ReleaseTemp()] 466 467 # Complicated augassign using slices: lvalue[lower:upper] += expr 468 469 elif isinstance(augassign.node, compiler.ast.Slice): 470 471 # <lvalue>, <lower>, <upper> -> <lvalue>.__setslice__(<lower>, <upper>, <lvalue>.__getslice__(<lower>, <upper>).__xxx__(expr)) 472 473 slice = augassign.node 474 store_expr = StoreTemp(index="expr", expr=self.dispatch(slice.expr)) 475 store_lower = StoreTemp(index="lower", expr=self.dispatch_or_none(slice.lower)) 476 store_upper = StoreTemp(index="upper", expr=self.dispatch_or_none(slice.upper)) 477 node_slice = self._visitSlice(slice, LoadTemp(index="expr"), LoadTemp(index="lower"), LoadTemp(index="upper"), "OP_APPLY") 478 get_incremented = StoreTemp( 479 expr=Invoke(expr=LoadAttr(expr=node_slice, name=self.augassign_methods[augassign.op]), args=[expr]) 480 ) 481 store = self._visitSlice(slice, LoadTemp(index="expr"), LoadTemp(index="lower"), LoadTemp(index="upper"), "OP_ASSIGN", LoadTemp()) 482 result.code = [store_expr, store_lower, store_upper, get_incremented, store, 483 ReleaseTemp(index="expr"), ReleaseTemp(index="lower"), ReleaseTemp(index="upper"), ReleaseTemp()] 484 485 # Complicated augassign using subscripts: lvalue[subs] += expr 486 487 elif isinstance(augassign.node, compiler.ast.Subscript): 488 489 # <lvalue>, <subs> -> <lvalue>.__setitem__(<subs>, <lvalue>.__getitem__(<subs>).__xxx__(expr)) 490 491 subscript = augassign.node 492 store_expr = StoreTemp(index="expr", expr=self.dispatch(subscript.expr)) 493 subs = self._visitSubscriptSubs(subscript.subs) 494 store_subs = StoreTemp(index="subs", expr=subs) 495 node_subscript = self._visitSubscript(subscript, LoadTemp(index="expr"), LoadTemp(index="subs"), "OP_APPLY") 496 get_incremented = StoreTemp( 497 expr=Invoke(expr=LoadAttr(expr=node_subscript, name=self.augassign_methods[augassign.op]), args=[expr]) 498 ) 499 store = self._visitSubscript(subscript, LoadTemp(index="expr"), LoadTemp(index="subs"), "OP_ASSIGN", LoadTemp()) 500 result.code = [store_expr, store_subs, get_incremented, store, ReleaseTemp(index="expr"), ReleaseTemp(index="subs"), ReleaseTemp()] 501 502 else: 503 raise NotImplementedError, augassign.node.__class__ 504 505 return result 506 507 def visitAssign(self, assign): 508 result = Assign(assign) 509 store = StoreTemp(expr=self.dispatch(assign.expr)) 510 release = ReleaseTemp() 511 result.code = [store] + self.dispatches(assign.nodes, 0) + [release] 512 return result 513 514 def visitAssList(self, asslist, in_sequence=0): 515 if not in_sequence: 516 expr = LoadTemp() 517 else: 518 expr = Invoke(expr=LoadAttr(expr=LoadTemp(), name="next")) 519 result = Assign(asslist) 520 store = StoreTemp(expr=Invoke(expr=LoadAttr(name="__iter__", expr=expr))) 521 release = ReleaseTemp() 522 result.code = [store] + self.dispatches(asslist.nodes, 1) + [release] 523 return result 524 525 visitAssTuple = visitAssList 526 527 def _visitAssNameOrAttr(self, node, in_sequence): 528 if not in_sequence: 529 return LoadTemp() 530 else: 531 return Invoke(expr=LoadAttr(expr=LoadTemp(), name="next")) 532 533 def visitAssName(self, assname, in_sequence=0): 534 expr = self._visitAssNameOrAttr(assname, in_sequence) 535 result = StoreName(assname, name=assname.name, expr=expr) 536 return result 537 538 def visitAssAttr(self, assattr, in_sequence=0): 539 expr = self._visitAssNameOrAttr(assattr, in_sequence) 540 lvalue = self.dispatch(assattr.expr) 541 result = StoreAttr(assattr, name=assattr.attrname, lvalue=lvalue, expr=expr) 542 return result 543 544 def _visitSlice(self, slice, expr, lower, upper, flags, value=None): 545 if flags == "OP_ASSIGN": 546 args = [value] 547 result = Invoke(expr=LoadAttr(expr=expr, name="__setslice__")) 548 elif flags == "OP_APPLY": 549 args = [] 550 result = Invoke(expr=LoadAttr(expr=expr, name="__getslice__")) 551 elif flags == "OP_DELETE": 552 args = [] 553 result = Invoke(expr=LoadAttr(expr=expr, name="__delslice__")) 554 else: 555 raise NotImplementedError, flags 556 557 # Add the dimensions. 558 559 args.insert(0, lower) 560 args.insert(1, upper) 561 562 result.original = slice 563 result.args = args 564 return result 565 566 def visitSlice(self, slice, in_sequence=0): 567 value = self._visitAssNameOrAttr(slice, in_sequence) 568 return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower), 569 self.dispatch_or_none(slice.upper), slice.flags, value) 570 571 def _visitSubscript(self, subscript, expr, subs, flags, value=None): 572 if flags == "OP_ASSIGN": 573 args = [value] 574 result = Invoke(expr=LoadAttr(expr=expr, name="__setitem__")) 575 elif flags == "OP_APPLY": 576 args = [] 577 result = Invoke(expr=LoadAttr(expr=expr, name="__getitem__")) 578 elif flags == "OP_DELETE": 579 args = [] 580 result = Invoke(expr=LoadAttr(expr=expr, name="__delitem__")) 581 else: 582 raise NotImplementedError, flags 583 584 # Add the dimensions. 585 586 args.insert(0, subs) 587 588 result.original = subscript 589 result.args = args 590 return result 591 592 def _visitSubscriptSubs(self, subs): 593 if len(subs) == 1: 594 return self.dispatch(subs[0]) 595 else: 596 return Invoke(expr=LoadName(name="tuple"), args=self.dispatches(subs)) 597 598 def visitSubscript(self, subscript, in_sequence=0): 599 value = self._visitAssNameOrAttr(subscript, in_sequence) 600 subs = self._visitSubscriptSubs(subscript.subs) 601 return self._visitSubscript(subscript, self.dispatch(subscript.expr), subs, subscript.flags, value) 602 603 # Invocation and subprogram transformations. 604 605 def visitClass(self, class_): 606 structure = Class(name=class_.name, bases=self.dispatches(class_.bases)) 607 self.structures.append(structure) 608 609 # Make a subprogram which initialises the class structure. 610 611 subprogram = Subprogram(name=None, structure=structure, params=[], star=None, dstar=None) 612 self.current_subprograms.append(subprogram) 613 614 # The class is initialised using the code found inside. 615 616 subprogram.code = self.dispatch(class_.code) 617 618 self.current_subprograms.pop() 619 self.subprograms.append(subprogram) 620 621 # Make a definition of the class associating it with a name. 622 623 result = Assign(class_) 624 store = StoreName(name=class_.name, expr=LoadRef(ref=structure)) 625 init = Invoke(expr=LoadRef(ref=subprogram), args=[], star=None, dstar=None) 626 result.code = [store, init] 627 return result 628 629 def _visitFunction(self, function, subprogram): 630 if function.flags & 4 != 0: has_star = 1 631 else: has_star = 0 632 if function.flags & 8 != 0: has_dstar = 1 633 else: has_dstar = 0 634 ndefaults = len(function.defaults) 635 npositional = len(function.argnames) - has_star - has_dstar 636 637 # Produce star and dstar parameters with appropriate defaults. 638 639 if has_star: 640 star = (function.argnames[npositional], Invoke(expr=LoadName(name="list"), args=[], star=None, dstar=None)) 641 else: 642 star = None 643 if has_dstar: 644 dstar = (function.argnames[npositional + has_star], Invoke(expr=LoadName(name="dict"), args=[], star=None, dstar=None)) 645 else: 646 dstar = None 647 648 params = [] 649 for i in range(0, npositional - ndefaults): 650 params.append((function.argnames[i], None)) 651 652 # NOTE: Fix/process defaults. 653 654 for i in range(0, ndefaults): 655 default = function.defaults[i] 656 if default is not None: 657 params.append((function.argnames[npositional - ndefaults + i], self.dispatch(default))) 658 else: 659 params.append((function.argnames[npositional - ndefaults + i], default)) 660 661 subprogram.params = params 662 subprogram.star = star 663 subprogram.dstar = dstar 664 self.subprograms.append(subprogram) 665 666 def visitFunction(self, function): 667 668 # Make a subprogram for the function and record it outside the main 669 # tree. 670 671 subprogram = Subprogram(name=function.name, returns_value=1, star=None, dstar=None) 672 self.current_subprograms.append(subprogram) 673 subprogram.code = self.dispatch(function.code) 674 self.current_subprograms.pop() 675 self._visitFunction(function, subprogram) 676 677 # Make a definition of the function associating it with a name. 678 679 result = StoreName(name=function.name, expr=LoadRef(ref=subprogram)) 680 return result 681 682 def visitLambda(self, lambda_): 683 684 # Make a subprogram for the function and record it outside the main 685 # tree. 686 687 subprogram = Subprogram(name=None, returns_value=1, star=None, dstar=None) 688 self.current_subprograms.append(subprogram) 689 subprogram.code = [Return(expr=self.dispatch(lambda_.code))] 690 self.current_subprograms.pop() 691 self._visitFunction(lambda_, subprogram) 692 693 # Get the subprogram reference to the lambda. 694 695 return LoadRef(lambda_, ref=subprogram) 696 697 def visitCallFunc(self, callfunc): 698 result = Invoke(callfunc, same_frame=0, star=None, dstar=None) 699 result.args = self.dispatches(callfunc.args) 700 if callfunc.star_args is not None: 701 result.star = self.dispatch(callfunc.star_args) 702 if callfunc.dstar_args is not None: 703 result.dstar = self.dispatch(callfunc.dstar_args) 704 result.expr = self.dispatch(callfunc.node) 705 return result 706 707 def visitWhile(self, while_): 708 709 # Make a subprogram for the block and record it outside the main tree. 710 711 subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 712 self.current_subprograms.append(subprogram) 713 714 # Include a conditional statement in the subprogram. 715 716 test = Conditional(else_=[]) 717 test.test = Invoke(expr=LoadAttr(expr=self.dispatch(while_.test), name="__true__"), 718 args=[], star=None, dstar=None) 719 720 # Inside the conditional, add a recursive invocation to the subprogram 721 # if the test condition was satisfied. 722 723 continuation = Invoke(same_frame=1, star=None, dstar=None, args=[]) 724 continuation.expr = LoadRef(ref=subprogram) 725 test.body = self.dispatch(while_.body) + [continuation] 726 if while_.else_ is not None: 727 test.else_ = self.dispatch(while_.else_) 728 subprogram.code = [test] 729 730 self.current_subprograms.pop() 731 self.subprograms.append(subprogram) 732 733 # Make an invocation of the subprogram. 734 735 result = Invoke(while_, same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 736 result.expr = LoadRef(ref=subprogram) 737 return result 738 739 def visitFor(self, for_): 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 if for_.else_ is not None: 747 else_stmt = self.dispatch(for_.else_) 748 else: 749 else_stmt = [] 750 751 # Wrap the assignment in a try...except statement. 752 753 try_except = Try(body=[], else_=[], finally_=[]) 754 try_except.handler = Conditional(test=Invoke(expr=LoadName(name="isinstance"), 755 args=[LoadExc(), LoadName(name="StopIteration")], star=None, dstar=None), 756 body=else_stmt, else_=[Raise(expr=LoadExc())]) 757 758 assign = Assign() 759 assign.code = [ 760 StoreTemp(expr=Invoke(expr=LoadAttr(expr=LoadTemp(), name="next"))), 761 self.dispatch(for_.assign), 762 ReleaseTemp() 763 ] 764 765 # Inside the conditional, add a recursive invocation to the subprogram 766 # if the test condition was satisfied. 767 768 continuation = Invoke(same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 769 continuation.expr = LoadRef(ref=subprogram) 770 try_except.body = [assign] + self.dispatch(for_.body) + [continuation] 771 subprogram.code = [try_except] 772 773 self.subprograms.append(subprogram) 774 self.current_subprograms.pop() 775 776 # Obtain an iterator for the sequence involved. 777 # Then, make an invocation of the subprogram. 778 779 result = Assign(for_) 780 result.code = [ 781 StoreTemp(expr=Invoke(expr=LoadAttr(name="__iter__", expr=self.dispatch(for_.list)))), 782 Invoke(expr=LoadRef(ref=subprogram), same_frame=1, produces_result=0, star=None, dstar=None, args=[]), 783 ReleaseTemp() 784 ] 785 return result 786 787 # Exception node transformations. 788 789 def visitTryFinally(self, tryfinally): 790 result = Try(tryfinally, body=[], else_=[], finally_=[]) 791 if tryfinally.body is not None: 792 result.body = self.dispatch(tryfinally.body) 793 if tryfinally.final is not None: 794 result.finally_ = self.dispatch(tryfinally.final) 795 return result 796 797 # vim: tabstop=4 expandtab shiftwidth=4