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