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