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), [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 n = node.node 751 attr = n._attr 752 753 args = [self.dispatch(node.node)] + [self.dispatch(arg) for arg in node.args] 754 755 if not attr or isinstance(attr, Instance): 756 op = "apply" 757 758 # Invocations with some knowledge available. 759 760 else: 761 context = attr.get_context() 762 value = attr.get_value() 763 764 # Class invocations. 765 766 if isinstance(value, Class): 767 op = "applyclass" 768 if value: 769 args[0] = quoted_ref(value) 770 else: 771 772 # Function invocations. 773 774 if context is ReplaceableContext: 775 op = "applyfunction" 776 777 # Method invocations via classes. 778 779 elif isinstance(context, Class) and value: 780 op = "applystaticmethod" 781 args.insert(0, quoted_ref(context)) 782 args[1] = quoted_ref(value) 783 784 # Plain method invocations. 785 786 elif context: 787 op = "applymethod" 788 789 # Unknown invocations. 790 791 else: 792 op = "apply" 793 794 return compiler.ast.CallFunc( 795 special_name(op), 796 args, 797 node.star_args and self.dispatch(node.star_args), 798 node.dstar_args and self.dispatch(node.dstar_args) 799 ) 800 801 def visitCompare(self, node): 802 nodes = [] 803 left = node.expr 804 for op_name, right in node.ops: 805 if op_name == "is": 806 nodes.append( 807 compiler.ast.CallFunc( 808 special_name("__is__"), 809 [self.dispatch(left), self.dispatch(right)] 810 ) 811 ) 812 elif op_name == "is not": 813 nodes.append( 814 compiler.ast.CallFunc( 815 special_name("__is_not__"), 816 [self.dispatch(left), self.dispatch(right)] 817 ) 818 ) 819 else: 820 nodes.append( 821 compiler.ast.CallFunc( 822 special_name("apply"), 823 [module_attribute("operator", operator_functions.get(op_name)), 824 self.dispatch(left), self.dispatch(right)] 825 ) 826 ) 827 left = right 828 return compiler.ast.And(nodes) 829 830 visitConst = NOP 831 832 def visitDict(self, node): 833 return compiler.ast.Dict([(self.dispatch(key), self.dispatch(value)) for (key, value) in node.items]) 834 835 def visitDiv(self, node): 836 return self._visitBinary(node) 837 838 def visitFloorDiv(self, node): 839 return self._visitBinary(node) 840 841 def visitGetattr(self, node, expr=None): 842 return self._visitAttr(node, expr) 843 844 def visitGenExpr(self, node): 845 return compiler.ast.GenExpr(self.dispatch(node.code)) 846 847 def visitGenExprFor(self, node): 848 expr = self.dispatch(node.iter) 849 return compiler.ast.GenExprFor( 850 self.dispatch(node.assign, expr), # NOTE: Needs to dispatch to AssName/AssTuple/AssList with an expression. 851 expr, 852 [self.dispatch(n) for n in node.ifs] 853 ) 854 855 def visitGenExprIf(self, node): 856 return compiler.ast.GenExprIf(self.dispatch(node.test)) 857 858 def visitGenExprInner(self, node): 859 return compiler.ast.GenExprInner( 860 self.dispatch(node.expr), 861 [self.dispatch(n) for n in node.quals] 862 ) 863 864 def visitIfExp(self, node): 865 return compiler.ast.IfExp( 866 self.dispatch(node.then), 867 self.dispatch(node.test), 868 self.dispatch(node.else_) 869 ) 870 871 def visitInvert(self, node): 872 return self._visitUnary(node) 873 874 def visitKeyword(self, node): 875 return compiler.ast.Keyword( 876 node.name, 877 self.dispatch(node.expr) 878 ) 879 880 def visitLambda(self, node): 881 self.units.append(node.unit) 882 883 try: 884 return compiler.ast.Lambda( 885 node.argnames, 886 [self.dispatch(n) for n in node.defaults], 887 node.flags, 888 self.dispatch(node.code) 889 ) 890 finally: 891 self.units.pop() 892 893 def visitLeftShift(self, node): 894 return self._visitBinary(node) 895 896 def visitList(self, node, expr=None): 897 if expr: 898 return self.visitAssList(node, expr) 899 return compiler.ast.List([self.dispatch(n) for n in node.nodes]) 900 901 def visitListComp(self, node): 902 903 """ 904 Convert from... 905 906 [<expr> for <assign> in <list> [ for <assign> in <list> ]... [ if <test> ]... ] 907 908 ...to... 909 910 _out = [] 911 ... 912 """ 913 914 unit = self.get_unit() 915 temp = quoted_name(unit.temp_usage) 916 unit.temp_usage += 1 917 918 return compiler.ast.Stmt([ 919 # storetemp(_out, __builtins__.list()) 920 compiler.ast.CallFunc(special_name("storetemp"), [ 921 temp, 922 compiler.ast.CallFunc( 923 special_name("apply"), 924 [module_attribute("__builtins__", "list")] 925 ) 926 ]), 927 # ... 928 self.dispatch(node.quals[0], temp, node.expr, node.quals[1:]) 929 ]) 930 931 def visitListCompFor(self, node, out_temp, expr, quals): 932 933 """ 934 Convert from... 935 936 [<expr> for <assign> in <list> ...] 937 938 ...to... 939 940 _it = iter(<list>) 941 while True: 942 try: 943 <assign> = _it.next() 944 except StopIteration: 945 break 946 else: 947 ... 948 _out.append(<expr>) 949 """ 950 951 unit = self.get_unit() 952 temp = quoted_name(unit.temp_usage) 953 unit.temp_usage += 1 954 955 # Either generate more "for" or "if" constructs. 956 957 if node.ifs or quals: 958 nodes = node.ifs + quals 959 body = self.dispatch(nodes[0], out_temp, expr, nodes[1:]) 960 961 # Or generate the append statement. 962 963 else: 964 body = self._visitListCompExpr(out_temp, expr) 965 966 # Wrap the above body in the loop construct. 967 968 return compiler.ast.Stmt([ 969 # storetemp(_it, __builtins__.iter(<list>)) 970 compiler.ast.CallFunc(special_name("storetemp"), [ 971 temp, 972 compiler.ast.CallFunc( 973 special_name("apply"), 974 [module_attribute("__builtins__", "iter"), self.dispatch(node.list)] 975 ) 976 ]), 977 # while True: ... 978 compiler.ast.While( 979 special_name("True"), 980 # try: ... 981 compiler.ast.TryExcept( 982 compiler.ast.Stmt([ 983 # <assign> = ... 984 self.dispatch(node.assign, 985 # _it.next() 986 compiler.ast.CallFunc( 987 compiler.ast.CallFunc(special_name("loadattrindex"), [ 988 compiler.ast.CallFunc(special_name("loadtemp"), [temp]), 989 special_name("next") 990 ]), 991 [] 992 ) 993 ) 994 ]), 995 # except StopIteration: ... 996 [(special_name("StopIteration"), None, compiler.ast.Stmt([compiler.ast.Break()]))], 997 # else: ... 998 body 999 ), 1000 None 1001 ) 1002 ]) 1003 1004 def visitListCompIf(self, node, out_temp, expr, quals): 1005 1006 # Either generate more "for" or "if" constructs. 1007 1008 if quals: 1009 body = self.dispatch(quals[0], out_temp, expr, quals[1:]) 1010 1011 # Or generate the append statement. 1012 1013 else: 1014 body = self._visitListCompExpr(out_temp, expr) 1015 1016 return compiler.ast.If( 1017 [(self.dispatch(node.test), body)], 1018 None 1019 ) 1020 1021 def _visitListCompExpr(self, out_temp, expr): 1022 1023 "To the 'out_temp' object, append the result of 'expr'." 1024 1025 return compiler.ast.Stmt([ 1026 # _out.append(<expr>) 1027 compiler.ast.CallFunc( 1028 compiler.ast.CallFunc(special_name("loadattrindex"), [ 1029 compiler.ast.CallFunc(special_name("loadtemp"), [out_temp]), 1030 special_name("append") 1031 ]), 1032 [self.dispatch(expr)] 1033 ) 1034 ]) 1035 1036 def visitMod(self, node): 1037 return self._visitBinary(node) 1038 1039 def visitMul(self, node): 1040 return self._visitBinary(node) 1041 1042 def visitName(self, node, expr=None): 1043 if expr: 1044 return self.visitAssName(node, expr) 1045 1046 unit = self.get_unit() 1047 attr = node._attr 1048 scope = node._scope 1049 1050 # Generate appropriate name access operation. 1051 1052 if scope == "constant": 1053 return node 1054 1055 # Function locals are referenced normally. 1056 1057 elif scope == "local" and isinstance(unit, Function): 1058 return node 1059 1060 # Other attributes should already be resolved. 1061 1062 elif attr is not None and not isinstance(attr, Instance): 1063 if attr.is_constant(): 1064 return constant_attribute(attr.parent, node.name) 1065 else: 1066 return compiler.ast.CallFunc( 1067 special_name("loadattr"), 1068 [quoted_ref(attr.parent), special_name(node.name)] 1069 ) 1070 1071 # Function globals are referenced via the module. 1072 1073 elif scope == "global": 1074 return compiler.ast.CallFunc( 1075 special_name("loadattr"), 1076 [quoted_ref(self.get_module()), special_name(node.name)] 1077 ) 1078 1079 # NOTE: Unknown attributes may arise because a class attribute has been 1080 # NOTE: optimised away. 1081 1082 else: 1083 return compiler.ast.CallFunc( 1084 special_name("loadunknown"), 1085 [special_name(node.name)] 1086 ) 1087 1088 def visitNot(self, node): 1089 return compiler.ast.Not(self.dispatch(node.expr)) 1090 1091 def visitOr(self, node): 1092 return compiler.ast.Or([self.dispatch(n) for n in node.nodes]) 1093 1094 def visitPower(self, node): 1095 return self._visitBinary(node) 1096 1097 def visitRightShift(self, node): 1098 return self._visitBinary(node) 1099 1100 def visitSet(self, node): 1101 return compiler.ast.Set([self.dispatch(n) for n in node.nodes]) 1102 1103 def visitSlice(self, node, expr=None): 1104 return compiler.ast.CallFunc( 1105 special_name("apply"), 1106 [module_attribute("operator", expr and "setslice" or "getslice"), 1107 self.dispatch(node.expr), 1108 node.lower and self.dispatch(node.lower), 1109 node.upper and self.dispatch(node.upper)] 1110 + (expr and [expr] or []) 1111 ) 1112 1113 def visitSliceobj(self, node): 1114 return compiler.ast.CallFunc( 1115 special_name("apply"), 1116 [module_attribute("__builtins__", "slice")] 1117 + [self.dispatch(n) for n in node.nodes] 1118 ) 1119 1120 def visitSub(self, node): 1121 return self._visitBinary(node) 1122 1123 def visitSubscript(self, node, expr=None): 1124 return compiler.ast.CallFunc( 1125 special_name("apply"), 1126 [module_attribute("operator", expr and "setitem" or "getitem"), 1127 self.dispatch(node.expr), 1128 compiler.ast.Tuple([self.dispatch(sub) for sub in node.subs])] 1129 + (expr and [expr] or []) 1130 ) 1131 1132 def visitTuple(self, node, expr=None): 1133 if expr: 1134 return self.visitAssTuple(node, expr) 1135 return compiler.ast.Tuple([self.dispatch(n) for n in node.nodes]) 1136 1137 def visitUnaryAdd(self, node): 1138 return self._visitUnary(node) 1139 1140 def visitUnarySub(self, node): 1141 return self._visitUnary(node) 1142 1143 # Convenience functions. 1144 1145 def convert(module, program, filename): 1146 stream = open(filename, "wb") 1147 try: 1148 source = ConvertedSource(module, program) 1149 source.to_stream(stream) 1150 finally: 1151 stream.close() 1152 1153 def translate(program, directory): 1154 if not exists(directory): 1155 os.mkdir(directory) 1156 1157 # NOTE: Add constants here. 1158 1159 for module in program.get_importer().get_modules(): 1160 convert(module, program, join(directory, "%s%spy" % (module.full_name(), extsep))) 1161 1162 # vim: tabstop=4 expandtab shiftwidth=4