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