1 #!/usr/bin/env python 2 3 """ 4 Simplify AST structures for easier type propagation and analysis. 5 6 Copyright (C) 2006 Paul Boddie <paul@boddie.org.uk> 7 8 This software is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License as 10 published by the Free Software Foundation; either version 2 of 11 the License, or (at your option) any later version. 12 13 This software is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public 19 License along with this library; see the file LICENCE.txt 20 If not, write to the Free Software Foundation, Inc., 21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 22 """ 23 24 from compiler.visitor import ASTVisitor 25 import compiler.ast 26 from simplified import * 27 28 class Simplifier(ASTVisitor): 29 30 """ 31 A simplifying visitor for AST nodes. 32 33 Covered: And, AssAttr, AssList, AssName, AssTuple, Assign, AugAssign, Break, 34 CallFunc, Class, Compare, Const, Continue, Dict, Discard, For, 35 From, Function, Getattr, Global, If, Import, Invert, Keyword, 36 Lambda, List, Module, Name, Not, Or, Pass, Raise, Return, Slice, 37 Stmt, Subscript, TryExcept, TryFinally, Tuple, While, UnaryAdd, 38 UnarySub. 39 40 Missing: Add, Assert, Backquote, Bitand, Bitor, Bitxor, Decorators, Div, 41 Ellipsis, Exec, FloorDiv, LeftShift, ListComp, ListCompFor, 42 ListCompIf, Mod, Mul, Power, Print, Printnl, RightShift, Sliceobj, 43 Sub, Yield. 44 """ 45 46 def __init__(self): 47 ASTVisitor.__init__(self) 48 self.result = None # The resulting tree. 49 self.subprograms = [] # Subprograms outside the tree. 50 self.current_subprograms = [] # Current subprograms being processed. 51 52 # Generic visitor methods. 53 54 def default(self, node, *args): 55 raise ValueError, node.__class__ 56 57 def dispatch(self, node, *args): 58 return ASTVisitor.dispatch(self, node, *args) 59 60 def dispatches(self, nodes, *args): 61 results = [] 62 for node in nodes: 63 results.append(self.dispatch(node, *args)) 64 return results 65 66 def dispatch_or_none(self, node, *args): 67 if node is not None: 68 return self.dispatch(node, *args) 69 else: 70 return LoadName(name="None") 71 72 # Placeholder or deletion transformations. 73 74 def visitStmt(self, stmt): 75 return self.dispatches(stmt.nodes) 76 77 def visitPass(self, pass_): 78 return Pass(pass_) 79 80 def visitDiscard(self, discard): 81 return self.dispatch(discard.expr) 82 83 # Relatively trivial transformations. 84 85 def visitModule(self, module): 86 self.result = Module(module) 87 self.result.code = self.dispatch(module.node) 88 return self.result 89 90 def visitClass(self, class_): 91 structure = Class(name=hex(id(class_)), bases=class_.bases) 92 93 subprogram = Subprogram(name=hex(id(class_)), acquire_locals=1, structure=structure, params=[], star=None, dstar=None) 94 self.current_subprograms.append(subprogram) 95 96 subprogram.code = self.dispatch(class_.code) 97 98 self.current_subprograms.pop() 99 self.subprograms.append(subprogram) 100 101 # Make a definition of the class associating it with a name. 102 103 result = Assign(class_) 104 init = Invoke(expr=LoadRef(ref=subprogram), args=[], star=None, dstar=None) 105 load = LoadRef(ref=structure) 106 store = StoreName(name=class_.name) 107 result.code = [init, load, store] 108 return result 109 110 def visitGetattr(self, getattr): 111 result = LoadAttr(getattr, name=getattr.attrname) 112 result.expr = self.dispatch(getattr.expr) 113 return result 114 115 def visitKeyword(self, keyword): 116 result = Keyword(keyword, name=keyword.name) 117 result.expr = self.dispatch(keyword.expr) 118 return result 119 120 def visitGlobal(self, global_): 121 result = Global(global_, names=global_.names) 122 return result 123 124 def visitImport(self, import_): 125 result = Assign(import_) 126 code = [] 127 for path, alias in import_.names: 128 importer = Import(name=path) 129 top = alias or path.split(".")[0] 130 code.append(StoreName(expr=importer, name=top)) 131 result.code = code 132 return result 133 134 def visitFrom(self, from_): 135 result = Assign(from_) 136 code = [] 137 code.append(StoreTemp(expr=Import(name=from_.modname))) 138 for name, alias in from_.names: 139 code.append(StoreName(expr=LoadAttr(expr=LoadTemp(), name=name), name=(alias or name))) 140 result.code = code 141 return result 142 143 def visitName(self, name): 144 result = LoadName(name, name=name.name) 145 return result 146 147 def visitConst(self, const): 148 result = LoadConst(const, value=const.value) 149 return result 150 151 def visitReturn(self, return_): 152 result = Return(return_) 153 result.expr = self.dispatch(return_.value) 154 return result 155 156 def visitBreak(self, break_): 157 result = Return(break_) 158 return result 159 160 def visitContinue(self, continue_): 161 result = Invoke(continue_, same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 162 result.expr = LoadRef(ref=self.current_subprograms[-1]) 163 return result 164 165 def visitRaise(self, raise_): 166 result = Raise(raise_, expr=self.dispatch(raise_.expr1), traceback=None) 167 if raise_.expr2 is not None: 168 result.args = [self.dispatch(raise_.expr2)] 169 if raise_.expr3 is not None: 170 result.traceback = self.dispatch(raise_.expr3) 171 return result 172 173 def _visitBuiltin(self, builtin, name): 174 result = Invoke(builtin, expr=LoadName(name=name)) 175 result.args = self.dispatches(builtin.nodes) 176 return result 177 178 def visitTuple(self, tuple): 179 return self._visitBuiltin(tuple, "Tuple") 180 181 def visitList(self, list): 182 return self._visitBuiltin(list, "List") 183 184 def visitDict(self, dict): 185 result = Invoke(dict, expr=LoadName(name="Dict")) 186 args = [] 187 for key, value in dict.items: 188 tuple = Invoke(expr=LoadName(name="Tuple"), star=None, dstar=None) 189 tuple.args = [self.dispatch(key), self.dispatch(value)] 190 args.append(tuple) 191 result.args = args 192 return result 193 194 # Logical and comparison operations plus chained statements. 195 196 def visitIf(self, if_): 197 198 # Make a subprogram for the statement and record it outside the main tree. 199 200 subprogram = Subprogram(name=hex(id(if_)), acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 201 self.current_subprograms.append(subprogram) 202 203 # In the subprogram, make conditionals for each test plus statement, 204 # adding a return onto the end of each statement block. 205 206 nodes = [] 207 for compare, stmt in if_.tests: 208 # Produce something like... 209 # expr.__true__() ? body 210 test = Conditional(else_=[], test=Invoke( 211 expr=LoadAttr(expr=self.dispatch(compare), name="__true__"), 212 args=[], star=None, dstar=None)) 213 test.body = self.dispatch(stmt) + [Return()] 214 nodes.append(test) 215 216 # Add the compound statement from any else clause to the end. 217 218 if if_.else_ is not None: 219 nodes += self.dispatch(if_.else_) 220 221 subprogram.code = nodes 222 223 self.current_subprograms.pop() 224 self.subprograms.append(subprogram) 225 226 # Make an invocation of the subprogram. 227 228 result = Invoke(compare, same_frame=1, star=None, dstar=None, args=[]) 229 result.expr = LoadRef(ref=subprogram) 230 return result 231 232 def _visitTryExcept(self, tryexcept): 233 234 # Make a subprogram for the statement and record it outside the main tree. 235 236 subprogram = Subprogram(name=hex(id(tryexcept)), acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 237 self.current_subprograms.append(subprogram) 238 239 # In the subprogram, make conditionals for each test plus statement, 240 # adding a return onto the end of each statement block. 241 242 nodes = [] 243 for spec, assign, stmt in tryexcept.handlers: 244 245 # If no specification exists, produce an unconditional block. 246 247 if spec is None: 248 nodes += self.dispatch(stmt) 249 250 # Produce something like... 251 # isinstance(<exc>, <spec>) 252 253 else: 254 new_spec = self.dispatch(spec) 255 test = Conditional(body=[], else_=[], test=Invoke(expr=LoadName(name="isinstance"), args=[LoadExc(), new_spec], star=None, dstar=None)) 256 if assign is not None: 257 test.body.append(Assign(code=[StoreTemp(expr=LoadExc()), self.dispatch(assign), ReleaseTemp()])) 258 test.body += self.dispatch(stmt) + [Return()] 259 nodes.append(test) 260 261 # Add a raise operation to deal with unhandled exceptions. 262 263 nodes.append(Raise(expr=LoadExc())) 264 subprogram.code = nodes 265 266 self.current_subprograms.pop() 267 self.subprograms.append(subprogram) 268 269 # Make an invocation of the subprogram. 270 271 result = Invoke(same_frame=1, star=None, dstar=None, args=[]) 272 result.expr = LoadRef(ref=subprogram) 273 return result 274 275 def visitTryExcept(self, tryexcept): 276 result = Try(tryexcept, body=[], else_=[], finally_=[]) 277 if tryexcept.body is not None: 278 result.body = self.dispatch(tryexcept.body) 279 if tryexcept.else_ is not None: 280 result.else_ = self.dispatch(tryexcept.else_) 281 result.handler = self._visitTryExcept(tryexcept) 282 return result 283 284 comparison_methods = { 285 "==" : "__eq__", "!=" : "__ne__", "<" : "__lt__", "<=" : "__le__", 286 ">=" : "__ge__", ">" : "__gt__", "is" : None, "is not" : None 287 } 288 289 def visitCompare(self, compare): 290 291 # Make a subprogram for the expression and record it outside the main tree. 292 293 subprogram = Subprogram(name=hex(id(compare)), acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 294 self.current_subprograms.append(subprogram) 295 296 # In the subprogram, make instructions which invoke a method on the 297 # first operand of each operand pair and, if appropriate, return with 298 # the value from that method. 299 300 nodes = [] 301 last = compare.ops[-1] 302 previous = self.dispatch(compare.expr) 303 for op in compare.ops: 304 op_name, node = op 305 expr = self.dispatch(node) 306 method_name = self.comparison_methods[op_name] 307 if method_name: 308 invocation = Invoke(expr=LoadAttr(expr=previous, name=method_name), args=[expr], star=None, dstar=None) 309 elif op_name == "is": 310 invocation = Invoke(expr=LoadName(name="__is__"), args=[previous, expr], star=None, dstar=None) 311 elif op_name == "is not": 312 invocation = Not(expr=Invoke(expr=LoadName(name="__is__"), args=[previous, expr], star=None, dstar=None)) 313 else: 314 raise NotImplementedError, op_name 315 nodes.append(StoreTemp(expr=invocation)) 316 if op is not last: 317 nodes.append(Conditional(test=Not(expr=LoadTemp()), body=[Return(expr=LoadTemp())])) 318 nodes.append(ReleaseTemp()) 319 else: 320 nodes.append(Return(expr=LoadTemp())) 321 previous = expr 322 subprogram.code = nodes 323 324 self.current_subprograms.pop() 325 self.subprograms.append(subprogram) 326 327 # Make an invocation of the subprogram. 328 329 result = Invoke(compare, same_frame=1, star=None, dstar=None, args=[]) 330 result.expr = LoadRef(ref=subprogram) 331 return result 332 333 def visitAnd(self, and_): 334 335 # Make a subprogram for the expression and record it outside the main tree. 336 337 subprogram = Subprogram(name=hex(id(and_)), acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 338 self.current_subprograms.append(subprogram) 339 340 # In the subprogram, make instructions which store each operand, test 341 # for each operand's truth status, and if appropriate return from the 342 # subprogram with the value of the operand. 343 344 nodes = [] 345 last = and_.nodes[-1] 346 for node in and_.nodes: 347 expr = self.dispatch(node) 348 if node is not last: 349 nodes.append(StoreTemp(expr=expr)) 350 invocation = Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), args=[], star=None, dstar=None) 351 nodes.append(Conditional(test=Not(expr=invocation), body=[Return(expr=LoadTemp())])) 352 nodes.append(ReleaseTemp()) 353 else: 354 nodes.append(Return(expr=expr)) 355 subprogram.code = nodes 356 357 self.current_subprograms.pop() 358 self.subprograms.append(subprogram) 359 360 # Make an invocation of the subprogram. 361 362 result = Invoke(and_, same_frame=1, star=None, dstar=None, args=[]) 363 result.expr = LoadRef(ref=subprogram) 364 return result 365 366 def visitOr(self, or_): 367 368 # Make a subprogram for the expression and record it outside the main tree. 369 370 subprogram = Subprogram(name=hex(id(or_)), acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 371 self.current_subprograms.append(subprogram) 372 373 # In the subprogram, make instructions which store each operand, test 374 # for each operand's truth status, and if appropriate return from the 375 # subprogram with the value of the operand. 376 377 nodes = [] 378 last = or_.nodes[-1] 379 for node in or_.nodes: 380 expr = self.dispatch(node) 381 if node is not last: 382 nodes.append(StoreTemp(expr=expr)) 383 invocation = Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), args=[], star=None, dstar=None) 384 nodes.append(Conditional(test=invocation, body=[Return(expr=LoadTemp())])) 385 nodes.append(ReleaseTemp()) 386 else: 387 nodes.append(Return(expr=expr)) 388 subprogram.code = nodes 389 390 self.current_subprograms.pop() 391 self.subprograms.append(subprogram) 392 393 # Make an invocation of the subprogram. 394 395 result = Invoke(or_, same_frame=1, star=None, dstar=None, args=[]) 396 result.expr = LoadRef(ref=subprogram) 397 return result 398 399 def visitNot(self, not_): 400 result = Not(not_, expr=Invoke(expr=LoadAttr(expr=self.dispatch(not_.expr), name="__true__"), 401 args=[], star=None, dstar=None)) 402 return result 403 404 # Operators. 405 406 def visitUnaryAdd(self, unaryadd): 407 return Invoke(unaryadd, expr=LoadAttr(expr=self.dispatch(unaryadd.expr), name="__pos__"), args=[]) 408 409 def visitUnarySub(self, unarysub): 410 return Invoke(unarysub, expr=LoadAttr(expr=self.dispatch(unarysub.expr), name="__neg__"), args=[]) 411 412 def visitInvert(self, invert): 413 return Invoke(invert, expr=LoadAttr(expr=self.dispatch(invert.expr), name="__invert__"), args=[]) 414 415 # Assignments. 416 417 augassign_methods = { 418 "+=" : "__iadd__", "-=" : "__isub__", "*=" : "__imul__", "/=" : "__idiv__", 419 "%=" : "__imod__", "**=" : "__ipow__", "<<=" : "__ilshift__", ">>=" : "__irshift__", 420 "&=" : "__iand__", "^=" : "__ixor__", "|=" : "__ior__" 421 } 422 423 def visitAugAssign(self, augassign): 424 result = Assign(augassign) 425 expr = self.dispatch(augassign.expr) 426 427 # Simple augmented assignment: name += expr 428 429 if isinstance(augassign.node, compiler.ast.Name): 430 name = augassign.node 431 node = self.dispatch(name) 432 get_incremented = StoreTemp( 433 expr=Invoke(expr=LoadAttr(expr=node, name=self.augassign_methods[augassign.op]), args=[expr]) 434 ) 435 store = StoreName(expr=LoadTemp(), name=name.name) 436 result.code = [get_incremented, store, ReleaseTemp()] 437 438 # Complicated augmented assignment: lvalue.attr += expr 439 440 elif isinstance(augassign.node, compiler.ast.Getattr): 441 442 # <lvalue> -> setattr(<lvalue>, getattr(<lvalue>, "attr").__xxx__(expr)) 443 444 getattr = augassign.node 445 store_expr = StoreTemp(index="expr", expr=self.dispatch(getattr.expr)) 446 node_attr = LoadAttr(expr=LoadTemp(index="expr"), name=getattr.attrname) 447 get_incremented = StoreTemp( 448 expr=Invoke(expr=LoadAttr(expr=node_attr, name=self.augassign_methods[augassign.op]), args=[expr]) 449 ) 450 store = StoreAttr(expr=LoadTemp(), lvalue=LoadTemp(index="expr"), name=getattr.attrname) 451 result.code = [store_expr, get_incremented, store, ReleaseTemp(index="expr"), ReleaseTemp()] 452 453 # Complicated augassign using slices: lvalue[lower:upper] += expr 454 455 elif isinstance(augassign.node, compiler.ast.Slice): 456 457 # <lvalue>, <lower>, <upper> -> <lvalue>.__setslice__(<lower>, <upper>, <lvalue>.__getslice__(<lower>, <upper>).__xxx__(expr)) 458 459 slice = augassign.node 460 store_expr = StoreTemp(index="expr", expr=self.dispatch(slice.expr)) 461 store_lower = StoreTemp(index="lower", expr=self.dispatch_or_none(slice.lower)) 462 store_upper = StoreTemp(index="upper", expr=self.dispatch_or_none(slice.upper)) 463 node_slice = self._visitSlice(slice, LoadTemp(index="expr"), LoadTemp(index="lower"), LoadTemp(index="upper"), "OP_APPLY") 464 get_incremented = StoreTemp( 465 expr=Invoke(expr=LoadAttr(expr=node_slice, name=self.augassign_methods[augassign.op]), args=[expr]) 466 ) 467 store = self._visitSlice(slice, LoadTemp(index="expr"), LoadTemp(index="lower"), LoadTemp(index="upper"), "OP_ASSIGN", LoadTemp()) 468 result.code = [store_expr, store_lower, store_upper, get_incremented, store, 469 ReleaseTemp(index="expr"), ReleaseTemp(index="lower"), ReleaseTemp(index="upper"), ReleaseTemp()] 470 471 # Complicated augassign using subscripts: lvalue[subs] += expr 472 473 elif isinstance(augassign.node, compiler.ast.Subscript): 474 475 # <lvalue>, <subs> -> <lvalue>.__setitem__(<subs>, <lvalue>.__getitem__(<subs>).__xxx__(expr)) 476 477 subscript = augassign.node 478 store_expr = StoreTemp(index="expr", expr=self.dispatch(subscript.expr)) 479 subs = self._visitSubscriptSubs(subscript.subs) 480 store_subs = StoreTemp(index="subs", expr=subs) 481 node_subscript = self._visitSubscript(subscript, LoadTemp(index="expr"), LoadTemp(index="subs"), "OP_APPLY") 482 get_incremented = StoreTemp( 483 expr=Invoke(expr=LoadAttr(expr=node_subscript, name=self.augassign_methods[augassign.op]), args=[expr]) 484 ) 485 store = self._visitSubscript(subscript, LoadTemp(index="expr"), LoadTemp(index="subs"), "OP_ASSIGN", LoadTemp()) 486 result.code = [store_expr, store_subs, get_incremented, store, ReleaseTemp(index="expr"), ReleaseTemp(index="subs"), ReleaseTemp()] 487 488 else: 489 raise NotImplementedError, augassign.node.__class__ 490 491 return result 492 493 def visitAssign(self, assign): 494 result = Assign(assign) 495 store = StoreTemp(expr=self.dispatch(assign.expr)) 496 release = ReleaseTemp() 497 result.code = [store] + self.dispatches(assign.nodes, 0) + [release] 498 return result 499 500 def visitAssList(self, asslist, in_sequence=0): 501 if not in_sequence: 502 expr = LoadTemp() 503 else: 504 expr = Invoke(expr=LoadAttr(expr=LoadTemp(), name="next")) 505 result = Assign(asslist) 506 store = StoreTemp(expr=Invoke(expr=LoadAttr(name="__iter__", expr=expr))) 507 release = ReleaseTemp() 508 result.code = [store] + self.dispatches(asslist.nodes, 1) + [release] 509 return result 510 511 visitAssTuple = visitAssList 512 513 def _visitAssNameOrAttr(self, node, in_sequence): 514 if not in_sequence: 515 return LoadTemp() 516 else: 517 return Invoke(expr=LoadAttr(expr=LoadTemp(), name="next")) 518 519 def visitAssName(self, assname, in_sequence=0): 520 expr = self._visitAssNameOrAttr(assname, in_sequence) 521 result = StoreName(assname, name=assname.name, expr=expr) 522 return result 523 524 def visitAssAttr(self, assattr, in_sequence=0): 525 expr = self._visitAssNameOrAttr(assattr, in_sequence) 526 lvalue = self.dispatch(assattr.expr) 527 result = StoreAttr(assattr, name=assattr.attrname, lvalue=lvalue, expr=expr) 528 return result 529 530 def _visitSlice(self, slice, expr, lower, upper, flags, value=None): 531 if flags == "OP_ASSIGN": 532 args = [value] 533 result = Invoke(expr=LoadAttr(expr=expr, name="__setslice__")) 534 elif flags == "OP_APPLY": 535 args = [] 536 result = Invoke(expr=LoadAttr(expr=expr, name="__getslice__")) 537 elif flags == "OP_DELETE": 538 args = [] 539 result = Invoke(expr=LoadAttr(expr=expr, name="__delslice__")) 540 else: 541 raise NotImplementedError, flags 542 543 # Add the dimensions. 544 545 args.insert(0, lower) 546 args.insert(1, upper) 547 548 result.original = slice 549 result.args = args 550 return result 551 552 def visitSlice(self, slice, in_sequence=0): 553 value = self._visitAssNameOrAttr(slice, in_sequence) 554 return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower), 555 self.dispatch_or_none(slice.upper), slice.flags, value) 556 557 def _visitSubscript(self, subscript, expr, subs, flags, value=None): 558 if flags == "OP_ASSIGN": 559 args = [value] 560 result = Invoke(expr=LoadAttr(expr=expr, name="__setitem__")) 561 elif flags == "OP_APPLY": 562 args = [] 563 result = Invoke(expr=LoadAttr(expr=expr, name="__getitem__")) 564 elif flags == "OP_DELETE": 565 args = [] 566 result = Invoke(expr=LoadAttr(expr=expr, name="__delitem__")) 567 else: 568 raise NotImplementedError, flags 569 570 # Add the dimensions. 571 572 args.insert(0, subs) 573 574 result.original = subscript 575 result.args = args 576 return result 577 578 def _visitSubscriptSubs(self, subs): 579 if len(subs) == 1: 580 return self.dispatch(subs[0]) 581 else: 582 return Invoke(expr=LoadName(name="Tuple"), args=self.dispatches(subs)) 583 584 def visitSubscript(self, subscript, in_sequence=0): 585 value = self._visitAssNameOrAttr(subscript, in_sequence) 586 subs = self._visitSubscriptSubs(subscript.subs) 587 return self._visitSubscript(subscript, self.dispatch(subscript.expr), subs, subscript.flags, value) 588 589 # Invocation and subprogram transformations. 590 591 def _visitFunction(self, function, subprogram): 592 if function.flags & 4 != 0: has_star = 1 593 else: has_star = 0 594 if function.flags & 8 != 0: has_dstar = 1 595 else: has_dstar = 0 596 ndefaults = len(function.defaults) 597 npositional = len(function.argnames) - has_star - has_dstar 598 if has_star: star = function.argnames[npositional] 599 else: star = None 600 if has_dstar: dstar = function.argnames[npositional + has_star] 601 else: dstar = None 602 603 params = [] 604 for i in range(0, npositional - ndefaults): 605 params.append((function.argnames[i], None)) 606 607 # NOTE: Fix/process defaults. 608 609 for i in range(0, ndefaults): 610 default = function.defaults[i] 611 if default is not None: 612 params.append((function.argnames[npositional - ndefaults + i], self.dispatch(default))) 613 else: 614 params.append((function.argnames[npositional - ndefaults + i], default)) 615 616 subprogram.params = params 617 subprogram.star = star 618 subprogram.dstar = dstar 619 self.subprograms.append(subprogram) 620 621 def visitFunction(self, function): 622 623 # Make a subprogram for the function and record it outside the main 624 # tree. 625 626 subprogram = Subprogram(name=hex(id(function)), returns_value=1, star=None, dstar=None) 627 self.current_subprograms.append(subprogram) 628 subprogram.code = self.dispatch(function.code) 629 self.current_subprograms.pop() 630 self._visitFunction(function, subprogram) 631 632 # Make a definition of the function associating it with a name. 633 634 result = Assign(function) 635 load = LoadRef(ref=subprogram) 636 store = StoreName(name=function.name) 637 result.code = [load, store] 638 return result 639 640 def visitLambda(self, lambda_): 641 642 # Make a subprogram for the function and record it outside the main 643 # tree. 644 645 subprogram = Subprogram(name=hex(id(lambda_)), returns_value=1, star=None, dstar=None) 646 self.current_subprograms.append(subprogram) 647 subprogram.code = [Return(expr=self.dispatch(lambda_.code))] 648 self.current_subprograms.pop() 649 self._visitFunction(lambda_, subprogram) 650 651 # Get the subprogram reference to the lambda. 652 653 return LoadRef(lambda_, ref=subprogram) 654 655 def visitCallFunc(self, callfunc): 656 result = Invoke(callfunc, same_frame=0, star=None, dstar=None) 657 result.args = self.dispatches(callfunc.args) 658 if callfunc.star_args is not None: 659 result.star = self.dispatch(callfunc.star_args) 660 if callfunc.dstar_args is not None: 661 result.dstar = self.dispatch(callfunc.dstar_args) 662 result.expr = self.dispatch(callfunc.node) 663 return result 664 665 def visitWhile(self, while_): 666 667 # Make a subprogram for the block and record it outside the main tree. 668 669 subprogram = Subprogram(name=hex(id(while_)), acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 670 self.current_subprograms.append(subprogram) 671 672 # Include a conditional statement in the subprogram. 673 674 test = Conditional(else_=[]) 675 test.test = Invoke(expr=LoadAttr(expr=self.dispatch(while_.test), name="__true__"), 676 args=[], star=None, dstar=None) 677 678 # Inside the conditional, add a recursive invocation to the subprogram 679 # if the test condition was satisfied. 680 681 continuation = Invoke(same_frame=1, star=None, dstar=None, args=[]) 682 continuation.expr = LoadRef(ref=subprogram) 683 test.body = self.dispatch(while_.body) + [continuation] 684 if while_.else_ is not None: 685 test.else_ = self.dispatch(while_.else_) 686 subprogram.code = [test] 687 688 self.current_subprograms.pop() 689 self.subprograms.append(subprogram) 690 691 # Make an invocation of the subprogram. 692 693 result = Invoke(while_, same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 694 result.expr = LoadRef(ref=subprogram) 695 return result 696 697 def visitFor(self, for_): 698 699 # Make a subprogram for the block and record it outside the main tree. 700 701 subprogram = Subprogram(name=hex(id(for_)), acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 702 self.current_subprograms.append(subprogram) 703 704 if for_.else_ is not None: 705 else_stmt = self.dispatch(for_.else_) 706 else: 707 else_stmt = [] 708 709 # Wrap the assignment in a try...except statement. 710 711 try_except = Try(body=[], else_=[], finally_=[]) 712 try_except.handler = Conditional(test=Invoke(expr=LoadName(name="isinstance"), 713 args=[LoadExc(), LoadName(name="StopIteration")], star=None, dstar=None), 714 body=else_stmt, else_=[Raise(expr=LoadExc())]) 715 716 assign = Assign() 717 assign.code = [ 718 StoreTemp(expr=Invoke(expr=LoadAttr(expr=LoadTemp(), name="next"))), 719 self.dispatch(for_.assign), 720 ReleaseTemp() 721 ] 722 723 # Inside the conditional, add a recursive invocation to the subprogram 724 # if the test condition was satisfied. 725 726 continuation = Invoke(same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 727 continuation.expr = LoadRef(ref=subprogram) 728 try_except.body = [assign] + self.dispatch(for_.body) + [continuation] 729 subprogram.code = [try_except] 730 731 self.subprograms.append(subprogram) 732 self.current_subprograms.pop() 733 734 # Obtain an iterator for the sequence involved. 735 # Then, make an invocation of the subprogram. 736 737 result = Assign(for_) 738 result.code = [ 739 StoreTemp(expr=Invoke(expr=LoadAttr(name="__iter__", expr=self.dispatch(for_.list)))), 740 Invoke(expr=LoadRef(ref=subprogram), same_frame=1, produces_result=0, star=None, dstar=None, args=[]), 741 ReleaseTemp() 742 ] 743 return result 744 745 # Exception node transformations. 746 747 def visitTryFinally(self, tryfinally): 748 result = Try(tryfinally, body=[], handlers=[], else_=[], finally_=[]) 749 if tryfinally.body is not None: 750 result.body = self.dispatch(tryfinally.body) 751 if tryfinally.final is not None: 752 result.finally_ = self.dispatch(tryfinally.final) 753 return result 754 755 # vim: tabstop=4 expandtab shiftwidth=4