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