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