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, Const, Continue, Dict, Discard, For, From, 35 Function, Getattr, Global, If, Import, Invert, Keyword, Lambda, 36 List, Module, Name, Not, Or, Pass, Raise, Return, Stmt, TryExcept, 37 TryFinally, Tuple, While, UnaryAdd, UnarySub. 38 39 Missing: Add, Assert, Backquote, Bitand, Bitor, Bitxor, Compare, Decorators, 40 Div, Ellipsis, Exec, FloorDiv, LeftShift, ListComp, ListCompFor, 41 ListCompIf, Mod, Mul, Power, Print, Printnl, RightShift, 42 Slice, Sliceobj, Sub, Subscript, Yield. 43 """ 44 45 def __init__(self): 46 ASTVisitor.__init__(self) 47 self.result = None # The resulting tree. 48 self.subprograms = [] # Subprograms outside the tree. 49 self.current_subprograms = [] # Current subprograms being processed. 50 51 # Generic visitor methods. 52 53 def default(self, node, *args): 54 raise ValueError, node.__class__ 55 56 def dispatch(self, node, *args): 57 return ASTVisitor.dispatch(self, node, *args) 58 59 def dispatches(self, nodes, *args): 60 results = [] 61 for node in nodes: 62 results.append(self.dispatch(node, *args)) 63 return results 64 65 def dispatch_or_none(self, node, *args): 66 if node is not None: 67 return self.dispatch(node, *args) 68 else: 69 return LoadName(name="None") 70 71 # Placeholder or deletion transformations. 72 73 def visitStmt(self, stmt): 74 return self.dispatches(stmt.nodes) 75 76 def visitPass(self, pass_): 77 return Pass(pass_) 78 79 def visitDiscard(self, discard): 80 return self.dispatch(discard.expr) 81 82 # Relatively trivial transformations. 83 84 def visitModule(self, module): 85 self.result = Module(module) 86 self.result.code = self.dispatch(module.node) 87 return self.result 88 89 def visitClass(self, class_): 90 result = Class(class_, name=class_.name, bases=class_.bases) 91 result.code = self.dispatch(class_.code) 92 return result 93 94 def visitGetattr(self, getattr): 95 result = LoadAttr(getattr, name=getattr.attrname) 96 result.expr = self.dispatch(getattr.expr) 97 return result 98 99 def visitKeyword(self, keyword): 100 result = Keyword(keyword, name=keyword.name) 101 result.expr = self.dispatch(keyword.expr) 102 return result 103 104 def visitGlobal(self, global_): 105 result = Global(global_, names=global_.names) 106 return result 107 108 def visitImport(self, import_): 109 result = Assign(import_) 110 code = [] 111 for path, alias in import_.names: 112 importer = Import(name=path) 113 top = alias or path.split(".")[0] 114 code.append(StoreName(expr=importer, name=top)) 115 result.code = code 116 return result 117 118 def visitFrom(self, from_): 119 result = Assign(from_) 120 code = [] 121 code.append(StoreTemp(expr=Import(name=from_.modname))) 122 for name, alias in from_.names: 123 code.append(StoreName(expr=LoadAttr(expr=LoadTemp(), name=name), name=(alias or name))) 124 result.code = code 125 return result 126 127 def visitName(self, name): 128 result = LoadName(name, name=name.name) 129 return result 130 131 def visitConst(self, const): 132 result = LoadConst(const, value=const.value) 133 return result 134 135 def visitReturn(self, return_): 136 result = Return(return_) 137 result.expr = self.dispatch(return_.value) 138 return result 139 140 def visitBreak(self, break_): 141 result = Return(break_) 142 return result 143 144 def visitContinue(self, continue_): 145 result = Invoke(continue_, same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 146 result.expr = LoadRef(ref=self.current_subprograms[-1]) 147 return result 148 149 def visitRaise(self, raise_): 150 result = Raise(raise_, expr=self.dispatch(raise_.expr1), traceback=None) 151 if raise_.expr2 is not None: 152 result.args = [self.dispatch(raise_.expr2)] 153 if raise_.expr3 is not None: 154 result.traceback = self.dispatch(raise_.expr3) 155 return result 156 157 def visitIf(self, if_): 158 result = If(if_, else_=[]) 159 tests = [] 160 for compare, stmt in if_.tests: 161 # Produce something like... 162 # expr.__true__() ? body 163 test = Conditional(else_=[], test=Invoke( 164 expr=LoadAttr(expr=self.dispatch(compare), name="__true__"), 165 params=[], star=None, dstar=None)) 166 test.body = self.dispatch(stmt) 167 tests.append(test) 168 result.tests = tests 169 if if_.else_ is not None: 170 result.else_ = self.dispatch(if_.else_) 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 operators. 195 196 def visitAnd(self, and_): 197 198 # Make a subprogram for the expression and record it outside the main tree. 199 200 subprogram = Subprogram(name=hex(id(and_)), acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 201 self.current_subprograms.append(subprogram) 202 203 # In the subprogram, make instructions which store each operand, test 204 # for each operand's truth status, and if appropriate return from the 205 # subprogram with the value of the operand. 206 207 nodes = [] 208 last = and_.nodes[-1] 209 for node in and_.nodes: 210 expr = self.dispatch(node) 211 if node is not last: 212 nodes.append(StoreTemp(expr=expr)) 213 invocation = Not(expr=Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), 214 params=[], star=None, dstar=None)) 215 nodes.append(Conditional(test=invocation, body=[Return(expr=LoadTemp())])) 216 nodes.append(ReleaseTemp()) 217 else: 218 nodes.append(Return(expr=expr)) 219 subprogram.code = nodes 220 221 self.current_subprograms.pop() 222 self.subprograms.append(subprogram) 223 224 # Make an invocation of the subprogram. 225 226 result = Invoke(and_, same_frame=1, star=None, dstar=None, args=[]) 227 result.expr = LoadRef(ref=subprogram) 228 return result 229 230 def visitOr(self, or_): 231 232 # Make a subprogram for the expression and record it outside the main tree. 233 234 subprogram = Subprogram(name=hex(id(or_)), acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) 235 self.current_subprograms.append(subprogram) 236 237 # In the subprogram, make instructions which store each operand, test 238 # for each operand's truth status, and if appropriate return from the 239 # subprogram with the value of the operand. 240 241 nodes = [] 242 last = or_.nodes[-1] 243 for node in or_.nodes: 244 expr = self.dispatch(node) 245 if node is not last: 246 nodes.append(StoreTemp(expr=expr)) 247 invocation = Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), 248 params=[], star=None, dstar=None) 249 nodes.append(Conditional(test=invocation, body=[Return(expr=LoadTemp())])) 250 nodes.append(ReleaseTemp()) 251 else: 252 nodes.append(Return(expr=expr)) 253 subprogram.code = nodes 254 255 self.current_subprograms.pop() 256 self.subprograms.append(subprogram) 257 258 # Make an invocation of the subprogram. 259 260 result = Invoke(or_, same_frame=1, star=None, dstar=None, args=[]) 261 result.expr = LoadRef(ref=subprogram) 262 return result 263 264 def visitNot(self, not_): 265 result = Not(not_, expr=Invoke(expr=LoadAttr(expr=self.dispatch(not_.expr), name="__true__"), 266 params=[], star=None, dstar=None)) 267 return result 268 269 # Operators. 270 271 def visitUnaryAdd(self, unaryadd): 272 return Invoke(unaryadd, expr=LoadAttr(expr=self.dispatch(unaryadd.expr), name="__pos__"), args=[]) 273 274 def visitUnarySub(self, unarysub): 275 return Invoke(unarysub, expr=LoadAttr(expr=self.dispatch(unarysub.expr), name="__neg__"), args=[]) 276 277 def visitInvert(self, invert): 278 return Invoke(invert, expr=LoadAttr(expr=self.dispatch(invert.expr), name="__invert__"), args=[]) 279 280 # Assignments. 281 282 augassign_methods = { 283 "+=" : "__iadd__", "-=" : "__isub__", "*=" : "__imul__", "/=" : "__idiv__", 284 "%=" : "__imod__", "**=" : "__ipow__", "<<=" : "__ilshift__", ">>=" : "__irshift__", 285 "&=" : "__iand__", "^=" : "__ixor__", "|=" : "__ior__" 286 } 287 288 def visitAugAssign(self, augassign): 289 result = Assign(augassign) 290 expr = self.dispatch(augassign.expr) 291 292 # Simple augmented assignment: name += expr 293 294 if isinstance(augassign.node, compiler.ast.Name): 295 name = augassign.node 296 node = self.dispatch(name) 297 get_incremented = StoreTemp( 298 expr=Invoke(expr=LoadAttr(expr=node, name=self.augassign_methods[augassign.op]), args=[expr]) 299 ) 300 store = StoreName(expr=LoadTemp(), name=name.name) 301 result.code = [get_incremented, store, ReleaseTemp()] 302 303 # Complicated augmented assignment: lvalue.attr += expr 304 305 elif isinstance(augassign.node, compiler.ast.Getattr): 306 307 # <lvalue> -> setattr(<lvalue>, getattr(<lvalue>, "attr").__xxx__(expr)) 308 309 getattr = augassign.node 310 store_expr = StoreTemp(index="expr", expr=self.dispatch(getattr.expr)) 311 node_attr = LoadAttr(expr=LoadTemp(index="expr"), name=getattr.attrname) 312 get_incremented = StoreTemp( 313 expr=Invoke(expr=LoadAttr(expr=node_attr, name=self.augassign_methods[augassign.op]), args=[expr]) 314 ) 315 store = StoreAttr(expr=LoadTemp(), lvalue=LoadTemp(index="expr"), name=getattr.attrname) 316 result.code = [store_expr, get_incremented, store, ReleaseTemp(index="expr"), ReleaseTemp()] 317 318 # Complicated augassign using slices: lvalue[lower:upper] += expr 319 320 elif isinstance(augassign.node, compiler.ast.Slice): 321 322 # <lvalue>, <lower>, <upper> -> <lvalue>.__setslice__(<lower>, <upper>, <lvalue>.__getslice__(<lower>, <upper>).__xxx__(expr)) 323 324 slice = augassign.node 325 store_expr = StoreTemp(index="expr", expr=self.dispatch(slice.expr)) 326 store_lower = StoreTemp(index="lower", expr=self.dispatch_or_none(slice.lower)) 327 store_upper = StoreTemp(index="upper", expr=self.dispatch_or_none(slice.upper)) 328 node_slice = self._visitSlice(slice, LoadTemp(index="expr"), LoadTemp(index="lower"), LoadTemp(index="upper"), "OP_APPLY") 329 get_incremented = StoreTemp( 330 expr=Invoke(expr=LoadAttr(expr=node_slice, name=self.augassign_methods[augassign.op]), args=[expr]) 331 ) 332 store = self._visitSlice(slice, LoadTemp(index="expr"), LoadTemp(index="lower"), LoadTemp(index="upper"), "OP_ASSIGN", LoadTemp()) 333 result.code = [store_expr, store_lower, store_upper, get_incremented, store, 334 ReleaseTemp(index="expr"), ReleaseTemp(index="lower"), ReleaseTemp(index="upper"), ReleaseTemp()] 335 336 # Complicated augassign using subscripts: lvalue[subs] += expr 337 338 elif isinstance(augassign.node, compiler.ast.Subscript): 339 340 # <lvalue>, <subs> -> <lvalue>.__setitem__(<subs>, <lvalue>.__getitem__(<subs>).__xxx__(expr)) 341 342 subscript = augassign.node 343 store_expr = StoreTemp(index="expr", expr=self.dispatch(subscript.expr)) 344 subs = self._visitSubscriptSubs(subscript.subs) 345 store_subs = StoreTemp(index="subs", expr=subs) 346 node_subscript = self._visitSubscript(subscript, LoadTemp(index="expr"), LoadTemp(index="subs"), "OP_APPLY") 347 get_incremented = StoreTemp( 348 expr=Invoke(expr=LoadAttr(expr=node_subscript, name=self.augassign_methods[augassign.op]), args=[expr]) 349 ) 350 store = self._visitSubscript(subscript, LoadTemp(index="expr"), LoadTemp(index="subs"), "OP_ASSIGN", LoadTemp()) 351 result.code = [store_expr, store_subs, get_incremented, store, ReleaseTemp(index="expr"), ReleaseTemp(index="subs"), ReleaseTemp()] 352 353 else: 354 raise NotImplementedError, augassign.node.__class__ 355 356 return result 357 358 def visitAssign(self, assign): 359 result = Assign(assign) 360 store = StoreTemp(expr=self.dispatch(assign.expr)) 361 release = ReleaseTemp() 362 result.code = [store] + self.dispatches(assign.nodes, 0) + [release] 363 return result 364 365 def visitAssList(self, asslist, in_sequence=0): 366 if not in_sequence: 367 expr = LoadTemp() 368 else: 369 expr = Invoke(expr=LoadAttr(expr=LoadTemp(), name="next")) 370 result = Assign(asslist) 371 store = StoreTemp(expr=Invoke(expr=LoadAttr(name="__iter__", expr=expr))) 372 release = ReleaseTemp() 373 result.code = [store] + self.dispatches(asslist.nodes, 1) + [release] 374 return result 375 376 visitAssTuple = visitAssList 377 378 def _visitAssNameOrAttr(self, node, in_sequence): 379 if not in_sequence: 380 return LoadTemp() 381 else: 382 return Invoke(expr=LoadAttr(expr=LoadTemp(), name="next")) 383 384 def visitAssName(self, assname, in_sequence=0): 385 expr = self._visitAssNameOrAttr(assname, in_sequence) 386 result = StoreName(assname, name=assname.name, expr=expr) 387 return result 388 389 def visitAssAttr(self, assattr, in_sequence=0): 390 expr = self._visitAssNameOrAttr(assattr, in_sequence) 391 lvalue = self.dispatch(assattr.expr) 392 result = StoreAttr(assattr, name=assattr.attrname, lvalue=lvalue, expr=expr) 393 return result 394 395 def _visitSlice(self, slice, expr, lower, upper, flags, value=None): 396 if flags == "OP_ASSIGN": 397 args = [value] 398 result = Invoke(expr=LoadAttr(expr=expr, name="__setslice__")) 399 elif flags == "OP_APPLY": 400 args = [] 401 result = Invoke(expr=LoadAttr(expr=expr, name="__getslice__")) 402 elif flags == "OP_DELETE": 403 args = [] 404 result = Invoke(expr=LoadAttr(expr=expr, name="__delslice__")) 405 else: 406 raise NotImplementedError, flags 407 408 # Add the dimensions. 409 410 args.insert(0, lower) 411 args.insert(1, upper) 412 413 result.original = slice 414 result.args = args 415 return result 416 417 def visitSlice(self, slice, in_sequence=0): 418 value = self._visitAssNameOrAttr(slice, in_sequence) 419 return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower), 420 self.dispatch_or_none(slice.upper), slice.flags, value) 421 422 def _visitSubscript(self, subscript, expr, subs, flags, value=None): 423 if flags == "OP_ASSIGN": 424 args = [value] 425 result = Invoke(expr=LoadAttr(expr=expr, name="__setitem__")) 426 elif flags == "OP_APPLY": 427 args = [] 428 result = Invoke(expr=LoadAttr(expr=expr, name="__getitem__")) 429 elif flags == "OP_DELETE": 430 args = [] 431 result = Invoke(expr=LoadAttr(expr=expr, name="__delitem__")) 432 else: 433 raise NotImplementedError, flags 434 435 # Add the dimensions. 436 437 args.insert(0, subs) 438 439 result.original = subscript 440 result.args = args 441 return result 442 443 def _visitSubscriptSubs(self, subs): 444 if len(subs) == 1: 445 return self.dispatch(subs[0]) 446 else: 447 return Invoke(expr=LoadName(name="Tuple"), args=self.dispatches(subs)) 448 449 def visitSubscript(self, subscript, in_sequence=0): 450 value = self._visitAssNameOrAttr(subscript, in_sequence) 451 subs = self._visitSubscriptSubs(subscript.subs) 452 return self._visitSubscript(subscript, self.dispatch(subscript.expr), subs, subscript.flags, value) 453 454 # Invocation and subprogram transformations. 455 456 def _visitFunction(self, function, subprogram): 457 if function.flags & 4 != 0: has_star = 1 458 else: has_star = 0 459 if function.flags & 8 != 0: has_dstar = 1 460 else: has_dstar = 0 461 ndefaults = len(function.defaults) 462 npositional = len(function.argnames) - has_star - has_dstar 463 if has_star: star = function.argnames[npositional] 464 else: star = None 465 if has_dstar: dstar = function.argnames[npositional + has_star] 466 else: dstar = None 467 468 params = [] 469 for i in range(0, npositional - ndefaults): 470 params.append((function.argnames[i], None)) 471 472 # NOTE: Fix/process defaults. 473 474 for i in range(0, ndefaults): 475 default = function.defaults[i] 476 if default is not None: 477 params.append((function.argnames[npositional - ndefaults + i], self.dispatch(default))) 478 else: 479 params.append((function.argnames[npositional - ndefaults + i], default)) 480 481 subprogram.params = params 482 subprogram.star = star 483 subprogram.dstar = dstar 484 self.subprograms.append(subprogram) 485 486 def visitFunction(self, function): 487 488 # Make a subprogram for the function and record it outside the main 489 # tree. 490 491 subprogram = Subprogram(name=function.name, returns_value=1, star=None, dstar=None) 492 self.current_subprograms.append(subprogram) 493 subprogram.code = self.dispatch(function.code) 494 self.current_subprograms.pop() 495 self._visitFunction(function, subprogram) 496 497 # Make a definition of the function associating it with a name. 498 499 result = Assign(function) 500 load = LoadRef(ref=subprogram) 501 store = StoreName(name=function.name) 502 result.code = [load, store] 503 return result 504 505 def visitLambda(self, lambda_): 506 507 # Make a subprogram for the function and record it outside the main 508 # tree. 509 510 subprogram = Subprogram(name=hex(id(lambda_)), returns_value=1, star=None, dstar=None) 511 self.current_subprograms.append(subprogram) 512 subprogram.code = [Return(expr=self.dispatch(lambda_.code))] 513 self.current_subprograms.pop() 514 self._visitFunction(lambda_, subprogram) 515 516 # Get the subprogram reference to the lambda. 517 518 return LoadRef(lambda_, ref=subprogram) 519 520 def visitCallFunc(self, callfunc): 521 result = Invoke(callfunc, same_frame=0, star=None, dstar=None) 522 result.args = self.dispatches(callfunc.args) 523 if callfunc.star_args is not None: 524 result.star = self.dispatch(callfunc.star_args) 525 if callfunc.dstar_args is not None: 526 result.dstar = self.dispatch(callfunc.dstar_args) 527 result.expr = self.dispatch(callfunc.node) 528 return result 529 530 def visitWhile(self, while_): 531 532 # Make a subprogram for the block and record it outside the main tree. 533 534 subprogram = Subprogram(name=hex(id(while_)), acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 535 self.current_subprograms.append(subprogram) 536 537 # Include a conditional statement in the subprogram. 538 539 test = Conditional(else_=[]) 540 test.test = Invoke(expr=LoadAttr(expr=self.dispatch(while_.test), name="__true__"), 541 params=[], star=None, dstar=None) 542 543 # Inside the conditional, add a recursive invocation to the subprogram 544 # if the test condition was satisfied. 545 546 continuation = Invoke(same_frame=1, star=None, dstar=None, args=[]) 547 continuation.expr = LoadRef(ref=subprogram) 548 test.body = self.dispatch(while_.body) + [continuation] 549 if while_.else_ is not None: 550 test.else_ = self.dispatch(while_.else_) 551 subprogram.code = [test] 552 553 self.current_subprograms.pop() 554 self.subprograms.append(subprogram) 555 556 # Make an invocation of the subprogram. 557 558 result = Invoke(while_, same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 559 result.expr = LoadRef(ref=subprogram) 560 return result 561 562 def visitFor(self, for_): 563 564 # Make a subprogram for the block and record it outside the main tree. 565 566 subprogram = Subprogram(name=hex(id(for_)), acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) 567 self.current_subprograms.append(subprogram) 568 569 # Wrap the assignment in a try...except statement. 570 571 try_except = Try(body=[], handlers=[], else_=[], finally_=[]) 572 except_spec = Invoke(expr=LoadName(name="Tuple"), params=[LoadName(name="StopIteration")]) 573 stopiteration = Except(spec=except_spec) 574 stopiteration.code = self.dispatch(for_.else_) 575 try_except.handlers = [stopiteration] 576 577 assign = Assign() 578 assign.code = [ 579 StoreTemp(expr=Invoke(expr=LoadAttr(expr=LoadTemp(), name="next"))), 580 self.dispatch(for_.assign), 581 ReleaseTemp() 582 ] 583 584 # Inside the conditional, add a recursive invocation to the subprogram 585 # if the test condition was satisfied. 586 587 continuation = Invoke(same_frame=1, produces_result=0, star=None, dstar=None, args=[]) 588 continuation.expr = LoadRef(ref=subprogram) 589 try_except.body = [assign] + self.dispatch(for_.body) + [continuation] 590 subprogram.code = [try_except] 591 592 self.subprograms.append(subprogram) 593 self.current_subprograms.pop() 594 595 # Obtain an iterator for the sequence involved. 596 # Then, make an invocation of the subprogram. 597 598 result = Assign(for_) 599 result.code = [ 600 StoreTemp(expr=Invoke(expr=LoadAttr(name="__iter__", expr=self.dispatch(for_.list)))), 601 Invoke(expr=LoadRef(ref=subprogram), same_frame=1, produces_result=0, star=None, dstar=None, args=[]), 602 ReleaseTemp() 603 ] 604 return result 605 606 # Exception node transformations. 607 608 def visitTryExcept(self, tryexcept): 609 result = Try(tryexcept, body=[], handlers=[], else_=[], finally_=[]) 610 if tryexcept.body is not None: 611 result.body = self.dispatch(tryexcept.body) 612 if tryexcept.else_ is not None: 613 result.else_ = self.dispatch(tryexcept.else_) 614 handlers = [] 615 for spec, assign, stmt in tryexcept.handlers: 616 get_exc = Assign() 617 get_exc.code = [StoreTemp(expr=LoadExc())] 618 if assign is not None: 619 get_exc.code.append(self.dispatch(assign)) 620 get_exc.code.append(ReleaseTemp()) 621 handler = Except() 622 if spec is not None: 623 handler.spec = self.dispatch(spec) 624 handler.code = [get_exc] + self.dispatch(stmt) 625 handlers.append(handler) 626 result.handlers = handlers 627 return result 628 629 def visitTryFinally(self, tryfinally): 630 result = Try(tryfinally, body=[], handlers=[], else_=[], finally_=[]) 631 if tryfinally.body is not None: 632 result.body = self.dispatch(tryfinally.body) 633 if tryfinally.final is not None: 634 result.finally_ = self.dispatch(tryfinally.final) 635 return result 636 637 # vim: tabstop=4 expandtab shiftwidth=4