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