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 result = Class(class_, name=class_.name, bases=class_.bases) 92 result.code = self.dispatch(class_.code) 93 return result 94 95 def visitGetattr(self, getattr): 96 result = LoadAttr(getattr, name=getattr.attrname) 97 result.expr = self.dispatch(getattr.expr) 98 return result 99 100 def visitKeyword(self, keyword): 101 result = Keyword(keyword, name=keyword.name) 102 result.expr = self.dispatch(keyword.expr) 103 return result 104 105 def visitGlobal(self, global_): 106 result = Global(global_, names=global_.names) 107 return result 108 109 def visitImport(self, import_): 110 result = Assign(import_) 111 code = [] 112 for path, alias in import_.names: 113 importer = Import(name=path) 114 top = alias or path.split(".")[0] 115 code.append(StoreName(expr=importer, name=top)) 116 result.code = code 117 return result 118 119 def visitFrom(self, from_): 120 result = Assign(from_) 121 code = [] 122 code.append(StoreTemp(expr=Import(name=from_.modname))) 123 for name, alias in from_.names: 124 code.append(StoreName(expr=LoadAttr(expr=LoadTemp(), name=name), name=(alias or name))) 125 result.code = code 126 return result 127 128 def visitName(self, name): 129 result = LoadName(name, name=name.name) 130 return result 131 132 def visitConst(self, const): 133 result = LoadConst(const, value=const.value) 134 return result 135 136 def visitReturn(self, return_): 137 result = Return(return_) 138 result.expr = self.dispatch(return_.value) 139 return result 140 141 def visitBreak(self, break_): 142 result = Return(break_) 143 return result 144 145 def visitContinue(self, continue_): 146 result = Invoke(continue_, same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 147 result.expr = LoadRef(ref=self.current_subprograms[-1]) 148 return result 149 150 def visitRaise(self, raise_): 151 result = Raise(raise_, expr=self.dispatch(raise_.expr1), traceback=None) 152 if raise_.expr2 is not None: 153 result.args = [self.dispatch(raise_.expr2)] 154 if raise_.expr3 is not None: 155 result.traceback = self.dispatch(raise_.expr3) 156 return result 157 158 def visitIf(self, if_): 159 result = If(if_, else_=[]) 160 tests = [] 161 for compare, stmt in if_.tests: 162 # Produce something like... 163 # expr.__true__() ? body 164 test = Conditional(else_=[], test=Invoke( 165 expr=LoadAttr(expr=self.dispatch(compare), name="__true__"), 166 params=[], star=None, dstar=None)) 167 test.body = self.dispatch(stmt) 168 tests.append(test) 169 result.tests = tests 170 if if_.else_ is not None: 171 result.else_ = self.dispatch(if_.else_) 172 return result 173 174 def _visitBuiltin(self, builtin, name): 175 result = Invoke(builtin, expr=LoadName(name=name)) 176 result.args = self.dispatches(builtin.nodes) 177 return result 178 179 def visitTuple(self, tuple): 180 return self._visitBuiltin(tuple, "Tuple") 181 182 def visitList(self, list): 183 return self._visitBuiltin(list, "List") 184 185 def visitDict(self, dict): 186 result = Invoke(dict, expr=LoadName(name="Dict")) 187 args = [] 188 for key, value in dict.items: 189 tuple = Invoke(expr=LoadName(name="Tuple"), star=None, dstar=None) 190 tuple.args = [self.dispatch(key), self.dispatch(value)] 191 args.append(tuple) 192 result.args = args 193 return result 194 195 # Logical and comparison operations. 196 197 comparison_methods = { 198 "==" : "__eq__", "!=" : "__ne__", "<" : "__lt__", "<=" : "__le__", 199 ">=" : "__ge__", ">" : "__gt__", "is" : None, "is not" : None 200 } 201 202 def visitCompare(self, compare): 203 204 # Make a subprogram for the expression and record it outside the main tree. 205 206 subprogram = Subprogram(name=hex(id(compare)), acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 207 self.current_subprograms.append(subprogram) 208 209 # In the subprogram, make instructions which invoke a method on the 210 # first operand of each operand pair and, if appropriate, return with 211 # the value from that method. 212 213 nodes = [] 214 last = compare.ops[-1] 215 previous = self.dispatch(compare.expr) 216 for op in compare.ops: 217 op_name, node = op 218 expr = self.dispatch(node) 219 method_name = self.comparison_methods[op_name] 220 if method_name: 221 invocation = Invoke(expr=LoadAttr(expr=previous, name=method_name), params=[expr], star=None, dstar=None) 222 elif op_name == "is": 223 invocation = Invoke(expr=LoadName(name="__is__"), params=[previous, expr], star=None, dstar=None) 224 elif op_name == "is not": 225 invocation = Not(expr=Invoke(expr=LoadName(name="__is__"), params=[previous, expr], star=None, dstar=None)) 226 else: 227 raise NotImplementedError, op_name 228 nodes.append(StoreTemp(expr=invocation)) 229 if op is not last: 230 nodes.append(Conditional(test=Not(expr=LoadTemp()), body=[Return(expr=LoadTemp())])) 231 nodes.append(ReleaseTemp()) 232 else: 233 nodes.append(Return(expr=LoadTemp())) 234 subprogram.code = nodes 235 236 self.current_subprograms.pop() 237 self.subprograms.append(subprogram) 238 239 # Make an invocation of the subprogram. 240 241 result = Invoke(compare, same_frame=1, star=None, dstar=None, args=[]) 242 result.expr = LoadRef(ref=subprogram) 243 return result 244 245 def visitAnd(self, and_): 246 247 # Make a subprogram for the expression and record it outside the main tree. 248 249 subprogram = Subprogram(name=hex(id(and_)), acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 250 self.current_subprograms.append(subprogram) 251 252 # In the subprogram, make instructions which store each operand, test 253 # for each operand's truth status, and if appropriate return from the 254 # subprogram with the value of the operand. 255 256 nodes = [] 257 last = and_.nodes[-1] 258 for node in and_.nodes: 259 expr = self.dispatch(node) 260 if node is not last: 261 nodes.append(StoreTemp(expr=expr)) 262 invocation = Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), params=[], star=None, dstar=None) 263 nodes.append(Conditional(test=Not(expr=invocation), body=[Return(expr=LoadTemp())])) 264 nodes.append(ReleaseTemp()) 265 else: 266 nodes.append(Return(expr=expr)) 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(and_, same_frame=1, star=None, dstar=None, args=[]) 275 result.expr = LoadRef(ref=subprogram) 276 return result 277 278 def visitOr(self, or_): 279 280 # Make a subprogram for the expression and record it outside the main tree. 281 282 subprogram = Subprogram(name=hex(id(or_)), acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 283 self.current_subprograms.append(subprogram) 284 285 # In the subprogram, make instructions which store each operand, test 286 # for each operand's truth status, and if appropriate return from the 287 # subprogram with the value of the operand. 288 289 nodes = [] 290 last = or_.nodes[-1] 291 for node in or_.nodes: 292 expr = self.dispatch(node) 293 if node is not last: 294 nodes.append(StoreTemp(expr=expr)) 295 invocation = Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), 296 params=[], star=None, dstar=None) 297 nodes.append(Conditional(test=invocation, body=[Return(expr=LoadTemp())])) 298 nodes.append(ReleaseTemp()) 299 else: 300 nodes.append(Return(expr=expr)) 301 subprogram.code = nodes 302 303 self.current_subprograms.pop() 304 self.subprograms.append(subprogram) 305 306 # Make an invocation of the subprogram. 307 308 result = Invoke(or_, same_frame=1, star=None, dstar=None, args=[]) 309 result.expr = LoadRef(ref=subprogram) 310 return result 311 312 def visitNot(self, not_): 313 result = Not(not_, expr=Invoke(expr=LoadAttr(expr=self.dispatch(not_.expr), name="__true__"), 314 params=[], star=None, dstar=None)) 315 return result 316 317 # Operators. 318 319 def visitUnaryAdd(self, unaryadd): 320 return Invoke(unaryadd, expr=LoadAttr(expr=self.dispatch(unaryadd.expr), name="__pos__"), args=[]) 321 322 def visitUnarySub(self, unarysub): 323 return Invoke(unarysub, expr=LoadAttr(expr=self.dispatch(unarysub.expr), name="__neg__"), args=[]) 324 325 def visitInvert(self, invert): 326 return Invoke(invert, expr=LoadAttr(expr=self.dispatch(invert.expr), name="__invert__"), args=[]) 327 328 # Assignments. 329 330 augassign_methods = { 331 "+=" : "__iadd__", "-=" : "__isub__", "*=" : "__imul__", "/=" : "__idiv__", 332 "%=" : "__imod__", "**=" : "__ipow__", "<<=" : "__ilshift__", ">>=" : "__irshift__", 333 "&=" : "__iand__", "^=" : "__ixor__", "|=" : "__ior__" 334 } 335 336 def visitAugAssign(self, augassign): 337 result = Assign(augassign) 338 expr = self.dispatch(augassign.expr) 339 340 # Simple augmented assignment: name += expr 341 342 if isinstance(augassign.node, compiler.ast.Name): 343 name = augassign.node 344 node = self.dispatch(name) 345 get_incremented = StoreTemp( 346 expr=Invoke(expr=LoadAttr(expr=node, name=self.augassign_methods[augassign.op]), args=[expr]) 347 ) 348 store = StoreName(expr=LoadTemp(), name=name.name) 349 result.code = [get_incremented, store, ReleaseTemp()] 350 351 # Complicated augmented assignment: lvalue.attr += expr 352 353 elif isinstance(augassign.node, compiler.ast.Getattr): 354 355 # <lvalue> -> setattr(<lvalue>, getattr(<lvalue>, "attr").__xxx__(expr)) 356 357 getattr = augassign.node 358 store_expr = StoreTemp(index="expr", expr=self.dispatch(getattr.expr)) 359 node_attr = LoadAttr(expr=LoadTemp(index="expr"), name=getattr.attrname) 360 get_incremented = StoreTemp( 361 expr=Invoke(expr=LoadAttr(expr=node_attr, name=self.augassign_methods[augassign.op]), args=[expr]) 362 ) 363 store = StoreAttr(expr=LoadTemp(), lvalue=LoadTemp(index="expr"), name=getattr.attrname) 364 result.code = [store_expr, get_incremented, store, ReleaseTemp(index="expr"), ReleaseTemp()] 365 366 # Complicated augassign using slices: lvalue[lower:upper] += expr 367 368 elif isinstance(augassign.node, compiler.ast.Slice): 369 370 # <lvalue>, <lower>, <upper> -> <lvalue>.__setslice__(<lower>, <upper>, <lvalue>.__getslice__(<lower>, <upper>).__xxx__(expr)) 371 372 slice = augassign.node 373 store_expr = StoreTemp(index="expr", expr=self.dispatch(slice.expr)) 374 store_lower = StoreTemp(index="lower", expr=self.dispatch_or_none(slice.lower)) 375 store_upper = StoreTemp(index="upper", expr=self.dispatch_or_none(slice.upper)) 376 node_slice = self._visitSlice(slice, LoadTemp(index="expr"), LoadTemp(index="lower"), LoadTemp(index="upper"), "OP_APPLY") 377 get_incremented = StoreTemp( 378 expr=Invoke(expr=LoadAttr(expr=node_slice, name=self.augassign_methods[augassign.op]), args=[expr]) 379 ) 380 store = self._visitSlice(slice, LoadTemp(index="expr"), LoadTemp(index="lower"), LoadTemp(index="upper"), "OP_ASSIGN", LoadTemp()) 381 result.code = [store_expr, store_lower, store_upper, get_incremented, store, 382 ReleaseTemp(index="expr"), ReleaseTemp(index="lower"), ReleaseTemp(index="upper"), ReleaseTemp()] 383 384 # Complicated augassign using subscripts: lvalue[subs] += expr 385 386 elif isinstance(augassign.node, compiler.ast.Subscript): 387 388 # <lvalue>, <subs> -> <lvalue>.__setitem__(<subs>, <lvalue>.__getitem__(<subs>).__xxx__(expr)) 389 390 subscript = augassign.node 391 store_expr = StoreTemp(index="expr", expr=self.dispatch(subscript.expr)) 392 subs = self._visitSubscriptSubs(subscript.subs) 393 store_subs = StoreTemp(index="subs", expr=subs) 394 node_subscript = self._visitSubscript(subscript, LoadTemp(index="expr"), LoadTemp(index="subs"), "OP_APPLY") 395 get_incremented = StoreTemp( 396 expr=Invoke(expr=LoadAttr(expr=node_subscript, name=self.augassign_methods[augassign.op]), args=[expr]) 397 ) 398 store = self._visitSubscript(subscript, LoadTemp(index="expr"), LoadTemp(index="subs"), "OP_ASSIGN", LoadTemp()) 399 result.code = [store_expr, store_subs, get_incremented, store, ReleaseTemp(index="expr"), ReleaseTemp(index="subs"), ReleaseTemp()] 400 401 else: 402 raise NotImplementedError, augassign.node.__class__ 403 404 return result 405 406 def visitAssign(self, assign): 407 result = Assign(assign) 408 store = StoreTemp(expr=self.dispatch(assign.expr)) 409 release = ReleaseTemp() 410 result.code = [store] + self.dispatches(assign.nodes, 0) + [release] 411 return result 412 413 def visitAssList(self, asslist, in_sequence=0): 414 if not in_sequence: 415 expr = LoadTemp() 416 else: 417 expr = Invoke(expr=LoadAttr(expr=LoadTemp(), name="next")) 418 result = Assign(asslist) 419 store = StoreTemp(expr=Invoke(expr=LoadAttr(name="__iter__", expr=expr))) 420 release = ReleaseTemp() 421 result.code = [store] + self.dispatches(asslist.nodes, 1) + [release] 422 return result 423 424 visitAssTuple = visitAssList 425 426 def _visitAssNameOrAttr(self, node, in_sequence): 427 if not in_sequence: 428 return LoadTemp() 429 else: 430 return Invoke(expr=LoadAttr(expr=LoadTemp(), name="next")) 431 432 def visitAssName(self, assname, in_sequence=0): 433 expr = self._visitAssNameOrAttr(assname, in_sequence) 434 result = StoreName(assname, name=assname.name, expr=expr) 435 return result 436 437 def visitAssAttr(self, assattr, in_sequence=0): 438 expr = self._visitAssNameOrAttr(assattr, in_sequence) 439 lvalue = self.dispatch(assattr.expr) 440 result = StoreAttr(assattr, name=assattr.attrname, lvalue=lvalue, expr=expr) 441 return result 442 443 def _visitSlice(self, slice, expr, lower, upper, flags, value=None): 444 if flags == "OP_ASSIGN": 445 args = [value] 446 result = Invoke(expr=LoadAttr(expr=expr, name="__setslice__")) 447 elif flags == "OP_APPLY": 448 args = [] 449 result = Invoke(expr=LoadAttr(expr=expr, name="__getslice__")) 450 elif flags == "OP_DELETE": 451 args = [] 452 result = Invoke(expr=LoadAttr(expr=expr, name="__delslice__")) 453 else: 454 raise NotImplementedError, flags 455 456 # Add the dimensions. 457 458 args.insert(0, lower) 459 args.insert(1, upper) 460 461 result.original = slice 462 result.args = args 463 return result 464 465 def visitSlice(self, slice, in_sequence=0): 466 value = self._visitAssNameOrAttr(slice, in_sequence) 467 return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower), 468 self.dispatch_or_none(slice.upper), slice.flags, value) 469 470 def _visitSubscript(self, subscript, expr, subs, flags, value=None): 471 if flags == "OP_ASSIGN": 472 args = [value] 473 result = Invoke(expr=LoadAttr(expr=expr, name="__setitem__")) 474 elif flags == "OP_APPLY": 475 args = [] 476 result = Invoke(expr=LoadAttr(expr=expr, name="__getitem__")) 477 elif flags == "OP_DELETE": 478 args = [] 479 result = Invoke(expr=LoadAttr(expr=expr, name="__delitem__")) 480 else: 481 raise NotImplementedError, flags 482 483 # Add the dimensions. 484 485 args.insert(0, subs) 486 487 result.original = subscript 488 result.args = args 489 return result 490 491 def _visitSubscriptSubs(self, subs): 492 if len(subs) == 1: 493 return self.dispatch(subs[0]) 494 else: 495 return Invoke(expr=LoadName(name="Tuple"), args=self.dispatches(subs)) 496 497 def visitSubscript(self, subscript, in_sequence=0): 498 value = self._visitAssNameOrAttr(subscript, in_sequence) 499 subs = self._visitSubscriptSubs(subscript.subs) 500 return self._visitSubscript(subscript, self.dispatch(subscript.expr), subs, subscript.flags, value) 501 502 # Invocation and subprogram transformations. 503 504 def _visitFunction(self, function, subprogram): 505 if function.flags & 4 != 0: has_star = 1 506 else: has_star = 0 507 if function.flags & 8 != 0: has_dstar = 1 508 else: has_dstar = 0 509 ndefaults = len(function.defaults) 510 npositional = len(function.argnames) - has_star - has_dstar 511 if has_star: star = function.argnames[npositional] 512 else: star = None 513 if has_dstar: dstar = function.argnames[npositional + has_star] 514 else: dstar = None 515 516 params = [] 517 for i in range(0, npositional - ndefaults): 518 params.append((function.argnames[i], None)) 519 520 # NOTE: Fix/process defaults. 521 522 for i in range(0, ndefaults): 523 default = function.defaults[i] 524 if default is not None: 525 params.append((function.argnames[npositional - ndefaults + i], self.dispatch(default))) 526 else: 527 params.append((function.argnames[npositional - ndefaults + i], default)) 528 529 subprogram.params = params 530 subprogram.star = star 531 subprogram.dstar = dstar 532 self.subprograms.append(subprogram) 533 534 def visitFunction(self, function): 535 536 # Make a subprogram for the function and record it outside the main 537 # tree. 538 539 subprogram = Subprogram(name=function.name, returns_value=1, star=None, dstar=None) 540 self.current_subprograms.append(subprogram) 541 subprogram.code = self.dispatch(function.code) 542 self.current_subprograms.pop() 543 self._visitFunction(function, subprogram) 544 545 # Make a definition of the function associating it with a name. 546 547 result = Assign(function) 548 load = LoadRef(ref=subprogram) 549 store = StoreName(name=function.name) 550 result.code = [load, store] 551 return result 552 553 def visitLambda(self, lambda_): 554 555 # Make a subprogram for the function and record it outside the main 556 # tree. 557 558 subprogram = Subprogram(name=hex(id(lambda_)), returns_value=1, star=None, dstar=None) 559 self.current_subprograms.append(subprogram) 560 subprogram.code = [Return(expr=self.dispatch(lambda_.code))] 561 self.current_subprograms.pop() 562 self._visitFunction(lambda_, subprogram) 563 564 # Get the subprogram reference to the lambda. 565 566 return LoadRef(lambda_, ref=subprogram) 567 568 def visitCallFunc(self, callfunc): 569 result = Invoke(callfunc, same_frame=0, star=None, dstar=None) 570 result.args = self.dispatches(callfunc.args) 571 if callfunc.star_args is not None: 572 result.star = self.dispatch(callfunc.star_args) 573 if callfunc.dstar_args is not None: 574 result.dstar = self.dispatch(callfunc.dstar_args) 575 result.expr = self.dispatch(callfunc.node) 576 return result 577 578 def visitWhile(self, while_): 579 580 # Make a subprogram for the block and record it outside the main tree. 581 582 subprogram = Subprogram(name=hex(id(while_)), acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 583 self.current_subprograms.append(subprogram) 584 585 # Include a conditional statement in the subprogram. 586 587 test = Conditional(else_=[]) 588 test.test = Invoke(expr=LoadAttr(expr=self.dispatch(while_.test), name="__true__"), 589 params=[], star=None, dstar=None) 590 591 # Inside the conditional, add a recursive invocation to the subprogram 592 # if the test condition was satisfied. 593 594 continuation = Invoke(same_frame=1, star=None, dstar=None, args=[]) 595 continuation.expr = LoadRef(ref=subprogram) 596 test.body = self.dispatch(while_.body) + [continuation] 597 if while_.else_ is not None: 598 test.else_ = self.dispatch(while_.else_) 599 subprogram.code = [test] 600 601 self.current_subprograms.pop() 602 self.subprograms.append(subprogram) 603 604 # Make an invocation of the subprogram. 605 606 result = Invoke(while_, same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 607 result.expr = LoadRef(ref=subprogram) 608 return result 609 610 def visitFor(self, for_): 611 612 # Make a subprogram for the block and record it outside the main tree. 613 614 subprogram = Subprogram(name=hex(id(for_)), acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 615 self.current_subprograms.append(subprogram) 616 617 # Wrap the assignment in a try...except statement. 618 619 try_except = Try(body=[], handlers=[], else_=[], finally_=[]) 620 except_spec = Invoke(expr=LoadName(name="Tuple"), params=[LoadName(name="StopIteration")]) 621 stopiteration = Except(spec=except_spec) 622 stopiteration.code = self.dispatch(for_.else_) 623 try_except.handlers = [stopiteration] 624 625 assign = Assign() 626 assign.code = [ 627 StoreTemp(expr=Invoke(expr=LoadAttr(expr=LoadTemp(), name="next"))), 628 self.dispatch(for_.assign), 629 ReleaseTemp() 630 ] 631 632 # Inside the conditional, add a recursive invocation to the subprogram 633 # if the test condition was satisfied. 634 635 continuation = Invoke(same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 636 continuation.expr = LoadRef(ref=subprogram) 637 try_except.body = [assign] + self.dispatch(for_.body) + [continuation] 638 subprogram.code = [try_except] 639 640 self.subprograms.append(subprogram) 641 self.current_subprograms.pop() 642 643 # Obtain an iterator for the sequence involved. 644 # Then, make an invocation of the subprogram. 645 646 result = Assign(for_) 647 result.code = [ 648 StoreTemp(expr=Invoke(expr=LoadAttr(name="__iter__", expr=self.dispatch(for_.list)))), 649 Invoke(expr=LoadRef(ref=subprogram), same_frame=1, produces_result=0, star=None, dstar=None, args=[]), 650 ReleaseTemp() 651 ] 652 return result 653 654 # Exception node transformations. 655 656 def visitTryExcept(self, tryexcept): 657 result = Try(tryexcept, body=[], handlers=[], else_=[], finally_=[]) 658 if tryexcept.body is not None: 659 result.body = self.dispatch(tryexcept.body) 660 if tryexcept.else_ is not None: 661 result.else_ = self.dispatch(tryexcept.else_) 662 handlers = [] 663 for spec, assign, stmt in tryexcept.handlers: 664 get_exc = Assign() 665 get_exc.code = [StoreTemp(expr=LoadExc())] 666 if assign is not None: 667 get_exc.code.append(self.dispatch(assign)) 668 get_exc.code.append(ReleaseTemp()) 669 handler = Except() 670 if spec is not None: 671 handler.spec = self.dispatch(spec) 672 handler.code = [get_exc] + self.dispatch(stmt) 673 handlers.append(handler) 674 result.handlers = handlers 675 return result 676 677 def visitTryFinally(self, tryfinally): 678 result = Try(tryfinally, body=[], handlers=[], else_=[], finally_=[]) 679 if tryfinally.body is not None: 680 result.body = self.dispatch(tryfinally.body) 681 if tryfinally.final is not None: 682 result.finally_ = self.dispatch(tryfinally.final) 683 return result 684 685 # vim: tabstop=4 expandtab shiftwidth=4