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