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