1 #!/usr/bin/env python 2 3 """ 4 Produce syspython code from an inspected program. 5 6 Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from micropython.common import * 23 from micropython.data import * 24 from micropython.errors import * 25 from os.path import exists, extsep, join 26 from micropython.stdcompiler import compiler 27 import sys 28 import os 29 30 try: 31 set 32 except NameError: 33 from sets import Set as set 34 35 # Convenience definitions. 36 37 special_name = compiler.ast.Name 38 39 def quoted_name(s): 40 return compiler.ast.Const(s) 41 42 def quoted_ref(obj): 43 return compiler.ast.CallFunc("static", [quoted_name(obj.full_name())]) 44 45 def module_attribute(module_name, attrname): 46 return special_name(module_name + "." + attrname) 47 48 def constant_attribute(parent, attrname): 49 return compiler.ast.CallFunc("static", [quoted_name(parent.full_name() + "." + attrname)]) 50 51 # Special function names. 52 # Some of the assignment operations cannot be supported unless attribute usage 53 # observations are being made. 54 55 assattr_functions = ("storeattrcontext", "storeattrcontext", 56 "storeattr", "storeattrindexcontextcond", 57 None) 58 getattr_functions = ("loadattrcontext", "loadattrcontextcond", 59 "loadattr", "loadattrindexcontextcond", 60 "loadconstant") 61 62 # Source code classes. 63 64 class ConvertedSource(ASTVisitor): 65 66 "A conversion of module source code to syspython." 67 68 def __init__(self, module, program): 69 self.visitor = self 70 self.module = module 71 self.program = program 72 self.objtable = program.get_object_table() 73 self.in_main = False 74 self.units = [] 75 76 def get_unit(self): 77 return self.units[-1] 78 79 def get_module(self): 80 return self.units[0] 81 82 def to_stream(self, stream): 83 84 "Write the converted code to the given 'stream'." 85 86 module = self.dispatch(self.module.astnode) 87 stream.write(str(module)) 88 89 def NOP(self, node): 90 return node 91 92 def visitModule(self, node): 93 module = node.unit 94 self.units.append(module) 95 96 definitions = self.process_definitions(node) 97 98 # keywords(name, ...) 99 100 keywords = module.keyword_names and [ 101 compiler.ast.CallFunc( 102 special_name("keywords"), 103 [special_name(name) for name in module.keyword_names] 104 ) 105 ] or [] 106 107 # globalnames(name, ...) 108 109 globalnames = module.module_attribute_names() and [ 110 compiler.ast.CallFunc( 111 special_name("globalnames"), 112 [special_name(attr.name) for attr in module.attributes_as_list()] 113 ) 114 ] or [] 115 116 # def __main__(): 117 # ... 118 119 self.in_main = True 120 121 main = compiler.ast.Function( 122 [], "__main__", [], [], 0, "Module initialisation.", 123 compiler.ast.Stmt(globalnames + self.dispatch(node.node).nodes) 124 ) 125 126 self.in_main = False 127 self.units.pop() 128 129 return compiler.ast.Module(node.doc, compiler.ast.Stmt(keywords + definitions + [main])) 130 131 # Statements. 132 133 def visitAssert(self, node): 134 return compiler.ast.Assert(self.dispatch(node.test), node.fail and self.dispatch(node.fail)) 135 136 def visitAssign(self, node): 137 expr = self.dispatch(node.expr) 138 return compiler.ast.Stmt( 139 [compiler.ast.Assign([compiler.ast.AssName("expr", "OP_ASSIGN")], expr)] + 140 [self.dispatch(n, compiler.ast.Name("expr")) for n in node.nodes] 141 ) 142 143 def visitAugAssign(self, node): 144 145 # lvalue = op(lvalue, expr) 146 # -> fn(lvalue, op(lvalue, expr)) 147 148 op_name = operator_functions[node.op] 149 150 return self.dispatch(node.node, compiler.ast.CallFunc( 151 special_name("apply"), 152 [module_attribute("operator", op_name), 153 self.dispatch(node.node), self.dispatch(node.expr)] 154 )) 155 156 visitBreak = NOP 157 158 def visitClass(self, node): 159 if not used_by_unit(node): 160 return compiler.ast.Stmt([]) 161 162 self.units.append(node.unit) 163 try: 164 # Incorporate class body code in the main function. 165 166 if self.in_main: 167 return self.dispatch(node.code) 168 else: 169 return self._visitClassDefinition(node) 170 171 finally: 172 self.units.pop() 173 174 def _visitClassDefinition(self, node): 175 cls = node.unit 176 177 # instattrs(name, ...) 178 # clsattrs(name, ...) 179 180 instattrs = cls.instance_attribute_names() and [ 181 compiler.ast.CallFunc( 182 special_name("instattrs"), 183 [special_name(attr.name) for attr in cls.instance_attributes_as_list()] 184 ) 185 ] or [] 186 187 clsattrs = cls.class_attribute_names() and [ 188 compiler.ast.CallFunc( 189 special_name("clsattrs"), 190 [special_name(attr.name) for attr in cls.attributes_as_list()] 191 ) 192 ] or [] 193 194 # inherited(superclass, name, ...) 195 # ... 196 197 attrs_by_cls = {} 198 for attrname, attr in cls.all_class_attributes().items(): 199 supercls = attr.parent 200 if supercls is cls: 201 continue 202 if not attrs_by_cls.has_key(supercls): 203 attrs_by_cls[supercls] = [] 204 attrs_by_cls[supercls].append(attrname) 205 206 inherited = [] 207 208 for supercls, attrnames in attrs_by_cls.items(): 209 inherited.append( 210 compiler.ast.CallFunc( 211 special_name("inherited"), 212 [quoted_ref(supercls)] + [special_name(name) for name in attrnames] 213 )) 214 215 # descendants(name, ...) 216 217 descendants = cls.all_descendants() and [ 218 compiler.ast.CallFunc( 219 special_name("descendants"), 220 [special_name(name) for name in cls.all_descendants().keys()] 221 ) 222 ] or [] 223 224 # Process all the definitions defined inside the class. 225 226 definitions = self.process_definitions(node) 227 228 return compiler.ast.Class(node.name, [], node.doc, 229 compiler.ast.Stmt(instattrs + clsattrs + inherited + descendants + definitions) 230 ) 231 232 visitContinue = NOP 233 234 def visitDiscard(self, node): 235 return compiler.ast.Discard(self.dispatch(node.expr)) 236 237 def visitFor(self, node): 238 239 """ 240 Convert from... 241 242 for <assign> in <list>: 243 <body> 244 [ else: 245 <else_> ] 246 247 ...to... 248 249 _it = iter(<list>) 250 while True: 251 try: 252 <assign> = _it.next() 253 except StopIteration: 254 [ <else_> ] 255 break 256 else: 257 <body> 258 """ 259 260 unit = self.get_unit() 261 temp = quoted_name(unit.temp_usage) 262 unit.temp_usage += 1 263 264 else_nodes = node.else_ and self.dispatch(node.else_).nodes or [] 265 266 return compiler.ast.Stmt([ 267 # storetemp(_it, __builtins__.iter(<list>)) 268 compiler.ast.CallFunc(special_name("storetemp"), [ 269 temp, 270 compiler.ast.CallFunc( 271 special_name("apply"), 272 [module_attribute("__builtins__", "iter"), self.dispatch(node.list)] 273 ) 274 ]), 275 # while True: ... 276 compiler.ast.While( 277 special_name("True"), 278 # try: ... 279 compiler.ast.TryExcept( 280 compiler.ast.Stmt([ 281 # <assign> = ... 282 self.dispatch(node.assign, 283 # _it.next() 284 compiler.ast.CallFunc( 285 compiler.ast.CallFunc(special_name("loadattrindex"), [ 286 compiler.ast.CallFunc(special_name("loadtemp"), [temp]), 287 special_name("next") 288 ]), 289 [] 290 ) 291 ) 292 ]), 293 # except StopIteration: ... 294 [(special_name("StopIteration"), None, compiler.ast.Stmt(else_nodes + [compiler.ast.Break()]))], 295 # else: ... 296 self.dispatch(node.body) 297 ), 298 None 299 ) 300 ]) 301 302 def visitFrom(self, node): 303 304 # Generate __main__ function calls for each step in the imported module 305 # hierarchy. 306 307 statements = [] 308 309 for modname in self.module.get_module_paths(node.modname): 310 statements.append( 311 compiler.ast.CallFunc(special_name("%s.__main__" % modname ), []) 312 ) 313 314 for name, alias in node.names: 315 statements.append( 316 compiler.ast.CallFunc( 317 special_name("storelocal"), 318 [special_name(alias or name), 319 compiler.ast.CallFunc( 320 special_name("loadattr"), 321 [special_name(node.modname), special_name(name)] 322 ) 323 ]) 324 ) 325 326 return compiler.ast.Stmt(statements) 327 328 def visitFunction(self, node): 329 if not used_by_unit(node): 330 return compiler.ast.Stmt([]) 331 332 self.units.append(node.unit) 333 334 try: 335 if self.in_main: 336 337 # Generate rebindings of functions. 338 339 fn = node.unit 340 if fn.name == fn.original_name: 341 return compiler.ast.Stmt([]) 342 else: 343 return compiler.ast.CallFunc( 344 special_name("storeattr"), 345 [quoted_ref(fn.parent), special_name(fn.original_name), 346 quoted_ref(fn)] 347 ) 348 else: 349 return self._visitFunctionDefinition(node) 350 finally: 351 self.units.pop() 352 353 def _visitFunctionDefinition(self, node): 354 fn = node.unit 355 356 # localnames(name, ...) 357 # globalnames(name, ...) 358 359 localnames = fn.all_locals() and [ 360 compiler.ast.CallFunc( 361 special_name("localnames"), 362 [special_name(name) for name in fn.all_locals().keys()] 363 ) 364 ] or [] 365 366 globalnames = fn.globals and [ 367 compiler.ast.CallFunc( 368 special_name("globalnames"), 369 [special_name(name) for name in fn.globals] 370 ) 371 ] or [] 372 373 defaults = [self.dispatch(n) for n in node.defaults] 374 375 # NOTE: Should generate guards for attribute usage operations. 376 377 code = self.dispatch(node.code) 378 379 return compiler.ast.Function(node.decorators, node.name, node.argnames, defaults, node.flags, node.doc, 380 compiler.ast.Stmt(localnames + globalnames + code.nodes)) 381 382 visitGlobal = NOP 383 384 def visitIf(self, node): 385 return compiler.ast.If( 386 [(self.dispatch(compare), self.dispatch(stmt)) for (compare, stmt) in node.tests], 387 node.else_ and self.dispatch(node.else_) 388 ) 389 390 def visitImport(self, node): 391 392 # Generate __main__ function calls for each step in the imported module 393 # hierarchy. 394 395 statements = [] 396 397 for name, alias in node.names: 398 for modname in self.module.get_module_paths(name): 399 statements.append( 400 compiler.ast.CallFunc(compiler.ast.Getattr(modname, "__main__"), []) 401 ) 402 403 statements.append( 404 compiler.ast.CallFunc( 405 special_name("storelocal"), 406 [special_name(alias or name.split(".")[0]), 407 compiler.ast.CallFunc( 408 special_name("static"), 409 [special_name(name)] 410 ) 411 ]) 412 ) 413 414 return compiler.ast.Stmt(statements) 415 416 def visitPass(self, node): 417 if not isinstance(self.get_unit(), Class): 418 return compiler.ast.Pass() 419 else: 420 return compiler.ast.Stmt([]) 421 422 def visitPrint(self, node): 423 return compiler.ast.CallFunc( 424 special_name("apply"), 425 [module_attribute("__builtins__", "_print"), 426 node.dest and self.dispatch(node.dest) or special_name("None")] 427 + [self.dispatch(n) for n in node.nodes] 428 ) 429 430 def visitPrintnl(self, node): 431 return compiler.ast.CallFunc( 432 special_name("apply"), 433 [module_attribute("__builtins__", "_println"), 434 node.dest and self.dispatch(node.dest) or special_name("None")] 435 + [self.dispatch(n) for n in node.nodes] 436 ) 437 438 def visitRaise(self, node): 439 return compiler.ast.Raise( 440 node.expr1 and self.dispatch(node.expr1), 441 node.expr2 and self.dispatch(node.expr2), 442 node.expr3 and self.dispatch(node.expr3) 443 ) 444 445 def visitReturn(self, node): 446 return compiler.ast.Return(self.dispatch(node.value)) 447 448 def visitStmt(self, node): 449 return compiler.ast.Stmt([self.dispatch(n) for n in node.nodes]) 450 451 def visitTryExcept(self, node): 452 # NOTE: Need to dispatch to the assignment with the exception. 453 return compiler.ast.TryExcept( 454 self.dispatch(node.body), 455 [(spec and self.dispatch(spec), assign and self.dispatch(assign), self.dispatch(statement)) 456 for spec, assign, statement in node.handlers], 457 node.else_ and self.dispatch(node.else_) 458 ) 459 460 def visitTryFinally(self, node): 461 return compiler.ast.TryFinally( 462 self.dispatch(node.body), 463 self.dispatch(node.final) 464 ) 465 466 def visitWhile(self, node): 467 return compiler.ast.While( 468 self.dispatch(node.test), 469 self.dispatch(node.body), 470 node.else_ and self.dispatch(node.else_) 471 ) 472 473 def visitYield(self, node): 474 return compiler.ast.Yield(self.dispatch(node.value)) 475 476 # Expression-related helper methods. 477 478 def _visitBitBinary(self, node): 479 op_name = operator_functions[node.__class__.__name__] 480 last = self.dispatch(node.nodes[0]) 481 482 for n in node.nodes[1:]: 483 last = compiler.ast.CallFunc( 484 special_name("apply"), 485 [module_attribute("operator", op_name), last, self.dispatch(n)] 486 ) 487 488 return last 489 490 def _visitBinary(self, node): 491 op_name = operator_functions[node.__class__.__name__] 492 493 return compiler.ast.CallFunc( 494 special_name("apply"), 495 [module_attribute("operator", op_name), 496 self.dispatch(node.left), self.dispatch(node.right)] 497 ) 498 499 def _visitUnary(self, node): 500 op_name = operator_functions[node.__class__.__name__] 501 502 return compiler.ast.CallFunc( 503 special_name("apply"), 504 [module_attribute("operator", op_name), self.dispatch(node.expr)] 505 ) 506 507 def _generateValue(self, value): 508 509 # Literal constants. 510 511 if isinstance(value, Const): 512 return compiler.ast.Const(value.get_value()) 513 514 # Other constant structures. 515 516 if isinstance(value, Constant): 517 return quoted_ref(value) 518 519 return None 520 521 def _visitAttr(self, node, expr=None): 522 unit = self.get_unit() 523 524 # Choose the appropriate special functions. 525 526 (opattrcontext, opattrcontextcond, opattr, opattrindexcontextcond, opconstant) = \ 527 expr and assattr_functions or getattr_functions 528 529 accessor = self.dispatch(node.expr) 530 531 # Generate already-deduced accesses. 532 533 if node._access_type == "constant": 534 value = self._generateValue(node._value_deduced) 535 536 # Where constant attributes are accessed via instances, a special 537 # operation setting the context is needed. 538 539 if node._set_context == "set": 540 return compiler.ast.CallFunc(special_name(opconstant), [value, accessor]) 541 else: 542 return value 543 544 # Generate accesses via static objects and instances. 545 546 if node._attr_deduced: 547 548 # Static attributes may cause context replacement. 549 550 if node._access_type == "static": 551 if node._set_context == "set": 552 op = opattrcontext 553 elif node._set_context == "cond": 554 op = opattrcontextcond 555 else: 556 op = opattr 557 558 parent = self._generateValue(node._attr_deduced.parent) 559 560 # Non-static attributes. 561 562 else: 563 op = opattr 564 parent = None 565 566 # Handle unsupported operations. 567 568 if not op: 569 raise TranslateError("Storing of class attribute %r via self not permitted." % node.attrname) 570 571 # Define the arguments: accessor, attribute name and optional value. 572 573 args = [ 574 parent or accessor, 575 special_name(node.attrname) 576 ] 577 578 if expr: 579 args.append(expr) 580 581 # Append any context to be set. 582 583 if node._set_context and args[0] is not accessor: 584 args.append(accessor) 585 586 return compiler.ast.CallFunc(special_name(op), args) 587 588 # Positioned accesses are normal accesses via instances. 589 590 if node._access_type == "positioned": 591 args = [accessor, special_name(node.attrname)] 592 if expr: 593 args.append(expr) 594 return compiler.ast.CallFunc(special_name(opattr), args) 595 596 # With no usable deductions, generate a table-based access. 597 598 args = [accessor, special_name(node.attrname)] 599 if expr: 600 args.append(expr) 601 access = compiler.ast.CallFunc(special_name(opattrindexcontextcond), args) 602 603 # class.__class__ => __builtins__.type 604 605 if node.attrname == "__class__": 606 607 # storetemp(n, <accessor>) 608 # isclass(n) and __builtins__.type or <access> 609 610 temp = quoted_name(unit.temp_usage) 611 unit.temp_usage += 1 612 613 return compiler.ast.Stmt([ 614 compiler.ast.CallFunc(special_name("storetemp"), [temp, access]), 615 compiler.ast.Or([ 616 compiler.ast.And([ 617 compiler.ast.CallFunc( 618 special_name("isclass"), 619 [compiler.ast.CallFunc(special_name("loadtemp"), [temp])] 620 ), 621 module_attribute("__builtins__", "type") 622 ]), 623 access 624 ]) 625 ]) 626 627 # General accesses. 628 629 else: 630 return access 631 632 # Expressions. 633 634 def visitAdd(self, node): 635 return self._visitBinary(node) 636 637 def visitAnd(self, node): 638 return compiler.ast.And([self.dispatch(n) for n in node.nodes]) 639 640 def visitAssAttr(self, node, expr=None): 641 642 # Handle deletion. 643 644 if compiler.ast.is_deletion(node): 645 return compiler.ast.Stmt([]) 646 647 return self._visitAttr(node, expr) 648 649 def visitAssList(self, node, expr=None): 650 651 # Handle deletion. 652 653 if compiler.ast.is_deletion(compiler.ast.flatten_assignment(node)): 654 return compiler.ast.Stmt([]) 655 656 return compiler.ast.Stmt([ 657 self.dispatch(n, compiler.ast.CallFunc( 658 special_name("apply"), 659 [module_attribute("operator", "getitem"), expr, i] 660 )) 661 for (i, n) in enumerate(node.nodes) 662 ]) 663 664 def visitAssName(self, node, expr=None): 665 666 # Handle deletion. 667 668 if compiler.ast.is_deletion(node): 669 return compiler.ast.Stmt([]) 670 671 unit = self.get_unit() 672 673 # Generate appropriate name access operation. 674 # NOTE: Should generate guards for attribute usage operations. 675 676 scope = getattr(node, "_scope", None) 677 if not scope: 678 attr, scope, from_name = self.get_unit()._get_with_scope(node.name) 679 680 if scope == "constant": 681 return node 682 elif scope == "local": 683 684 # Function locals are stored using a function. 685 686 if isinstance(unit, Function): 687 return compiler.ast.CallFunc( 688 special_name("storelocal"), 689 [special_name(node.name), expr] 690 ) 691 692 # Class locals are class attribute references. 693 694 elif isinstance(unit, Class): 695 return compiler.ast.CallFunc( 696 special_name("storeattrcontext"), 697 [quoted_ref(unit), special_name(node.name), expr] 698 ) 699 700 # Module locals are module attribute references. 701 702 elif isinstance(unit, Module): 703 return compiler.ast.CallFunc( 704 special_name("storeattr"), 705 [quoted_ref(unit), special_name(node.name), expr] 706 ) 707 else: 708 raise TranslateError("Program unit has no local %r." % name) 709 710 elif scope == "global": 711 712 # Globals are references to module attributes. 713 714 return compiler.ast.CallFunc( 715 special_name("storeattr"), 716 [quoted_ref(self.get_module()), special_name(node.name), expr] 717 ) 718 719 elif scope == "builtin": 720 721 # Builtins are accessed via the __builtins__ module. 722 723 return compiler.ast.CallFunc( 724 special_name("storeattr"), 725 [special_name("__builtins__"), special_name(node.name), expr] 726 ) 727 728 else: 729 # NOTE: This may happen because a class attribute is optimised away. 730 return compiler.ast.CallFunc( 731 special_name("storeunknown"), 732 [special_name(node.name), expr] 733 ) 734 735 visitAssTuple = visitAssList 736 737 def visitBitand(self, node): 738 self._visitBitBinary(node) 739 740 def visitBitor(self, node): 741 self._visitBitBinary(node) 742 743 def visitBitxor(self, node): 744 self._visitBitBinary(node) 745 746 def visitCallFunc(self, node): 747 748 # Determine whether the invocation target is known. 749 750 args = [self.dispatch(node.node)] + [self.dispatch(arg) for arg in node.args] 751 752 target = node.node 753 754 # Attribute information is only known for specific accessors. 755 756 if isinstance(target, compiler.ast.AttributeAccessor): 757 attr = target._attr 758 else: 759 attr = None 760 761 if not attr or isinstance(attr, (Instance, UnresolvedName)): 762 op = "apply" 763 764 # Invocations with some knowledge available. 765 766 else: 767 context = attr.get_context() 768 value = attr.get_value() 769 770 # Class invocations. 771 772 if isinstance(value, Class): 773 op = "applyclass" 774 if value: 775 args[0] = quoted_ref(value) 776 else: 777 778 # Function invocations. 779 780 if context is ReplaceableContext: 781 op = "applyfunction" 782 783 # Method invocations via classes. 784 785 elif isinstance(context, Class) and value: 786 op = "applystaticmethod" 787 args.insert(0, quoted_ref(context)) 788 args[1] = quoted_ref(value) 789 790 # Plain method invocations. 791 792 elif context: 793 op = "applymethod" 794 795 # Unknown invocations. 796 797 else: 798 op = "apply" 799 800 return compiler.ast.CallFunc( 801 special_name(op), 802 args, 803 node.star_args and self.dispatch(node.star_args), 804 node.dstar_args and self.dispatch(node.dstar_args) 805 ) 806 807 def visitCompare(self, node): 808 nodes = [] 809 left = node.expr 810 for op_name, right in node.ops: 811 if op_name == "is": 812 nodes.append( 813 compiler.ast.CallFunc( 814 special_name("__is__"), 815 [self.dispatch(left), self.dispatch(right)] 816 ) 817 ) 818 elif op_name == "is not": 819 nodes.append( 820 compiler.ast.CallFunc( 821 special_name("__is_not__"), 822 [self.dispatch(left), self.dispatch(right)] 823 ) 824 ) 825 else: 826 nodes.append( 827 compiler.ast.CallFunc( 828 special_name("apply"), 829 [module_attribute("operator", operator_functions.get(op_name)), 830 self.dispatch(left), self.dispatch(right)] 831 ) 832 ) 833 left = right 834 return compiler.ast.And(nodes) 835 836 visitConst = NOP 837 838 def visitDict(self, node): 839 return compiler.ast.Dict([(self.dispatch(key), self.dispatch(value)) for (key, value) in node.items]) 840 841 def visitDiv(self, node): 842 return self._visitBinary(node) 843 844 def visitExec(self, node): 845 846 # NOTE: Return the statement for now. 847 848 return node 849 850 def visitFloorDiv(self, node): 851 return self._visitBinary(node) 852 853 def visitGetattr(self, node, expr=None): 854 return self._visitAttr(node, expr) 855 856 def visitGenExpr(self, node): 857 return compiler.ast.GenExpr(self.dispatch(node.code)) 858 859 def visitGenExprFor(self, node): 860 expr = self.dispatch(node.iter) 861 return compiler.ast.GenExprFor( 862 self.dispatch(node.assign, expr), # NOTE: Needs to dispatch to AssName/AssTuple/AssList with an expression. 863 expr, 864 [self.dispatch(n) for n in node.ifs] 865 ) 866 867 def visitGenExprIf(self, node): 868 return compiler.ast.GenExprIf(self.dispatch(node.test)) 869 870 def visitGenExprInner(self, node): 871 return compiler.ast.GenExprInner( 872 self.dispatch(node.expr), 873 [self.dispatch(n) for n in node.quals] 874 ) 875 876 def visitIfExp(self, node): 877 return compiler.ast.IfExp( 878 self.dispatch(node.then), 879 self.dispatch(node.test), 880 self.dispatch(node.else_) 881 ) 882 883 def visitInvert(self, node): 884 return self._visitUnary(node) 885 886 def visitKeyword(self, node): 887 return compiler.ast.Keyword( 888 node.name, 889 self.dispatch(node.expr) 890 ) 891 892 def visitLambda(self, node): 893 self.units.append(node.unit) 894 895 try: 896 return compiler.ast.Lambda( 897 node.argnames, 898 [self.dispatch(n) for n in node.defaults], 899 node.flags, 900 self.dispatch(node.code) 901 ) 902 finally: 903 self.units.pop() 904 905 def visitLeftShift(self, node): 906 return self._visitBinary(node) 907 908 def visitList(self, node, expr=None): 909 if expr: 910 return self.visitAssList(node, expr) 911 return compiler.ast.List([self.dispatch(n) for n in node.nodes]) 912 913 def visitListComp(self, node): 914 915 """ 916 Convert from... 917 918 [<expr> for <assign> in <list> [ for <assign> in <list> ]... [ if <test> ]... ] 919 920 ...to... 921 922 _out = [] 923 ... 924 """ 925 926 unit = self.get_unit() 927 temp = quoted_name(unit.temp_usage) 928 unit.temp_usage += 1 929 930 return compiler.ast.Stmt([ 931 # storetemp(_out, __builtins__.list()) 932 compiler.ast.CallFunc(special_name("storetemp"), [ 933 temp, 934 compiler.ast.CallFunc( 935 special_name("apply"), 936 [module_attribute("__builtins__", "list")] 937 ) 938 ]), 939 # ... 940 self.dispatch(node.quals[0], temp, node.expr, node.quals[1:]) 941 ]) 942 943 def visitListCompFor(self, node, out_temp, expr, quals): 944 945 """ 946 Convert from... 947 948 [<expr> for <assign> in <list> ...] 949 950 ...to... 951 952 _it = iter(<list>) 953 while True: 954 try: 955 <assign> = _it.next() 956 except StopIteration: 957 break 958 else: 959 ... 960 _out.append(<expr>) 961 """ 962 963 unit = self.get_unit() 964 temp = quoted_name(unit.temp_usage) 965 unit.temp_usage += 1 966 967 # Either generate more "for" or "if" constructs. 968 969 if node.ifs or quals: 970 nodes = node.ifs + quals 971 body = self.dispatch(nodes[0], out_temp, expr, nodes[1:]) 972 973 # Or generate the append statement. 974 975 else: 976 body = self._visitListCompExpr(out_temp, expr) 977 978 # Wrap the above body in the loop construct. 979 980 return compiler.ast.Stmt([ 981 # storetemp(_it, __builtins__.iter(<list>)) 982 compiler.ast.CallFunc(special_name("storetemp"), [ 983 temp, 984 compiler.ast.CallFunc( 985 special_name("apply"), 986 [module_attribute("__builtins__", "iter"), self.dispatch(node.list)] 987 ) 988 ]), 989 # while True: ... 990 compiler.ast.While( 991 special_name("True"), 992 # try: ... 993 compiler.ast.TryExcept( 994 compiler.ast.Stmt([ 995 # <assign> = ... 996 self.dispatch(node.assign, 997 # _it.next() 998 compiler.ast.CallFunc( 999 compiler.ast.CallFunc(special_name("loadattrindex"), [ 1000 compiler.ast.CallFunc(special_name("loadtemp"), [temp]), 1001 special_name("next") 1002 ]), 1003 [] 1004 ) 1005 ) 1006 ]), 1007 # except StopIteration: ... 1008 [(special_name("StopIteration"), None, compiler.ast.Stmt([compiler.ast.Break()]))], 1009 # else: ... 1010 body 1011 ), 1012 None 1013 ) 1014 ]) 1015 1016 def visitListCompIf(self, node, out_temp, expr, quals): 1017 1018 # Either generate more "for" or "if" constructs. 1019 1020 if quals: 1021 body = self.dispatch(quals[0], out_temp, expr, quals[1:]) 1022 1023 # Or generate the append statement. 1024 1025 else: 1026 body = self._visitListCompExpr(out_temp, expr) 1027 1028 return compiler.ast.If( 1029 [(self.dispatch(node.test), body)], 1030 None 1031 ) 1032 1033 def _visitListCompExpr(self, out_temp, expr): 1034 1035 "To the 'out_temp' object, append the result of 'expr'." 1036 1037 return compiler.ast.Stmt([ 1038 # _out.append(<expr>) 1039 compiler.ast.CallFunc( 1040 compiler.ast.CallFunc(special_name("loadattrindex"), [ 1041 compiler.ast.CallFunc(special_name("loadtemp"), [out_temp]), 1042 special_name("append") 1043 ]), 1044 [self.dispatch(expr)] 1045 ) 1046 ]) 1047 1048 def visitMod(self, node): 1049 return self._visitBinary(node) 1050 1051 def visitMul(self, node): 1052 return self._visitBinary(node) 1053 1054 def visitName(self, node, expr=None): 1055 if expr: 1056 return self.visitAssName(node, expr) 1057 1058 unit = self.get_unit() 1059 attr = node._attr 1060 scope = node._scope 1061 1062 # Generate appropriate name access operation. 1063 1064 if scope == "constant": 1065 return node 1066 1067 # Function locals are referenced normally. 1068 1069 elif scope == "local" and isinstance(unit, Function): 1070 return node 1071 1072 # Other attributes should already be resolved. 1073 1074 elif attr is not None and not isinstance(attr, Instance): 1075 if attr.is_constant(): 1076 return constant_attribute(attr.parent, node.name) 1077 else: 1078 return compiler.ast.CallFunc( 1079 special_name("loadattr"), 1080 [quoted_ref(attr.parent), special_name(node.name)] 1081 ) 1082 1083 # Function globals are referenced via the module. 1084 1085 elif scope == "global": 1086 return compiler.ast.CallFunc( 1087 special_name("loadattr"), 1088 [quoted_ref(self.get_module()), special_name(node.name)] 1089 ) 1090 1091 # NOTE: Unknown attributes may arise because a class attribute has been 1092 # NOTE: optimised away. 1093 1094 else: 1095 return compiler.ast.CallFunc( 1096 special_name("loadunknown"), 1097 [special_name(node.name)] 1098 ) 1099 1100 def visitNot(self, node): 1101 return compiler.ast.Not(self.dispatch(node.expr)) 1102 1103 def visitOr(self, node): 1104 return compiler.ast.Or([self.dispatch(n) for n in node.nodes]) 1105 1106 def visitPower(self, node): 1107 return self._visitBinary(node) 1108 1109 def visitRightShift(self, node): 1110 return self._visitBinary(node) 1111 1112 def visitSet(self, node): 1113 return compiler.ast.Set([self.dispatch(n) for n in node.nodes]) 1114 1115 def visitSlice(self, node, expr=None): 1116 return compiler.ast.CallFunc( 1117 special_name("apply"), 1118 [module_attribute("operator", expr and "setslice" or "getslice"), 1119 self.dispatch(node.expr), 1120 node.lower and self.dispatch(node.lower), 1121 node.upper and self.dispatch(node.upper)] 1122 + (expr and [expr] or []) 1123 ) 1124 1125 def visitSliceobj(self, node): 1126 return compiler.ast.CallFunc( 1127 special_name("apply"), 1128 [module_attribute("__builtins__", "slice")] 1129 + [self.dispatch(n) for n in node.nodes] 1130 ) 1131 1132 def visitSub(self, node): 1133 return self._visitBinary(node) 1134 1135 def visitSubscript(self, node, expr=None): 1136 return compiler.ast.CallFunc( 1137 special_name("apply"), 1138 [module_attribute("operator", expr and "setitem" or "getitem"), 1139 self.dispatch(node.expr), 1140 compiler.ast.Tuple([self.dispatch(sub) for sub in node.subs])] 1141 + (expr and [expr] or []) 1142 ) 1143 1144 def visitTuple(self, node, expr=None): 1145 if expr: 1146 return self.visitAssTuple(node, expr) 1147 return compiler.ast.Tuple([self.dispatch(n) for n in node.nodes]) 1148 1149 def visitUnaryAdd(self, node): 1150 return self._visitUnary(node) 1151 1152 def visitUnarySub(self, node): 1153 return self._visitUnary(node) 1154 1155 def visitWith(self, node): 1156 1157 """ 1158 Convert from... 1159 1160 with <expr> as <var>: 1161 ... 1162 1163 ...to... 1164 1165 _manager = <var> = <expr> # <var> may be absent 1166 _exit = _manager.__exit__ 1167 _manager.__enter__() 1168 try: 1169 ... 1170 except Exception, exc: 1171 if not _exit(exc.type, exc.value, exc.tb): 1172 raise 1173 else: 1174 _exit(None, None, None) 1175 """ 1176 1177 # NOTE: For now, not adding this exuberance to the output. 1178 1179 return node 1180 1181 # Convenience functions. 1182 1183 def convert(module, program, filename): 1184 stream = open(filename, "wb") 1185 try: 1186 source = ConvertedSource(module, program) 1187 source.to_stream(stream) 1188 finally: 1189 stream.close() 1190 1191 def translate(program, directory): 1192 if not exists(directory): 1193 os.mkdir(directory) 1194 1195 # NOTE: Add constants here. 1196 1197 for module in program.get_importer().get_modules(): 1198 convert(module, program, join(directory, "%s%spy" % (module.full_name(), extsep))) 1199 1200 # vim: tabstop=4 expandtab shiftwidth=4