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