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 if not self.processing_definition(node): 391 392 # Generate rebindings of functions where multiple definitions 393 # exist within a scope. Also generate dynamic function object 394 # initialisation. 395 396 fn = node.unit 397 if fn.is_dynamic(): 398 ref = compiler.ast.CallFunc( 399 special_name("makedynamic"), 400 [quoted_ref(fn)] + [self.dispatch(n) for n in fn.defaults] 401 ) 402 elif fn.defaults: 403 ref = compiler.ast.CallFunc( 404 special_name("setdefaults"), 405 [quoted_ref(fn)] + [self.dispatch(n) for n in fn.defaults] 406 ) 407 if fn.name == fn.original_name: 408 return ref 409 elif fn.name == fn.original_name: 410 return compiler.ast.Stmt([]) 411 else: 412 ref = quoted_ref(fn) 413 414 return self.store_value(fn.parent, "local", fn.original_name, ref) 415 416 # Where this function is being processed, visit the definition in its 417 # entirety. 418 419 else: 420 self.units.append(node.unit) 421 try: 422 return self._visitFunctionDefinition(node) 423 finally: 424 self.units.pop() 425 426 def _visitFunctionDefinition(self, node): 427 fn = node.unit 428 429 # localnames(name, ...) 430 # globalnames(name, ...) 431 432 localnames = fn.all_locals() and [ 433 compiler.ast.CallFunc( 434 special_name("localnames"), 435 [special_name(name) for name in fn.all_locals().keys()] 436 ) 437 ] or [] 438 439 globalnames = fn.globals and [ 440 compiler.ast.CallFunc( 441 special_name("globalnames"), 442 [special_name(name) for name in fn.globals] 443 ) 444 ] or [] 445 446 # Process any local class or function definitions. 447 448 current = self.current_definition 449 definitions = self.process_definitions(node) 450 self.current_definition = current 451 452 # NOTE: Any required defaults should be copied into the local namespace 453 # NOTE: using the __context__ reference to the instance of the function. 454 455 # NOTE: Should generate guards for attribute usage operations. 456 457 code = self.dispatch(node.code) 458 459 return compiler.ast.Function(node.decorators, node.name, node.argnames, node.defaults, node.flags, node.doc, 460 compiler.ast.Stmt(localnames + globalnames + definitions + code.nodes)) 461 462 visitGlobal = NOP 463 464 def visitIf(self, node): 465 return compiler.ast.If( 466 [(self.dispatch(compare), self.dispatch(stmt)) for (compare, stmt) in node.tests], 467 node.else_ and self.dispatch(node.else_) 468 ) 469 470 def visitImport(self, node): 471 472 # Generate __main__ function calls for each step in the imported module 473 # hierarchy. 474 475 statements = [] 476 477 for name, alias in node.names: 478 for modname in self.module.get_module_paths(name): 479 statements.append( 480 compiler.ast.CallFunc(compiler.ast.Getattr(modname, "__main__"), []) 481 ) 482 483 statements.append( 484 compiler.ast.CallFunc( 485 special_name("storelocal"), 486 [special_name(alias or name.split(".")[0]), 487 compiler.ast.CallFunc( 488 special_name("static"), 489 [special_name(name)] 490 ) 491 ]) 492 ) 493 494 return compiler.ast.Stmt(statements) 495 496 def visitPass(self, node): 497 if not isinstance(self.get_unit(), Class): 498 return compiler.ast.Pass() 499 else: 500 return compiler.ast.Stmt([]) 501 502 def visitPrint(self, node): 503 return compiler.ast.CallFunc( 504 special_name("apply"), 505 [module_attribute("__builtins__", "_print"), 506 node.dest and self.dispatch(node.dest) or special_name("None")] 507 + [self.dispatch(n) for n in node.nodes] 508 ) 509 510 def visitPrintnl(self, node): 511 return compiler.ast.CallFunc( 512 special_name("apply"), 513 [module_attribute("__builtins__", "_println"), 514 node.dest and self.dispatch(node.dest) or special_name("None")] 515 + [self.dispatch(n) for n in node.nodes] 516 ) 517 518 def visitRaise(self, node): 519 return compiler.ast.Raise( 520 node.expr1 and self.dispatch(node.expr1), 521 node.expr2 and self.dispatch(node.expr2), 522 node.expr3 and self.dispatch(node.expr3) 523 ) 524 525 def visitReturn(self, node): 526 return compiler.ast.Return(self.dispatch(node.value)) 527 528 def visitStmt(self, node): 529 return compiler.ast.Stmt([self.dispatch(n) for n in node.nodes]) 530 531 def visitTryExcept(self, node): 532 # NOTE: Need to dispatch to the assignment with the exception. 533 return compiler.ast.TryExcept( 534 self.dispatch(node.body), 535 [(spec and self.dispatch(spec), assign and self.dispatch(assign), self.dispatch(statement)) 536 for spec, assign, statement in node.handlers], 537 node.else_ and self.dispatch(node.else_) 538 ) 539 540 def visitTryFinally(self, node): 541 return compiler.ast.TryFinally( 542 self.dispatch(node.body), 543 self.dispatch(node.final) 544 ) 545 546 def visitWhile(self, node): 547 return compiler.ast.While( 548 self.dispatch(node.test), 549 self.dispatch(node.body), 550 node.else_ and self.dispatch(node.else_) 551 ) 552 553 def visitYield(self, node): 554 return compiler.ast.Yield(self.dispatch(node.value)) 555 556 # Expression-related helper methods. 557 558 def _visitBitBinary(self, node): 559 op_name = operator_functions[node.__class__.__name__] 560 last = self.dispatch(node.nodes[0]) 561 562 for n in node.nodes[1:]: 563 last = compiler.ast.CallFunc( 564 special_name("apply"), 565 [module_attribute("operator", op_name), last, self.dispatch(n)] 566 ) 567 568 return last 569 570 def _visitBinary(self, node): 571 op_name = operator_functions[node.__class__.__name__] 572 573 return compiler.ast.CallFunc( 574 special_name("apply"), 575 [module_attribute("operator", op_name), 576 self.dispatch(node.left), self.dispatch(node.right)] 577 ) 578 579 def _visitUnary(self, node): 580 op_name = operator_functions[node.__class__.__name__] 581 582 return compiler.ast.CallFunc( 583 special_name("apply"), 584 [module_attribute("operator", op_name), self.dispatch(node.expr)] 585 ) 586 587 def _generateValue(self, value): 588 589 # Literal constants. 590 591 if isinstance(value, Const): 592 return compiler.ast.Const(value.get_value()) 593 594 # Other constant structures. 595 596 if isinstance(value, Constant): 597 return quoted_ref(value) 598 599 return None 600 601 def _visitAttr(self, node, expr=None): 602 unit = self.get_unit() 603 604 # Choose the appropriate special functions. 605 606 (opattrcontext, opattrcontextcond, opattr, opattrindexcontextcond, opconstant) = \ 607 expr and assattr_functions or getattr_functions 608 609 accessor = self.dispatch(node.expr) 610 611 # Generate already-deduced accesses. 612 613 if node._access_type == "constant": 614 value = self._generateValue(node._value_deduced) 615 616 # Where constant attributes are accessed via instances, a special 617 # operation setting the context is needed. 618 619 if node._set_context == "set": 620 return compiler.ast.CallFunc(special_name(opconstant), [value, accessor]) 621 else: 622 return value 623 624 # Generate accesses via static objects and instances. 625 626 if node._attr_deduced: 627 628 # Static attributes may cause context replacement. 629 630 if node._access_type == "static": 631 if node._set_context == "set": 632 op = opattrcontext 633 elif node._set_context == "cond": 634 op = opattrcontextcond 635 else: 636 op = opattr 637 638 parent = self._generateValue(node._attr_deduced.parent) 639 640 # Non-static attributes. 641 642 else: 643 op = opattr 644 parent = None 645 646 # Handle unsupported operations. 647 648 if not op: 649 raise TranslateError("Storing of class attribute %r via self not permitted." % node.attrname) 650 651 # Define the arguments: accessor, attribute name and optional value. 652 653 args = [ 654 parent or accessor, 655 special_name(node.attrname) 656 ] 657 658 if expr: 659 args.append(expr) 660 661 # Append any context to be set. 662 663 if node._set_context and args[0] is not accessor: 664 args.append(accessor) 665 666 return compiler.ast.CallFunc(special_name(op), args) 667 668 # Positioned accesses are normal accesses via instances. 669 670 if node._access_type == "positioned": 671 args = [accessor, special_name(node.attrname)] 672 if expr: 673 args.append(expr) 674 return compiler.ast.CallFunc(special_name(opattr), args) 675 676 # With no usable deductions, generate a table-based access. 677 678 args = [accessor, special_name(node.attrname)] 679 if expr: 680 args.append(expr) 681 access = compiler.ast.CallFunc(special_name(opattrindexcontextcond), args) 682 683 # class.__class__ => __builtins__.type 684 685 if node.attrname == "__class__": 686 687 # storetemp(n, <accessor>) 688 # isclass(n) and __builtins__.type or <access> 689 690 temp = quoted_name(unit.temp_usage) 691 unit.temp_usage += 1 692 693 return compiler.ast.Stmt([ 694 compiler.ast.CallFunc(special_name("storetemp"), [temp, access]), 695 compiler.ast.Or([ 696 compiler.ast.And([ 697 compiler.ast.CallFunc( 698 special_name("isclass"), 699 [compiler.ast.CallFunc(special_name("loadtemp"), [temp])] 700 ), 701 module_attribute("__builtins__", "type") 702 ]), 703 access 704 ]) 705 ]) 706 707 # General accesses. 708 709 else: 710 return access 711 712 # Expressions. 713 714 def visitAdd(self, node): 715 return self._visitBinary(node) 716 717 def visitAnd(self, node): 718 return compiler.ast.And([self.dispatch(n) for n in node.nodes]) 719 720 def visitAssAttr(self, node, expr=None): 721 722 # Handle deletion. 723 724 if compiler.ast.is_deletion(node): 725 return compiler.ast.Stmt([]) 726 727 return self._visitAttr(node, expr) 728 729 def visitAssList(self, node, expr=None): 730 731 # Handle deletion. 732 733 if compiler.ast.is_deletion(compiler.ast.flatten_assignment(node)): 734 return compiler.ast.Stmt([]) 735 736 return compiler.ast.Stmt([ 737 self.dispatch(n, compiler.ast.CallFunc( 738 special_name("apply"), 739 [module_attribute("operator", "getitem"), expr, i] 740 )) 741 for (i, n) in enumerate(node.nodes) 742 ]) 743 744 def visitAssName(self, node, expr=None): 745 746 # Handle deletion. 747 748 if compiler.ast.is_deletion(node): 749 return compiler.ast.Stmt([]) 750 751 unit = self.get_unit() 752 753 # Generate appropriate name access operation. 754 # NOTE: Should generate guards for attribute usage operations. 755 756 scope = getattr(node, "_scope", None) 757 if not scope: 758 attr, scope, from_name = self.get_unit()._get_with_scope(node.name) 759 760 if scope == "constant": 761 return node 762 else: 763 return self.store_value(unit, scope, node.name, expr) 764 765 visitAssTuple = visitAssList 766 767 def visitBitand(self, node): 768 self._visitBitBinary(node) 769 770 def visitBitor(self, node): 771 self._visitBitBinary(node) 772 773 def visitBitxor(self, node): 774 self._visitBitBinary(node) 775 776 def visitCallFunc(self, node): 777 778 # Determine whether the invocation target is known. 779 780 args = [self.dispatch(node.node)] + [self.dispatch(arg) for arg in node.args] 781 782 target = node.node 783 784 # Attribute information is only known for specific accessors. 785 786 if isinstance(target, compiler.ast.AttributeAccessor): 787 attr = target._attr 788 else: 789 attr = None 790 791 if not attr or isinstance(attr, (Instance, UnresolvedName)): 792 op = "apply" 793 794 # Invocations with some knowledge available. 795 796 else: 797 context = attr.get_context() 798 value = attr.get_value() 799 800 # Class invocations. 801 802 if isinstance(value, Class): 803 op = "applyclass" 804 if value: 805 args[0] = quoted_ref(value) 806 else: 807 808 # Function invocations. 809 810 if context is ReplaceableContext: 811 op = "applyfunction" 812 813 # Method invocations via classes. 814 815 elif isinstance(context, Class) and value: 816 op = "applystaticmethod" 817 args[0] = quoted_ref(value) 818 args.insert(1, quoted_ref(context)) 819 820 # Plain method invocations. 821 822 elif context: 823 op = "applymethod" 824 825 # Unknown invocations. 826 827 else: 828 op = "apply" 829 830 return compiler.ast.CallFunc( 831 special_name(op), 832 args, 833 node.star_args and self.dispatch(node.star_args), 834 node.dstar_args and self.dispatch(node.dstar_args) 835 ) 836 837 def visitCompare(self, node): 838 nodes = [] 839 left = node.expr 840 for op_name, right in node.ops: 841 if op_name == "is": 842 nodes.append( 843 compiler.ast.CallFunc( 844 special_name("__is__"), 845 [self.dispatch(left), self.dispatch(right)] 846 ) 847 ) 848 elif op_name == "is not": 849 nodes.append( 850 compiler.ast.CallFunc( 851 special_name("__is_not__"), 852 [self.dispatch(left), self.dispatch(right)] 853 ) 854 ) 855 else: 856 nodes.append( 857 compiler.ast.CallFunc( 858 special_name("apply"), 859 [module_attribute("operator", operator_functions.get(op_name)), 860 self.dispatch(left), self.dispatch(right)] 861 ) 862 ) 863 left = right 864 return compiler.ast.And(nodes) 865 866 visitConst = NOP 867 868 def visitDict(self, node): 869 return compiler.ast.Dict([(self.dispatch(key), self.dispatch(value)) for (key, value) in node.items]) 870 871 def visitDiv(self, node): 872 return self._visitBinary(node) 873 874 def visitExec(self, node): 875 876 # NOTE: Return the statement for now. 877 878 return node 879 880 def visitFloorDiv(self, node): 881 return self._visitBinary(node) 882 883 def visitGetattr(self, node, expr=None): 884 return self._visitAttr(node, expr) 885 886 def visitGenExpr(self, node): 887 return compiler.ast.GenExpr(self.dispatch(node.code)) 888 889 def visitGenExprFor(self, node): 890 expr = self.dispatch(node.iter) 891 return compiler.ast.GenExprFor( 892 self.dispatch(node.assign, expr), # NOTE: Needs to dispatch to AssName/AssTuple/AssList with an expression. 893 expr, 894 [self.dispatch(n) for n in node.ifs] 895 ) 896 897 def visitGenExprIf(self, node): 898 return compiler.ast.GenExprIf(self.dispatch(node.test)) 899 900 def visitGenExprInner(self, node): 901 return compiler.ast.GenExprInner( 902 self.dispatch(node.expr), 903 [self.dispatch(n) for n in node.quals] 904 ) 905 906 def visitIfExp(self, node): 907 return compiler.ast.IfExp( 908 self.dispatch(node.then), 909 self.dispatch(node.test), 910 self.dispatch(node.else_) 911 ) 912 913 def visitInvert(self, node): 914 return self._visitUnary(node) 915 916 def visitKeyword(self, node): 917 return compiler.ast.Keyword( 918 node.name, 919 self.dispatch(node.expr) 920 ) 921 922 def visitLambda(self, node): 923 self.units.append(node.unit) 924 925 # NOTE: Need to initialise any defaults. Lambdas should probably be 926 # NOTE: expanded to be "real" function definitions. 927 928 try: 929 return compiler.ast.Lambda( 930 node.argnames, 931 [self.dispatch(n) for n in node.defaults], 932 node.flags, 933 self.dispatch(node.code) 934 ) 935 finally: 936 self.units.pop() 937 938 def visitLeftShift(self, node): 939 return self._visitBinary(node) 940 941 def visitList(self, node, expr=None): 942 if expr: 943 return self.visitAssList(node, expr) 944 return compiler.ast.List([self.dispatch(n) for n in node.nodes]) 945 946 def visitListComp(self, node): 947 948 """ 949 Convert from... 950 951 [<expr> for <assign> in <list> [ for <assign> in <list> ]... [ if <test> ]... ] 952 953 ...to... 954 955 _out = [] 956 ... 957 """ 958 959 unit = self.get_unit() 960 temp = quoted_name(unit.temp_usage) 961 unit.temp_usage += 1 962 963 return compiler.ast.Stmt([ 964 # storetemp(_out, __builtins__.list()) 965 compiler.ast.CallFunc(special_name("storetemp"), [ 966 temp, 967 compiler.ast.CallFunc( 968 special_name("apply"), 969 [module_attribute("__builtins__", "list")] 970 ) 971 ]), 972 # ... 973 self.dispatch(node.quals[0], temp, node.expr, node.quals[1:]) 974 ]) 975 976 def visitListCompFor(self, node, out_temp, expr, quals): 977 978 """ 979 Convert from... 980 981 [<expr> for <assign> in <list> ...] 982 983 ...to... 984 985 _it = iter(<list>) 986 while True: 987 try: 988 <assign> = _it.next() 989 except StopIteration: 990 break 991 else: 992 ... 993 _out.append(<expr>) 994 """ 995 996 unit = self.get_unit() 997 temp = quoted_name(unit.temp_usage) 998 unit.temp_usage += 1 999 1000 # Either generate more "for" or "if" constructs. 1001 1002 if node.ifs or quals: 1003 nodes = node.ifs + quals 1004 body = self.dispatch(nodes[0], out_temp, expr, nodes[1:]) 1005 1006 # Or generate the append statement. 1007 1008 else: 1009 body = self._visitListCompExpr(out_temp, expr) 1010 1011 # Wrap the above body in the loop construct. 1012 1013 return compiler.ast.Stmt([ 1014 # storetemp(_it, __builtins__.iter(<list>)) 1015 compiler.ast.CallFunc(special_name("storetemp"), [ 1016 temp, 1017 compiler.ast.CallFunc( 1018 special_name("apply"), 1019 [module_attribute("__builtins__", "iter"), self.dispatch(node.list)] 1020 ) 1021 ]), 1022 # while True: ... 1023 compiler.ast.While( 1024 special_name("True"), 1025 # try: ... 1026 compiler.ast.TryExcept( 1027 compiler.ast.Stmt([ 1028 # <assign> = ... 1029 self.dispatch(node.assign, 1030 # _it.next() 1031 compiler.ast.CallFunc( 1032 compiler.ast.CallFunc(special_name("loadattrindex"), [ 1033 compiler.ast.CallFunc(special_name("loadtemp"), [temp]), 1034 special_name("next") 1035 ]), 1036 [] 1037 ) 1038 ) 1039 ]), 1040 # except StopIteration: ... 1041 [(special_name("StopIteration"), None, compiler.ast.Stmt([compiler.ast.Break()]))], 1042 # else: ... 1043 body 1044 ), 1045 None 1046 ) 1047 ]) 1048 1049 def visitListCompIf(self, node, out_temp, expr, quals): 1050 1051 # Either generate more "for" or "if" constructs. 1052 1053 if quals: 1054 body = self.dispatch(quals[0], out_temp, expr, quals[1:]) 1055 1056 # Or generate the append statement. 1057 1058 else: 1059 body = self._visitListCompExpr(out_temp, expr) 1060 1061 return compiler.ast.If( 1062 [(self.dispatch(node.test), body)], 1063 None 1064 ) 1065 1066 def _visitListCompExpr(self, out_temp, expr): 1067 1068 "To the 'out_temp' object, append the result of 'expr'." 1069 1070 return compiler.ast.Stmt([ 1071 # _out.append(<expr>) 1072 compiler.ast.CallFunc( 1073 compiler.ast.CallFunc(special_name("loadattrindex"), [ 1074 compiler.ast.CallFunc(special_name("loadtemp"), [out_temp]), 1075 special_name("append") 1076 ]), 1077 [self.dispatch(expr)] 1078 ) 1079 ]) 1080 1081 def visitMod(self, node): 1082 return self._visitBinary(node) 1083 1084 def visitMul(self, node): 1085 return self._visitBinary(node) 1086 1087 def visitName(self, node, expr=None): 1088 if expr: 1089 return self.visitAssName(node, expr) 1090 1091 unit = self.get_unit() 1092 attr = node._attr 1093 scope = node._scope 1094 1095 # Generate appropriate name access operation. 1096 1097 if scope == "constant": 1098 return node 1099 1100 # Function locals are referenced normally. 1101 1102 elif scope == "local" and isinstance(unit, Function): 1103 return node 1104 1105 # Other attributes should already be resolved. 1106 1107 elif attr is not None and not isinstance(attr, Instance): 1108 if attr.is_constant(): 1109 return constant_attribute(attr.parent, node.name) 1110 else: 1111 return compiler.ast.CallFunc( 1112 special_name("loadattr"), 1113 [quoted_ref(attr.parent), special_name(node.name)] 1114 ) 1115 1116 # Function globals are referenced via the module. 1117 1118 elif scope == "global": 1119 return compiler.ast.CallFunc( 1120 special_name("loadattr"), 1121 [quoted_ref(self.get_module()), special_name(node.name)] 1122 ) 1123 1124 # NOTE: Unknown attributes may arise because a class attribute has been 1125 # NOTE: optimised away. 1126 1127 else: 1128 return compiler.ast.CallFunc( 1129 special_name("loadunknown"), 1130 [special_name(node.name)] 1131 ) 1132 1133 def visitNot(self, node): 1134 return compiler.ast.Not(self.dispatch(node.expr)) 1135 1136 def visitOr(self, node): 1137 return compiler.ast.Or([self.dispatch(n) for n in node.nodes]) 1138 1139 def visitPower(self, node): 1140 return self._visitBinary(node) 1141 1142 def visitRightShift(self, node): 1143 return self._visitBinary(node) 1144 1145 def visitSet(self, node): 1146 return compiler.ast.Set([self.dispatch(n) for n in node.nodes]) 1147 1148 def visitSlice(self, node, expr=None): 1149 return compiler.ast.CallFunc( 1150 special_name("apply"), 1151 [module_attribute("operator", expr and "setslice" or "getslice"), 1152 self.dispatch(node.expr), 1153 node.lower and self.dispatch(node.lower), 1154 node.upper and self.dispatch(node.upper)] 1155 + (expr and [expr] or []) 1156 ) 1157 1158 def visitSliceobj(self, node): 1159 return compiler.ast.CallFunc( 1160 special_name("apply"), 1161 [module_attribute("__builtins__", "slice")] 1162 + [self.dispatch(n) for n in node.nodes] 1163 ) 1164 1165 def visitSub(self, node): 1166 return self._visitBinary(node) 1167 1168 def visitSubscript(self, node, expr=None): 1169 return compiler.ast.CallFunc( 1170 special_name("apply"), 1171 [module_attribute("operator", expr and "setitem" or "getitem"), 1172 self.dispatch(node.expr), 1173 compiler.ast.Tuple([self.dispatch(sub) for sub in node.subs])] 1174 + (expr and [expr] or []) 1175 ) 1176 1177 def visitTuple(self, node, expr=None): 1178 if expr: 1179 return self.visitAssTuple(node, expr) 1180 return compiler.ast.Tuple([self.dispatch(n) for n in node.nodes]) 1181 1182 def visitUnaryAdd(self, node): 1183 return self._visitUnary(node) 1184 1185 def visitUnarySub(self, node): 1186 return self._visitUnary(node) 1187 1188 def visitWith(self, node): 1189 1190 """ 1191 Convert from... 1192 1193 with <expr> as <var>: 1194 ... 1195 1196 ...to... 1197 1198 _manager = <var> = <expr> # <var> may be absent 1199 _exit = _manager.__exit__ 1200 _manager.__enter__() 1201 try: 1202 ... 1203 except Exception, exc: 1204 if not _exit(exc.type, exc.value, exc.tb): 1205 raise 1206 else: 1207 _exit(None, None, None) 1208 """ 1209 1210 # NOTE: For now, not adding this exuberance to the output. 1211 1212 return node 1213 1214 # Convenience functions. 1215 1216 def convert(module, program, filename): 1217 stream = open(filename, "wb") 1218 try: 1219 source = ConvertedSource(module, program) 1220 source.to_stream(stream) 1221 finally: 1222 stream.close() 1223 1224 def translate(program, directory): 1225 if not exists(directory): 1226 os.mkdir(directory) 1227 1228 # NOTE: Add constants here. 1229 1230 for module in program.get_importer().get_modules(): 1231 convert(module, program, join(directory, "%s%spy" % (module.full_name(), extsep))) 1232 1233 # vim: tabstop=4 expandtab shiftwidth=4