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