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, 2007 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 27 To use this module, the easiest approach is to use the simplify function: 28 29 simplify(filename) 30 31 The more complicated approach involves first instantiating a Simplifier object: 32 33 simplifier = Simplifier() 34 35 Then, applying the simplifier to an AST tree: 36 37 module = compiler.parseFile(filename) 38 simplifier.process(module) 39 """ 40 41 from simplified import * 42 import compiler.ast 43 import os 44 45 class Simplifier(Visitor): 46 47 """ 48 A simplifying visitor for AST nodes. 49 50 Covered: Add, And, AssAttr, AssList, AssName, AssTuple, Assign, AugAssign, 51 Break, CallFunc, Class, Compare, Const, Continue, Dict, Discard, 52 Div, FloorDiv, For, From, Function, Getattr, Global, If, Import, 53 Invert, Keyword, Lambda, List, Mod, Module, Mul, Name, Not, Or, 54 Pass, Power, Print, Printnl, Raise, Return, Slice, Stmt, Sub, 55 Subscript, TryExcept, TryFinally, Tuple, While, UnaryAdd, UnarySub. 56 57 Missing: Assert, Backquote, Bitand, Bitor, Bitxor, Decorators, Ellipsis, 58 Exec, LeftShift, ListComp, ListCompFor, ListCompIf, RightShift, 59 Sliceobj, Yield. 60 """ 61 62 def __init__(self, builtins=0): 63 64 """ 65 Initialise the simplifier with the optional 'builtins' parameter 66 indicating whether the module contains the built-in classes and 67 functions. 68 """ 69 70 Visitor.__init__(self) 71 self.subprograms = [] # Subprograms outside the tree. 72 self.structures = [] # Structures/classes. 73 self.constants = {} # Constants. 74 self.current_subprograms = [] # Current subprograms being processed. 75 self.current_structures = [] # Current structures being processed. 76 self.within_class = 0 # Whether a class is being defined. 77 self.builtins = builtins # Whether the builtins are being processed. 78 79 # Convenience attributes. 80 81 self.subnames = {} 82 83 # For compiler package mechanisms. 84 85 self.visitor = self 86 87 def process(self, node, name): 88 result = self.dispatch(node, name) 89 result.simplifier = self 90 return result 91 92 def dispatch_or_none(self, node, *args): 93 if node is not None: 94 return self.dispatch(node, *args) 95 else: 96 return LoadName(node, name="None") 97 98 # Top-level transformation. 99 100 def visitModule(self, module, name=None): 101 102 """ 103 Process the given 'module', producing a Module object which contains the 104 resulting program nodes. If the optional 'name' is provided, the 'name' 105 attribute is set on the Module object using a value other than None. 106 """ 107 108 result = self.module = Module(module, 1, name=name) 109 module_code = self.dispatch(module.node) 110 111 # NOTE: Constant initialisation necessary for annotation but perhaps 112 # NOTE: redundant in the program. 113 114 init_code = [] 115 for value, constant in self.constants.items(): 116 init_code.append( 117 StoreAttr( 118 lvalue=LoadRef(ref=constant), 119 name="__class__", 120 expr=LoadName(name=constant.typename) 121 ) 122 ) 123 124 # NOTE: Hack to ensure correct initialisation of constants. 125 126 if self.builtins: 127 result.code = module_code + init_code 128 else: 129 result.code = init_code + module_code 130 return result 131 132 # Node transformations. 133 134 def visitAdd(self, add): 135 return self._visitBinary(add, "__add__", "__radd__") 136 137 def visitAnd(self, and_): 138 139 """ 140 Make a subprogram for the 'and_' node and record its contents inside the 141 subprogram. Convert... 142 143 And (test) 144 (test) 145 ... 146 147 ...to: 148 149 Subprogram -> Conditional (test) -> ReturnFromBlock ... 150 (else) -> Conditional (test) -> ReturnFromBlock ... 151 (else) -> ... 152 """ 153 154 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) 155 self.current_subprograms.append(subprogram) 156 157 # In the subprogram, make instructions which store each operand, test 158 # for each operand's truth status, and if appropriate return from the 159 # subprogram with the value of the operand. 160 161 last = and_.nodes[-1] 162 results = nodes = [] 163 164 for node in and_.nodes: 165 expr = self.dispatch(node) 166 167 # Return from the subprogram where the test is not satisfied. 168 169 if node is not last: 170 nodes += [ 171 StoreTemp(expr=expr), 172 Conditional( 173 test=self._visitNot(LoadTemp()), 174 body=[ 175 ReturnFromBlock( 176 expr=LoadTemp() 177 ) 178 ], 179 else_=[ 180 ReleaseTemp() 181 # Subsequent operations go here! 182 ] 183 ) 184 ] 185 186 # Put subsequent operations in the else section of this conditional. 187 188 nodes = nodes[-1].else_ 189 190 # For the last operation, return the result. 191 192 else: 193 nodes.append(ReturnFromBlock(expr=expr)) 194 195 # Finish the subprogram definition. 196 197 subprogram.code = results 198 199 self.current_subprograms.pop() 200 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 201 202 # Make an invocation of the subprogram. 203 204 result = InvokeBlock(and_, 1, produces_result=1) 205 result.expr = LoadRef(ref=subprogram) 206 return result 207 208 # Assignments. 209 210 def visitAssAttr(self, assattr, in_sequence=0): 211 expr = self._visitAssNameOrAttr(assattr, in_sequence) 212 lvalue = self.dispatch(assattr.expr) 213 result = StoreAttr(assattr, 1, name=assattr.attrname, lvalue=lvalue, expr=expr) 214 return result 215 216 def visitAssign(self, assign): 217 result = Assign(assign, 1) 218 store = StoreTemp(expr=self.dispatch(assign.expr)) 219 release = ReleaseTemp() 220 result.code = [store] + self.dispatches(assign.nodes, 0) + [release] 221 return result 222 223 def visitAssList(self, asslist, in_sequence=0): 224 if not in_sequence: 225 expr = LoadTemp() 226 else: 227 expr = InvokeFunction(asslist, expr=LoadAttr(expr=LoadTemp(), name="next")) 228 result = Assign(asslist, 1) 229 store = StoreTemp(expr=InvokeFunction(asslist, expr=LoadAttr(name="__iter__", expr=expr))) 230 release = ReleaseTemp() 231 result.code = [store] + self.dispatches(asslist.nodes, 1) + [release] 232 return result 233 234 visitAssTuple = visitAssList 235 236 def _visitAssNameOrAttr(self, node, in_sequence): 237 if not in_sequence: 238 return LoadTemp() 239 else: 240 return InvokeFunction(node, expr=LoadAttr(expr=LoadTemp(), name="next")) 241 242 def visitAssName(self, assname, in_sequence=0): 243 expr = self._visitAssNameOrAttr(assname, in_sequence) 244 result = StoreName(assname, 1, name=assname.name, expr=expr) 245 return result 246 247 augassign_methods = { 248 "+=" : "__iadd__", "-=" : "__isub__", "*=" : "__imul__", "/=" : "__idiv__", 249 "%=" : "__imod__", "**=" : "__ipow__", "<<=" : "__ilshift__", ">>=" : "__irshift__", 250 "&=" : "__iand__", "^=" : "__ixor__", "|=" : "__ior__" 251 } 252 253 def visitAugAssign(self, augassign): 254 255 """ 256 Convert the augmented assignment... 257 258 AugAssign (node) -> Name | Getattr | Slice | Subscript 259 (op) 260 (expr) 261 262 ...to: 263 264 Assign (code) -> StoreTemp (expr) -> InvokeFunction (expr) -> LoadAttr (expr) -> <name> 265 (name) -> <op> 266 StoreName (name) -> <name> 267 (expr) -> LoadTemp 268 ReleaseTemp 269 """ 270 271 result = Assign(augassign, 1) 272 expr = self.dispatch(augassign.expr) 273 274 # Simple augmented assignment: name += expr 275 276 if isinstance(augassign.node, compiler.ast.Name): 277 result.code = [ 278 StoreTemp( 279 expr=InvokeFunction( # referenced below 280 augassign, 281 args=[expr], 282 star=None, 283 dstar=None, 284 expr=LoadAttr( 285 expr=self.dispatch(augassign.node), 286 name=self.augassign_methods[augassign.op] 287 ) 288 ) 289 ), 290 StoreName( 291 expr=LoadTemp(), 292 name=augassign.node.name), 293 ReleaseTemp() 294 ] 295 296 # Make nice annotations for the viewer. 297 298 augassign._op_call = result.code[0].expr 299 300 # Complicated augmented assignment: lvalue.attr += expr 301 302 elif isinstance(augassign.node, compiler.ast.Getattr): 303 304 # <lvalue> -> setattr(<lvalue>, getattr(<lvalue>, "attr").__xxx__(expr)) 305 306 result.code = [ 307 StoreTemp( 308 index="expr", 309 expr=self.dispatch(augassign.node.expr) 310 ), 311 StoreTemp( 312 expr=InvokeFunction( # referenced below 313 augassign, 314 args=[expr], star=None, dstar=None, 315 expr=LoadAttr( 316 expr=LoadAttr(augassign.node, 1, 317 expr=LoadTemp(index="expr"), 318 name=augassign.node.attrname 319 ), 320 name=self.augassign_methods[augassign.op] 321 ) 322 ) 323 ), 324 StoreAttr( 325 expr=LoadTemp(), 326 lvalue=LoadTemp(index="expr"), 327 name=augassign.node.attrname 328 ), 329 ReleaseTemp(index="expr"), 330 ReleaseTemp() 331 ] 332 333 # Make nice annotations for the viewer. 334 335 augassign._op_call = result.code[1].expr 336 337 # Complicated augassign using slices: lvalue[lower:upper] += expr 338 339 elif isinstance(augassign.node, compiler.ast.Slice): 340 341 # <lvalue>, <lower>, <upper> -> <lvalue>.__setslice__(<lower>, <upper>, <lvalue>.__getslice__(<lower>, <upper>).__xxx__(expr)) 342 343 result.code = [ 344 StoreTemp( 345 index="expr", 346 expr=self.dispatch(augassign.node.expr) 347 ), 348 StoreTemp( 349 index="lower", 350 expr=self.dispatch_or_none(augassign.node.lower) 351 ), 352 StoreTemp( 353 index="upper", 354 expr=self.dispatch_or_none(augassign.node.upper) 355 ), 356 StoreTemp( 357 expr=InvokeFunction( # referenced below 358 augassign, 359 args=[expr], star=None, dstar=None, 360 expr=LoadAttr( 361 expr=self._visitSlice( 362 augassign.node, 363 LoadTemp(index="expr"), 364 LoadTemp(index="lower"), 365 LoadTemp(index="upper"), 366 "OP_APPLY"), 367 name=self.augassign_methods[augassign.op] 368 ) 369 ) 370 ), 371 self._visitSlice( 372 augassign.node, 373 LoadTemp(index="expr"), 374 LoadTemp(index="lower"), 375 LoadTemp(index="upper"), 376 "OP_ASSIGN", 377 LoadTemp() 378 ), 379 ReleaseTemp(index="expr"), 380 ReleaseTemp(index="lower"), 381 ReleaseTemp(index="upper"), 382 ReleaseTemp() 383 ] 384 385 # Make nice annotations for the viewer. 386 387 augassign._op_call = result.code[3].expr 388 389 # Complicated augassign using subscripts: lvalue[subs] += expr 390 391 elif isinstance(augassign.node, compiler.ast.Subscript): 392 393 # <lvalue>, <subs> -> <lvalue>.__setitem__(<subs>, <lvalue>.__getitem__(<subs>).__xxx__(expr)) 394 395 result.code = [ 396 StoreTemp(index="expr", expr=self.dispatch(augassign.node.expr)), 397 StoreTemp(index="subs", expr=self._visitSubscriptSubs(augassign.node, augassign.node.subs)), 398 StoreTemp( 399 expr=InvokeFunction( # referenced below 400 augassign, 401 args=[expr], star=None, dstar=None, 402 expr=LoadAttr( 403 expr=self._visitSubscript( 404 augassign.node, 405 LoadTemp(index="expr"), 406 LoadTemp(index="subs"), 407 "OP_APPLY" 408 ), 409 name=self.augassign_methods[augassign.op] 410 ) 411 ) 412 ), 413 self._visitSubscript( 414 augassign.node, 415 LoadTemp(index="expr"), 416 LoadTemp(index="subs"), 417 "OP_ASSIGN", 418 LoadTemp() 419 ), 420 ReleaseTemp(index="expr"), 421 ReleaseTemp(index="subs"), 422 ReleaseTemp() 423 ] 424 425 # Make nice annotations for the viewer. 426 427 augassign._op_call = result.code[2].expr 428 429 else: 430 raise NotImplementedError, augassign.node.__class__ 431 432 return result 433 434 def visitBreak(self, break_): 435 result = ReturnFromBlock(break_, 1) 436 return result 437 438 def visitCallFunc(self, callfunc): 439 result = InvokeFunction(callfunc, 1, star=None, dstar=None, args=self.dispatches(callfunc.args)) 440 if callfunc.star_args is not None: 441 result.star = self.dispatch(callfunc.star_args) 442 if callfunc.dstar_args is not None: 443 result.dstar = self.dispatch(callfunc.dstar_args) 444 result.expr = self.dispatch(callfunc.node) 445 return result 446 447 def visitClass(self, class_): 448 449 # Add "object" if the class is not "object" and has an empty bases list. 450 451 if class_.name != "object" and not class_.bases: 452 bases = [compiler.ast.Name("object")] 453 else: 454 bases = class_.bases 455 456 structure = Class(name=class_.name, module=self.module, bases=self.dispatches(bases)) 457 self.structures.append(structure) 458 within_class = self.within_class 459 self.within_class = 1 460 461 # Make a subprogram which initialises the class structure. 462 463 subprogram = Subprogram(name=None, module=self.module, structure=structure, params=[], star=None, dstar=None) 464 self.current_subprograms.append(subprogram) 465 self.current_structures.append(structure) # mostly for name construction 466 467 # The class is initialised using the code found inside. 468 469 subprogram.code = self.dispatch(class_.code) + [ReturnFromBlock()] 470 471 self.within_class = within_class 472 self.current_structures.pop() 473 self.current_subprograms.pop() 474 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 475 476 # Make a definition of the class associating it with a name. 477 478 result = Assign( 479 code=[ 480 StoreName(class_, 1, # defines the class 481 name=class_.name, 482 expr=LoadRef(ref=structure) 483 ), 484 InvokeBlock( 485 class_, 486 share_locals=0, # override the local sharing usually in InvokeBlock 487 expr=LoadRef(ref=subprogram) 488 ) 489 ] 490 ) 491 return result 492 493 comparison_methods = { 494 "==" : ("__eq__", "__ne__"), 495 "!=" : ("__ne__", "__eq__"), 496 "<" : ("__lt__", "__gt__"), 497 "<=" : ("__le__", "__ge__"), 498 ">=" : ("__ge__", "__le__"), 499 ">" : ("__gt__", "__lt__"), 500 "is" : None, 501 "is not" : None 502 } 503 504 def visitCompare(self, compare): 505 506 """ 507 Make a subprogram for the 'compare' node and record its contents inside 508 the subprogram. Convert... 509 510 Compare (expr) 511 (name/node) 512 ... 513 514 ...to: 515 516 InvokeBlock -> Subprogram -> Conditional (test) -> (body) 517 (else) -> Conditional (test) -> (body) 518 (else) -> ... 519 """ 520 521 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) 522 self.current_subprograms.append(subprogram) 523 524 # In the subprogram, make instructions which invoke a method on the 525 # first operand of each operand pair and, if appropriate, return with 526 # the value from that method. 527 528 last = compare.ops[-1] 529 previous = self.dispatch(compare.expr) 530 results = nodes = [] 531 532 # For viewing purposes, record invocations on the AST node. 533 534 compare._ops = [] 535 536 for op in compare.ops: 537 op_name, node = op 538 539 # Make a new AST-style node to wrap the operation program nodes. 540 541 new_op = Op(op_name, node) 542 expr = self.dispatch(node) 543 544 # Identify the operation and produce the appropriate method call. 545 546 method_names = self.comparison_methods[op_name] 547 if method_names: 548 first_name, alternative_name = method_names 549 invocation = self._visitBinaryCompareOp(new_op, previous, expr, first_name, alternative_name) 550 551 elif op_name == "is": 552 invocation = InvokeFunction( 553 new_op, 1, 554 expr=LoadName(name="__is__"), 555 args=[previous, expr], 556 star=None, 557 dstar=None) 558 559 elif op_name == "is not": 560 invocation = Not( 561 new_op, 1, 562 expr=InvokeFunction( 563 new_op, 564 expr=LoadName(name="__is__"), 565 args=[previous, expr], 566 star=None, 567 dstar=None) 568 ) 569 else: 570 raise NotImplementedError, op_name 571 572 nodes.append(StoreTemp(expr=invocation)) 573 compare._ops.append(new_op) 574 575 # Return from the subprogram where the test is not satisfied. 576 577 if op is not last: 578 nodes.append( 579 Conditional( 580 test=self._visitNot(LoadTemp()), 581 body=[ 582 ReturnFromBlock(expr=LoadTemp()) 583 ], 584 else_=[ 585 ReleaseTemp() 586 # Subsequent operations go here! 587 ] 588 ) 589 ) 590 591 # Put subsequent operations in the else section of this conditional. 592 593 nodes = nodes[-1].else_ 594 595 # For the last operation, return the result. 596 597 else: 598 nodes.append( 599 ReturnFromBlock(expr=LoadTemp(release=1)) 600 ) 601 602 previous = expr 603 604 # Finish the subprogram definition. 605 606 subprogram.code = results 607 608 self.current_subprograms.pop() 609 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 610 611 # Make an invocation of the subprogram. 612 613 result = InvokeBlock(compare, 1, produces_result=1) 614 result.expr = LoadRef(ref=subprogram) 615 return result 616 617 def visitConst(self, const): 618 key = "%s-%s" % (const.value.__class__.__name__, const.value) 619 if not self.constants.has_key(key): 620 self.constants[key] = Constant(name=repr(const.value), value=const.value) 621 result = LoadRef(const, 1, ref=self.constants[key]) 622 return result 623 624 def visitContinue(self, continue_): 625 result = InvokeBlock(continue_, 1, 626 expr=LoadRef(ref=self.current_subprograms[-1]) 627 ) 628 return result 629 630 def visitDict(self, dict): 631 result = InvokeFunction(dict, 1, expr=LoadName(name="dict"), star=None, dstar=None) 632 args = [] 633 for key, value in dict.items: 634 tuple = InvokeFunction(dict, expr=LoadName(name="tuple"), star=None, dstar=None) 635 tuple.set_args([self.dispatch(key), self.dispatch(value)]) 636 args.append(tuple) 637 result.set_args(args) 638 return result 639 640 def visitDiscard(self, discard): 641 return self.dispatch(discard.expr) 642 643 def visitDiv(self, div): 644 return self._visitBinary(div, "__div__", "__rdiv__") 645 646 def visitFloorDiv(self, floordiv): 647 return self._visitBinary(floordiv, "__floordiv__", "__rfloordiv__") 648 649 def visitFor(self, for_): 650 651 """ 652 Make a subprogram for the 'for_' node and record its contents inside the 653 subprogram. Convert... 654 655 For (assign) 656 (body) 657 (else) 658 659 ...to: 660 661 Assign (assign #1) 662 Invoke -> Subprogram -> Try (body) -> (assign #2) 663 (body) 664 Invoke subprogram 665 (handler) -> ... 666 (else) -> ... 667 """ 668 669 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=0, params=[], star=None, dstar=None) 670 self.current_subprograms.append(subprogram) 671 672 # Always return from conditional sections/subprograms. 673 674 if for_.else_ is not None: 675 else_stmt = self.dispatch(for_.else_) + [ReturnFromBlock()] 676 else: 677 else_stmt = [ReturnFromBlock()] 678 679 # Wrap the assignment in a try...except statement. 680 # Inside the body, add a recursive invocation to the subprogram. 681 682 subprogram.code = [ 683 Try( 684 body=[ 685 Assign( 686 code=[ 687 StoreTemp(expr=InvokeFunction(for_, expr=LoadAttr(expr=LoadTemp(), name="next"))), 688 self.dispatch(for_.assign), 689 ReleaseTemp() 690 ]) 691 ] + self.dispatch(for_.body) + [ 692 InvokeBlock( 693 for_, 694 expr=LoadRef(ref=subprogram) 695 ) 696 ], 697 handler=[ 698 Conditional( 699 test=InvokeFunction( 700 for_, 701 expr=LoadName(name="isinstance"), 702 args=[LoadExc(), LoadName(name="StopIteration")], 703 star=None, 704 dstar=None), 705 body=else_stmt, 706 else_=[Raise(expr=LoadExc())] 707 ) 708 ], 709 else_=[], 710 finally_=[] 711 ), 712 ReturnFromBlock() 713 ] 714 715 # Finish the subprogram definition. 716 717 self.current_subprograms.pop() 718 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 719 720 # Obtain an iterator for the sequence involved. 721 # Then, make an invocation of the subprogram. 722 723 result = Assign(for_, 1, 724 code=[ 725 StoreTemp( 726 expr=InvokeFunction( 727 for_, 728 expr=LoadAttr( 729 name="__iter__", 730 expr=self.dispatch(for_.list) 731 ) 732 ) 733 ), 734 InvokeBlock(for_, expr=LoadRef(ref=subprogram)), 735 ReleaseTemp() 736 ] 737 ) 738 739 # Make nice annotations for the viewer. 740 741 for_._iter_call = result.code[0].expr 742 for_._next_call = subprogram.code[0].body[0].code[0].expr 743 744 return result 745 746 def visitFrom(self, from_): 747 result = Assign(from_, 1) 748 code = [] 749 _names = [] 750 code.append( 751 StoreTemp( 752 expr=Import(name=from_.modname, alias=1) 753 ) 754 ) 755 from_._modname = code[-1].expr 756 for name, alias in from_.names: 757 code.append( 758 StoreName( 759 expr=LoadAttr( 760 expr=LoadTemp(), 761 name=name), 762 name=(alias or name) 763 ) 764 ) 765 _names.append(code[-1].expr) 766 code.append(ReleaseTemp()) 767 result.code = code 768 from_._names = _names 769 return result 770 771 def _visitFunction(self, function, subprogram): 772 773 """ 774 A common function generator which transforms the given 'function' node 775 and initialises the given 'subprogram' appropriately. 776 """ 777 778 # Discover star and dstar parameters. 779 780 if function.flags & 4 != 0: 781 has_star = 1 782 else: 783 has_star = 0 784 if function.flags & 8 != 0: 785 has_dstar = 1 786 else: 787 has_dstar = 0 788 789 # Discover the number of defaults and positional parameters. 790 791 ndefaults = len(function.defaults) 792 npositional = len(function.argnames) - has_star - has_dstar 793 794 # Produce star and dstar parameters with appropriate defaults. 795 796 if has_star: 797 star = ( 798 function.argnames[npositional], 799 self.dispatch(compiler.ast.List([])) 800 ) 801 else: 802 star = None 803 if has_dstar: 804 dstar = ( 805 function.argnames[npositional + has_star], 806 self.dispatch(compiler.ast.Dict([])) 807 ) 808 else: 809 dstar = None 810 811 params = [] 812 for i in range(0, npositional - ndefaults): 813 params.append((function.argnames[i], None)) 814 815 # Process defaults. 816 817 for i in range(0, ndefaults): 818 default = function.defaults[i] 819 if default is not None: 820 params.append((function.argnames[npositional - ndefaults + i], self.dispatch(default))) 821 else: 822 params.append((function.argnames[npositional - ndefaults + i], None)) 823 824 subprogram.params = params 825 subprogram.star = star 826 subprogram.dstar = dstar 827 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 828 829 def visitFunction(self, function): 830 831 """ 832 Make a subprogram for the 'function' and record it outside the main 833 tree. Produce something like the following: 834 835 StoreName (name) 836 (expr) -> LoadRef (ref) -> Subprogram (params) 837 (star) 838 (dstar) 839 """ 840 841 subprogram = Subprogram(function, name=function.name, module=self.module, structures=self.current_structures[:], 842 internal=0, returns_value=1, star=None, dstar=None, is_method=self.within_class, original_def=function) 843 844 # Make nice annotations for the viewer. 845 846 function._subprogram = subprogram 847 848 self.current_subprograms.append(subprogram) 849 within_class = self.within_class 850 self.within_class = 0 851 852 subprogram.code = self.dispatch(function.code) + [ReturnFromFunction()] 853 854 self.within_class = within_class 855 self.current_subprograms.pop() 856 self._visitFunction(function, subprogram) 857 858 # Make a definition of the function associating it with a name. 859 860 result = StoreName(function, 1, name=function.name, expr=LoadRef(ref=subprogram)) 861 return result 862 863 def visitGetattr(self, getattr): 864 result = LoadAttr(getattr, 1, 865 name=getattr.attrname, 866 expr=self.dispatch(getattr.expr) 867 ) 868 return result 869 870 def visitGlobal(self, global_): 871 result = Global(global_, 1, 872 names=global_.names 873 ) 874 return result 875 876 def visitIf(self, if_): 877 878 """ 879 Make conditionals for each test from an 'if_' AST node, adding the body 880 and putting each subsequent test as part of the conditional's else 881 section. 882 883 Convert... 884 885 If (test/body) 886 (test/body) 887 ... 888 (else/body) 889 890 ...to: 891 892 Conditional (test) -> (body) 893 (else) -> Conditional (test) -> (body) 894 (else) -> ... 895 """ 896 897 898 results = nodes = [] 899 900 # Produce something like... 901 # expr.__bool__() ? body 902 903 first = 1 904 for compare, stmt in if_.tests: 905 906 # Set the first as the defining node. 907 908 test = Conditional(if_, first, 909 test=InvokeFunction( 910 if_, 911 expr=LoadAttr( 912 expr=self.dispatch(compare), 913 name="__bool__" 914 ), 915 ) 916 ) 917 test.body = self.dispatch(stmt) 918 nodes.append(test) 919 nodes = test.else_ = [] 920 first = 0 921 922 # Add the compound statement from any else clause to the end. 923 924 if if_.else_ is not None: 925 nodes += self.dispatch(if_.else_) 926 927 result = results[0] 928 return result 929 930 def visitImport(self, import_): 931 result = Assign(import_, 1) 932 code = [] 933 _names = [] 934 for path, alias in import_.names: 935 importer = Import(name=path, alias=alias) 936 top = alias or path.split(".")[0] 937 code.append(StoreName(expr=importer, name=top)) 938 _names.append(code[-1].expr) 939 result.code = code 940 import_._names = _names 941 return result 942 943 def visitInvert(self, invert): 944 return self._visitUnary(invert, "__invert__") 945 946 def visitKeyword(self, keyword): 947 result = Keyword(keyword, 1, 948 name=keyword.name, 949 expr=self.dispatch(keyword.expr) 950 ) 951 return result 952 953 def visitLambda(self, lambda_): 954 955 # Make a subprogram for the function and record it outside the main 956 # tree. 957 958 subprogram = Subprogram(lambda_, name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None, original_def=lambda_) 959 960 # Make nice annotations for the viewer. 961 962 function._subprogram = subprogram 963 964 # Process the lambda contents. 965 966 self.current_subprograms.append(subprogram) 967 subprogram.code = [ReturnFromFunction(expr=self.dispatch(lambda_.code))] 968 self.current_subprograms.pop() 969 self._visitFunction(lambda_, subprogram) 970 971 # Get the subprogram reference to the lambda. 972 973 return LoadRef(lambda_, 1, ref=subprogram) 974 975 def visitList(self, list): 976 return self._visitBuiltin(list, "list") 977 978 def visitMod(self, mod): 979 return self._visitBinary(mod, "__mod__", "__rmod__") 980 981 def visitMul(self, mul): 982 return self._visitBinary(mul, "__mul__", "__rmul__") 983 984 def visitName(self, name): 985 result = LoadName(name, 1, name=name.name) 986 return result 987 988 def _visitNot(self, expr, not_=None): 989 invocation = InvokeFunction( 990 not_, # NOTE: May need a real original node. 991 expr=LoadAttr( 992 expr=expr, 993 name="__bool__" 994 ), 995 ) 996 if not_ is not None: 997 result = Not(not_, 1, expr=invocation) 998 else: 999 result = Not(expr=invocation) 1000 return result 1001 1002 def visitNot(self, not_): 1003 return self._visitNot(self.dispatch(not_.expr), not_) 1004 1005 def visitOr(self, or_): 1006 1007 """ 1008 Make a subprogram for the 'or_' node and record its contents inside the 1009 subprogram. Convert... 1010 1011 Or (test) 1012 (test) 1013 ... 1014 1015 ...to: 1016 1017 Subprogram -> Conditional (test) -> ReturnFromBlock ... 1018 (else) -> Conditional (test) -> ReturnFromBlock ... 1019 (else) -> ... 1020 """ 1021 1022 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) 1023 self.current_subprograms.append(subprogram) 1024 1025 # In the subprogram, make instructions which store each operand, test 1026 # for each operand's truth status, and if appropriate return from the 1027 # subprogram with the value of the operand. 1028 1029 last = or_.nodes[-1] 1030 results = nodes = [] 1031 1032 for node in or_.nodes: 1033 expr = self.dispatch(node) 1034 1035 # Return from the subprogram where the test is satisfied. 1036 1037 if node is not last: 1038 nodes.append(StoreTemp(expr=expr)) 1039 invocation = InvokeFunction(or_, expr=LoadAttr(expr=LoadTemp(), name="__bool__")) 1040 test = Conditional(test=invocation, body=[ReturnFromBlock(expr=LoadTemp())]) 1041 nodes.append(test) 1042 1043 # Put subsequent operations in the else section of this conditional. 1044 1045 nodes = test.else_ = [ReleaseTemp()] 1046 1047 # For the last operation, return the result. 1048 1049 else: 1050 nodes.append( 1051 ReturnFromBlock(expr=expr) 1052 ) 1053 1054 # Finish the subprogram definition. 1055 1056 subprogram.code = results 1057 1058 self.current_subprograms.pop() 1059 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1060 1061 # Make an invocation of the subprogram. 1062 1063 result = InvokeBlock(or_, 1, produces_result=1) 1064 result.expr = LoadRef(ref=subprogram) 1065 return result 1066 1067 def visitPass(self, pass_): 1068 return Pass(pass_, 1) 1069 1070 def visitPower(self, power): 1071 return self._visitBinary(power, "__pow__", "__rpow__") 1072 1073 def visitPrint(self, print_): 1074 1075 """ 1076 Convert... 1077 1078 Print (dest) -> 1079 (nodes) 1080 1081 ...to: 1082 1083 StoreTemp (index) -> "print" 1084 (expr) -> LoadAttr (expr) -> (dest) 1085 (name) -> "write" 1086 InvokeFunction (expr) -> LoadTemp (index) -> "print" 1087 (args) -> [(node)] 1088 ReleaseTemp (index) -> "print" 1089 """ 1090 1091 if print_.dest is not None: 1092 dest = self.dispatch(print_.dest) 1093 else: 1094 dest = self.dispatch(compiler.ast.Name("stdout")) 1095 1096 result = Assign(print_, 1, 1097 code=[ 1098 StoreTemp( 1099 index="print", 1100 expr=LoadAttr( 1101 expr=dest, 1102 name="write" 1103 ) 1104 ) 1105 ] 1106 ) 1107 1108 for node in print_.nodes: 1109 result.code.append( 1110 InvokeFunction( 1111 print_, 1112 expr=LoadTemp(index="print"), 1113 args=[self.dispatch(node)], 1114 star=None, 1115 dstar=None 1116 ) 1117 ) 1118 1119 result.code.append( 1120 ReleaseTemp(index="print") 1121 ) 1122 1123 return result 1124 1125 def visitPrintnl(self, printnl): 1126 result = self.visitPrint(printnl) 1127 result.code.insert( 1128 len(result.code) - 1, 1129 InvokeFunction( 1130 printnl, 1131 expr=LoadTemp(index="print"), 1132 args=[self.dispatch(compiler.ast.Const("\n"))], 1133 star=None, 1134 dstar=None 1135 ) 1136 ) 1137 return result 1138 1139 def visitRaise(self, raise_): 1140 result = Raise(raise_, 1) 1141 if raise_.expr2 is None: 1142 result.expr = self.dispatch(raise_.expr1) 1143 else: 1144 result.expr = InvokeFunction( 1145 raise_, 1146 expr=self.dispatch(raise_.expr1), 1147 args=[self.dispatch(raise_.expr2)], 1148 star=None, 1149 dstar=None 1150 ) 1151 if raise_.expr3 is not None: 1152 result.traceback = self.dispatch(raise_.expr3) 1153 else: 1154 result.traceback = None 1155 return result 1156 1157 def visitReturn(self, return_): 1158 result = ReturnFromFunction(return_, 1, 1159 expr=self.dispatch(return_.value) 1160 ) 1161 return result 1162 1163 def _visitSlice(self, slice, expr, lower, upper, flags, value=None): 1164 if flags == "OP_ASSIGN": 1165 result = InvokeFunction(slice, 1, 1166 expr=LoadAttr( 1167 expr=expr, 1168 name="__setslice__" 1169 ), 1170 star=None, 1171 dstar=None, 1172 args=[lower, upper, value] 1173 ) 1174 elif flags == "OP_APPLY": 1175 args = [] 1176 result = InvokeFunction(slice, 1, 1177 expr=LoadAttr( 1178 expr=expr, 1179 name="__getslice__" 1180 ), 1181 star=None, 1182 dstar=None, 1183 args=[lower, upper] 1184 ) 1185 elif flags == "OP_DELETE": 1186 args = [] 1187 result = InvokeFunction(slice, 1, 1188 expr=LoadAttr( 1189 expr=expr, 1190 name="__delslice__" 1191 ), 1192 star=None, 1193 dstar=None, 1194 args=[lower, upper] 1195 ) 1196 else: 1197 raise NotImplementedError, flags 1198 1199 return result 1200 1201 def visitSlice(self, slice, in_sequence=0): 1202 return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower), 1203 self.dispatch_or_none(slice.upper), slice.flags, self._visitAssNameOrAttr(slice, in_sequence)) 1204 1205 def visitStmt(self, stmt): 1206 return self.dispatches(stmt.nodes) 1207 1208 def visitSub(self, sub): 1209 return self._visitBinary(sub, "__sub__", "__rsub__") 1210 1211 def _visitSubscript(self, subscript, expr, subs, flags, value=None): 1212 if flags == "OP_ASSIGN": 1213 result = InvokeFunction(subscript, 1, 1214 expr=LoadAttr( 1215 expr=expr, 1216 name="__setitem__" 1217 ), 1218 star=None, 1219 dstar=None, 1220 args=[subs, value] 1221 ) 1222 elif flags == "OP_APPLY": 1223 args = [] 1224 result = InvokeFunction(subscript, 1, 1225 expr=LoadAttr( 1226 expr=expr, 1227 name="__getitem__" 1228 ), 1229 star=None, 1230 dstar=None, 1231 args=[subs] 1232 ) 1233 elif flags == "OP_DELETE": 1234 args = [] 1235 result = InvokeFunction(subscript, 1, 1236 expr=LoadAttr( 1237 expr=expr, 1238 name="__delitem__" 1239 ), 1240 star=None, 1241 dstar=None, 1242 args=[subs] 1243 ) 1244 else: 1245 raise NotImplementedError, flags 1246 1247 return result 1248 1249 def _visitSubscriptSubs(self, node, subs): 1250 if len(subs) == 1: 1251 return self.dispatch(subs[0]) 1252 else: 1253 return InvokeFunction(node, 1, 1254 expr=LoadName(name="tuple"), 1255 args=self.dispatches(subs), 1256 star=None, 1257 dstar=None 1258 ) 1259 1260 def visitSubscript(self, subscript, in_sequence=0): 1261 return self._visitSubscript( 1262 subscript, self.dispatch(subscript.expr), self._visitSubscriptSubs(subscript, subscript.subs), subscript.flags, 1263 self._visitAssNameOrAttr(subscript, in_sequence) 1264 ) 1265 1266 def visitTryExcept(self, tryexcept): 1267 1268 """ 1269 Make conditionals for each handler associated with a 'tryexcept' node. 1270 1271 Convert... 1272 1273 TryExcept (body) 1274 (else) 1275 (spec/assign/stmt) 1276 ... 1277 1278 ...to: 1279 1280 Try (body) 1281 (else) 1282 (handler) -> Conditional (test) -> (stmt) 1283 (body) -> ResetExc ... 1284 (else) -> Conditional (test) -> (stmt) 1285 (body) -> ResetExc ... 1286 (else) -> ... 1287 """ 1288 1289 result = Try(tryexcept, 1, body=[], else_=[], finally_=[]) 1290 1291 if tryexcept.body is not None: 1292 result.body = self.dispatch(tryexcept.body) 1293 if tryexcept.else_ is not None: 1294 result.else_ = self.dispatch(tryexcept.else_) 1295 1296 results = nodes = [] 1297 catch_all = 0 1298 1299 for spec, assign, stmt in tryexcept.handlers: 1300 1301 # If no specification exists, produce an unconditional block. 1302 1303 if spec is None: 1304 nodes += self.dispatch(stmt) 1305 catch_all = 1 1306 1307 # Produce an exception value check. 1308 1309 else: 1310 test = Conditional( 1311 isolate_test=1, 1312 test=CheckType(expr=LoadExc(), choices=self._visitTryExcept(spec)) 1313 ) 1314 test.body = [] 1315 1316 if assign is not None: 1317 test.body.append( 1318 Assign( 1319 code=[ 1320 StoreTemp(expr=LoadExc()), 1321 self.dispatch(assign), 1322 ReleaseTemp() 1323 ] 1324 ) 1325 ) 1326 1327 test.body += [ResetExc()] + self.dispatch(stmt) 1328 nodes.append(test) 1329 nodes = test.else_ = [] 1330 1331 # Add a raise operation to deal with unhandled exceptions. 1332 1333 if not catch_all: 1334 nodes.append( 1335 Raise( 1336 expr=LoadExc()) 1337 ) 1338 1339 result.handler = results 1340 return result 1341 1342 def _visitTryExcept(self, spec): 1343 1344 "Return a list of nodes for the given exception type 'spec'." 1345 1346 if isinstance(spec, compiler.ast.Tuple): 1347 nodes = [] 1348 for node in spec.nodes: 1349 nodes += self._visitTryExcept(node) 1350 else: 1351 nodes = [self.dispatch(spec)] 1352 return nodes 1353 1354 def visitTryFinally(self, tryfinally): 1355 result = Try(tryfinally, 1, body=[], else_=[], finally_=[]) 1356 if tryfinally.body is not None: 1357 result.body = self.dispatch(tryfinally.body) 1358 if tryfinally.final is not None: 1359 result.finally_ = self.dispatch(tryfinally.final) 1360 return result 1361 1362 def visitTuple(self, tuple): 1363 return self._visitBuiltin(tuple, "tuple") 1364 1365 def visitUnaryAdd(self, unaryadd): 1366 return self._visitUnary(unaryadd, "__pos__") 1367 1368 def visitUnarySub(self, unarysub): 1369 return self._visitUnary(unarysub, "__neg__") 1370 1371 def visitWhile(self, while_): 1372 1373 """ 1374 Make a subprogram for the 'while' node and record its contents inside the 1375 subprogram. Convert... 1376 1377 While (test) -> (body) 1378 (else) 1379 1380 ...to: 1381 1382 Subprogram -> Conditional (test) -> (body) -> Invoke subprogram 1383 (else) -> Conditional (test) -> ReturnFromBlock ... 1384 (else) -> ... 1385 """ 1386 1387 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=0, params=[], star=None, dstar=None) 1388 self.current_subprograms.append(subprogram) 1389 1390 # Include a conditional statement in the subprogram. 1391 # Inside the conditional, add a recursive invocation to the subprogram 1392 # if the test condition was satisfied. 1393 # Return within the main section of the loop. 1394 1395 test = Conditional( 1396 test=InvokeFunction( 1397 while_, 1398 expr=LoadAttr( 1399 expr=self.dispatch(while_.test), 1400 name="__bool__"), 1401 ), 1402 body=self.dispatch(while_.body) + [ 1403 InvokeBlock( 1404 while_, 1405 expr=LoadRef(ref=subprogram) 1406 ), 1407 ReturnFromBlock() 1408 ], 1409 else_=[] 1410 ) 1411 1412 # Provide the else section, if present, along with an explicit return. 1413 1414 if while_.else_ is not None: 1415 test.else_ = self.dispatch(while_.else_) + [ReturnFromBlock()] 1416 1417 # Finish the subprogram definition. 1418 1419 subprogram.code = [test] 1420 1421 self.current_subprograms.pop() 1422 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1423 1424 # Make an invocation of the subprogram. 1425 1426 result = InvokeBlock(while_, 1, 1427 expr=LoadRef(ref=subprogram) 1428 ) 1429 1430 # Make nice annotations for the viewer. 1431 1432 while_._test_call = subprogram.code[0].test 1433 1434 return result 1435 1436 # Convenience methods. 1437 1438 def _visitBinary(self, binary, left_name, right_name): 1439 return self._visitBinaryOp(binary, self.dispatch(binary.left), self.dispatch(binary.right), left_name, right_name) 1440 1441 def _visitBinaryCompareOp(self, binary, left, right, left_name, right_name): 1442 1443 """ 1444 Emulate the current mechanisms by producing nodes as follows: 1445 1446 InvokeBlock -> Subprogram -> StoreTemp (expr) -> x.__lt__(y) 1447 Conditional (test) -> __is__(LoadTemp, NotImplemented) 1448 (body) -> ReleaseTemp 1449 StoreTemp (expr) -> y.__gt__(x) 1450 Conditional (test) -> __is__(LoadTemp, NotImplemented) 1451 (body) -> ReturnFromBlock (expr) -> False 1452 (else) -> ReturnFromBlock (expr) -> LoadTemp 1453 (else) -> ReturnFromBlock (expr) -> LoadTemp 1454 """ 1455 1456 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) 1457 self.current_subprograms.append(subprogram) 1458 1459 subprogram.code = [ 1460 StoreTemp( 1461 expr=InvokeFunction( 1462 binary, 1463 expr=LoadAttr(expr=left, name=left_name), 1464 args=[right], 1465 star=None, 1466 dstar=None) 1467 ), 1468 Conditional( 1469 isolate_test=1, 1470 test=CheckType( 1471 expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")] 1472 ), 1473 body=[ 1474 ReleaseTemp(), 1475 StoreTemp( 1476 expr=InvokeFunction( 1477 binary, 1478 expr=LoadAttr(expr=right, name=right_name), 1479 args=[left], 1480 star=None, 1481 dstar=None) 1482 ), 1483 Conditional( 1484 isolate_test=1, 1485 test=CheckType( 1486 expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")] 1487 ), 1488 body=[ 1489 ReturnFromBlock( 1490 expr=LoadName(name="False") 1491 ) 1492 ], 1493 else_=[ 1494 CheckType( 1495 inverted=1, expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")] 1496 ), 1497 ReturnFromBlock( 1498 expr=LoadTemp() 1499 ) 1500 ] 1501 ) 1502 ], 1503 else_=[ 1504 CheckType( 1505 inverted=1, expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")] 1506 ), 1507 ReturnFromBlock( 1508 expr=LoadTemp() 1509 ) 1510 ] 1511 ) 1512 ] 1513 1514 self.current_subprograms.pop() 1515 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1516 1517 result = InvokeBlock( 1518 binary, 1519 produces_result=1, 1520 expr=LoadRef(ref=subprogram) 1521 ) 1522 1523 # Make nice annotations for the viewer. 1524 1525 binary._left_call = subprogram.code[0].expr 1526 binary._right_call = subprogram.code[1].body[1].expr 1527 1528 return result 1529 1530 def _visitBinaryOp(self, binary, left, right, left_name, right_name): 1531 1532 """ 1533 Emulate the current mechanisms by producing nodes as follows: 1534 1535 InvokeBlock -> Subprogram -> Try (body) -> ReturnFromBlock (expr) -> x.__add__(y) 1536 (else) 1537 (handler) -> Conditional (test) -> CheckType (expr) -> LoadExc 1538 (choices) -> LoadName TypeError 1539 (body) -> ReturnFromBlock (expr) -> y.__radd__(x) 1540 (else) 1541 """ 1542 1543 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None) 1544 self.current_subprograms.append(subprogram) 1545 1546 subprogram.code = [ 1547 Try(binary, 1, 1548 body=[ 1549 ReturnFromBlock( 1550 expr=InvokeFunction( 1551 binary, 1552 expr=LoadAttr(expr=left, name=left_name), 1553 args=[right], 1554 star=None, 1555 dstar=None) 1556 ) 1557 ], 1558 else_=[], 1559 finally_=[], 1560 handler=[ 1561 Conditional( 1562 test=CheckType(expr=LoadExc(), choices=[LoadName(name="TypeError")]), 1563 body=[ 1564 ReturnFromBlock( 1565 expr=InvokeFunction( 1566 binary, 1567 expr=LoadAttr(expr=right, name=right_name), 1568 args=[left], 1569 star=None, 1570 dstar=None) 1571 ) 1572 ], 1573 else_=[] 1574 ) 1575 ] 1576 ) 1577 ] 1578 1579 self.current_subprograms.pop() 1580 self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram 1581 1582 result = InvokeBlock( 1583 binary, 1584 produces_result=1, 1585 expr=LoadRef(ref=subprogram) 1586 ) 1587 1588 # Make nice annotations for the viewer. 1589 1590 binary._left_call = subprogram.code[0].body[0].expr 1591 binary._right_call = subprogram.code[0].handler[0].body[0].expr 1592 1593 return result 1594 1595 def _visitBuiltin(self, builtin, name): 1596 result = InvokeFunction(builtin, 1, expr=LoadName(name=name), args=self.dispatches(builtin.nodes), star=None, dstar=None) 1597 return result 1598 1599 def _visitUnary(self, unary, name): 1600 result = InvokeFunction(unary, 1, 1601 expr=LoadAttr( 1602 expr=self.dispatch(unary.expr), 1603 name=name 1604 ) 1605 ) 1606 1607 # Make nice annotations for the viewer. 1608 1609 unary._unary_call = result 1610 1611 return result 1612 1613 # Convenience functions. 1614 1615 def simplify(filename, builtins=0, module_name=None): 1616 1617 """ 1618 Simplify the module stored in the file with the given 'filename'. 1619 1620 If the optional 'builtins' parameter is set to a true value (the default 1621 being a false value), then the module is considered as the builtins module. 1622 """ 1623 1624 simplifier = Simplifier(builtins) 1625 module = compiler.parseFile(filename) 1626 compiler.misc.set_filename(filename, module) 1627 if builtins: 1628 name = module_name or "__builtins__" 1629 else: 1630 path, ext = os.path.splitext(filename) 1631 path, name = os.path.split(path) 1632 name = module_name or name 1633 simplified = simplifier.process(module, name) 1634 return simplified 1635 1636 # vim: tabstop=4 expandtab shiftwidth=4