1 #!/usr/bin/env python 2 3 """ 4 Translate the AST of a Python program into a more interpretable representation. 5 6 Copyright (C) 2007, 2008 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.rsvp import * 25 import compiler.ast 26 from compiler.visitor import ASTVisitor 27 28 # Program visitors. 29 30 class Translation(ASTVisitor): 31 32 "A translated module." 33 34 supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage", "load_operations", "unused_results"] 35 36 attribute_load_instructions = (LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex) 37 attribute_store_instructions = (None, None, StoreAttr, StoreAttrIndex) 38 name_load_instructions = (LoadName, LoadAddress) 39 name_store_instructions = (StoreName, StoreAddress) 40 41 def __init__(self, module, importer, optimisations=None): 42 43 """ 44 Initialise the translation with an inspected 'module', the 'importer' 45 and optional 'optimisations'. See the 'supported_optimisations' 46 attribute of this class for permitted values. 47 """ 48 49 ASTVisitor.__init__(self) 50 self.visitor = self 51 self.module = module 52 53 # Global program dependencies. 54 55 self.importer = importer 56 self.objtable = self.importer.get_object_table() 57 self.paramtable = self.importer.get_parameter_table() 58 self.builtins = self.importer.modules.get("__builtins__") 59 60 # Desired optimisations. 61 62 self.optimisations = set(optimisations or []) 63 64 # The current unit being translated. 65 66 self.unit = None 67 68 # The current "active" instruction. 69 # As a rule, this will become the last instruction, but some 70 # control-flow operations will flush the "active" instruction. 71 72 self.active = None 73 74 # The temporary storage used by the current assignment expression. 75 76 self.expr_temp = None 77 78 # Wiring within the code. 79 80 self.labels = {} 81 self.label_number = 0 82 self.loop_labels = [] 83 self.exception_labels = [] 84 85 # The code itself. This is limited to the code for a particular block 86 # being processed. Also retained is information about temporary values. 87 88 self.code = None 89 self.temp_position = 0 90 91 def __repr__(self): 92 return "Translation(%r)" % self.module 93 94 def get_module_code(self): 95 96 "Return the top-level module code." 97 98 self.unit = self.module 99 self.code = [] 100 self.temp_position = 0 101 102 if self.module.module is not None: 103 self.dispatch(self.module.module) 104 105 return self.code 106 107 def get_code(self, unit): 108 109 "Return the code for the given 'unit'." 110 111 self.unit = unit 112 self.code = [] 113 self.temp_position = 0 114 115 if unit.astnode is not None: 116 self.dispatch(unit.astnode) 117 118 return self.code 119 120 # Name-related methods. 121 122 def get_scope(self, name): 123 124 "Return the scope for the given 'name'." 125 126 if self.unit.has_key(name): 127 return "local" 128 elif self.module.has_key(name): 129 return "global" 130 else: 131 return "builtins" 132 133 def load_builtin(self, name, node): 134 135 "Generate an instruction loading 'name' for the given 'node'." 136 137 self.new_op(LoadAddress(self.get_builtin(name, node))) 138 139 def get_builtin(self, name, node): 140 141 """ 142 Return the built-in module definition for the given 'name', used by the 143 given 'node'. 144 """ 145 146 if self.builtins is not None: 147 try: 148 return self.builtins[name] 149 except KeyError: 150 raise TranslateError(self.module.full_name(), node, "No __builtins__ definition is available for name %r." % name) 151 else: 152 raise TranslateError(self.module.full_name(), node, "No __builtins__ module is available for name %r." % name) 153 154 # Code feature methods. 155 156 def new_label(self): 157 158 "Return a new label object for use with set_label." 159 160 number = self.label_number 161 label = Label(number) 162 self.labels[label] = label 163 self.label_number += 1 164 return label 165 166 def set_label(self, label): 167 168 """ 169 Set the location of 'label' to that within the entire image: the 170 location within the code combined with location of the code unit. 171 """ 172 173 label.location = len(self.code) + self.unit.code_location 174 175 def get_loop_labels(self): 176 return self.loop_labels[-1] 177 178 def add_loop_labels(self, next_label, exit_label): 179 self.loop_labels.append((next_label, exit_label)) 180 181 def drop_loop_labels(self): 182 self.loop_labels.pop() 183 184 def get_exception_labels(self): 185 return self.exception_labels[-1] 186 187 def add_exception_labels(self, handler_label, exit_label): 188 self.exception_labels.append((handler_label, exit_label)) 189 190 def drop_exception_labels(self): 191 self.exception_labels.pop() 192 193 # Assignment expression values. 194 195 def record_value(self): 196 self.expr_temp = self._optimise_temp_storage() 197 198 def discard_value(self): 199 self.discard_temp(self.expr_temp) 200 self.expr_temp = None 201 202 def set_source(self): 203 if self.active is not None: 204 self.active.source = self.expr_temp 205 206 # Optimise away constant storage if appropriate. 207 208 self._optimise_constant_storage() 209 210 # Temporary storage administration. 211 212 def get_temp(self): 213 214 """ 215 Add a temporary storage instruction for the current value and return a 216 sequence of access instructions. 217 """ 218 219 temp_position = self.reserve_temp(1) 220 self.new_op(StoreTemp(temp_position)) 221 return LoadTemp(temp_position) 222 223 def reserve_temp(self, n): 224 temp_position = self.temp_position 225 self.temp_position += n 226 return temp_position 227 228 def discard_temp(self, instruction): 229 if isinstance(instruction, LoadTemp): 230 self.temp_position -= 1 231 232 # Code writing methods. 233 234 def new_op(self, op): 235 236 "Add 'op' to the generated code." 237 238 # Optimise load operations employed by this instruction. 239 240 self._optimise_load_operations(op) 241 242 self.code.append(op) 243 self.active = op 244 245 def remove_op(self): 246 247 "Remove the last instruction." 248 249 op = self.code.pop() 250 self.active = None 251 252 def replace_op(self, op): 253 254 "Replace the last added instruction with 'op'." 255 256 self.remove_op() 257 self.new_op(op) 258 259 def last_op(self): 260 261 "Return the last added instruction." 262 263 try: 264 return self.code[-1] 265 except IndexError: 266 return None 267 268 # Optimisation tests. 269 270 def _should_optimise_constant_storage(self): 271 return "constant_storage" in self.optimisations 272 273 def _should_optimise_known_target(self): 274 return "known_target" in self.optimisations 275 276 def _should_optimise_self_access(self): 277 return "self_access" in self.optimisations 278 279 def _should_optimise_temp_storage(self): 280 return "temp_storage" in self.optimisations 281 282 def _should_optimise_load_operations(self): 283 return "load_operations" in self.optimisations 284 285 def _should_optimise_unused_results(self): 286 return "unused_results" in self.optimisations 287 288 # Simple tests. 289 290 def _is_constant_input(self, instruction): 291 292 "Return whether 'instruction' provides a constant input." 293 294 return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 or \ 295 isinstance(instruction, LoadConst) 296 297 def _is_constant_target(self, instruction): 298 299 "Return whether 'instruction' provides a constant target." 300 301 return isinstance(instruction, (StoreName, StoreAddress)) and \ 302 instruction.attr.assignments == 1 303 304 def _is_simple_input(self, instruction): 305 306 "Return whether 'instruction' provides a simple input." 307 308 return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadAddress, MakeObject)) 309 310 def _is_simple_input_user(self, instruction): 311 312 "Return whether 'instruction' can use simple input from the current value." 313 314 return isinstance(instruction, ( 315 StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored 316 LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced 317 StoreAttr, StoreAttrIndex, StoreCallable # as the object being referenced 318 )) 319 320 def _is_input(self, instruction): 321 322 "Return whether 'instruction' provides an input." 323 324 return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult) + self.attribute_load_instructions) 325 326 # Convenience tests. 327 328 def _have_constant_input(self): 329 330 "Return whether the active instruction provides a constant input." 331 332 return self._is_constant_input(self.active) 333 334 _have_known_target = _have_constant_input 335 336 def _have_constant_target(self): 337 338 "Return whether the active instruction provides a constant target." 339 340 return self._is_constant_target(self.active) 341 342 def _have_constant_source(self): 343 344 "Return whether the active instruction has a constant source." 345 346 return self._is_constant_input(self.active.source) 347 348 def _have_simple_input(self): 349 350 "Return whether the active instruction provides a simple input." 351 352 return self._is_simple_input(self.active) 353 354 def _have_input(self): 355 356 "Return whether the active instruction provides an input." 357 358 return self._is_input(self.active) 359 360 def _have_self_input(self): 361 362 "Return whether the active instruction is a reference to self." 363 364 return isinstance(self.unit, Function) and \ 365 self.unit.is_method() and isinstance(self.active, LoadName) and \ 366 self.active.attr.name == "self" 367 368 def _have_temp_compatible_access(self): 369 370 """ 371 Indicate whether the active instruction can be used in place of access 372 to a temporary variable retaining the result of the last instruction. 373 """ 374 375 return isinstance(self.active, (LoadName, LoadTemp, LoadAddress, LoadConst, LoadResult)) 376 377 # Optimisation methods. See the supported_optimisations class attribute. 378 379 def _optimise_constant_storage(self): 380 381 """ 382 Where the last operation stores a constant into a target which is also 383 constant, optimise away both operations. 384 """ 385 386 if self._should_optimise_constant_storage() and \ 387 self._have_constant_target() and \ 388 self._have_constant_source(): 389 390 self.remove_op() 391 return 1 392 else: 393 return 0 394 395 def _optimise_known_target(self): 396 397 """ 398 Where the target of an invocation is known, provide information about it 399 and its context. If a class is being invoked and the conditions are 400 appropriate, get information about the specific initialiser. 401 """ 402 403 if self._should_optimise_known_target() and self._have_known_target(): 404 last = self.last_op() 405 target = last.attr.value 406 context = last.attr.context 407 408 # Handle calls to classes. 409 410 if isinstance(target, Class): 411 target = target.get_instantiator() 412 context = Undefined() 413 414 # A special context is chosen to avoid generating unnecessary 415 # context loading and checking instructions. 416 417 return target, context 418 else: 419 return None 420 421 def _optimise_self_access(self, attrname, classes, node): 422 423 """ 424 Where the provided 'attrname' accesses an attribute which occupies the 425 same position in all possible objects which can be accessed, generate an 426 instruction using one of the given 'classes', accessing the attribute 427 directly. 428 """ 429 430 AddressInstruction, AddressContextInstruction, AttrInstruction = classes 431 432 if self._should_optimise_self_access() and self._have_self_input() and \ 433 not self.unit.is_relocated(attrname): 434 435 # Either generate an instruction operating on an instance attribute. 436 437 try: 438 attr = self.unit.parent.instance_attributes()[attrname] 439 self.new_op(AttrInstruction(attr)) 440 441 # Or generate an instruction operating on a class attribute. 442 443 except KeyError: 444 attr = self.unit.parent.all_attributes()[attrname] 445 new_attr = attr.via_instance() 446 447 # Only permit loading (not storing) of class attributes via self. 448 449 if AddressContextInstruction is not None: 450 self.new_op(AddressContextInstruction(new_attr)) 451 else: 452 raise TranslateError(self.module.full_name(), node, 453 "Storing of class attribute %r via self not permitted." % attrname) 454 455 return 1 456 else: 457 return 0 458 459 def _optimise_temp_storage(self): 460 461 """ 462 Where the next operation would involve storing a value into temporary 463 storage at 'temp_position', record and remove any simple instruction 464 which produced the value to be stored such that instead of subsequently 465 accessing the temporary storage, that instruction is substituted. 466 467 If no optimisation can be achieved, a StoreTemp instruction is produced 468 and the appropriate LoadTemp instruction is returned. 469 470 Restriction: for use only in situations where the source of the 471 temporary data will not be disturbed between its first access and its 472 subsequent use. 473 """ 474 475 if self._should_optimise_temp_storage() and \ 476 self._have_temp_compatible_access(): 477 478 last = self.last_op() 479 self.remove_op() 480 return last 481 else: 482 return self.get_temp() 483 484 def _optimise_load_operations(self, instruction): 485 486 """ 487 Incorporate previous load operations into other operations. 488 """ 489 490 if self._should_optimise_load_operations() and \ 491 self._have_simple_input() and \ 492 self._is_simple_input_user(instruction): 493 494 last = self.last_op() 495 self.remove_op() 496 instruction.input = last 497 498 def _optimise_unused_results(self): 499 500 "Discard results which will not be used." 501 502 if self._have_input(): 503 self.remove_op() 504 505 # Visitor methods. 506 507 def default(self, node, *args): 508 raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__) 509 510 def dispatch(self, node, *args): 511 return ASTVisitor.dispatch(self, node, *args) 512 513 # Internal helper methods. 514 515 def _visitAttr(self, node, classes): 516 517 """ 518 Visit the attribute-related 'node', generating instructions based on the 519 given 'classes'. 520 """ 521 522 self.dispatch(node.expr) 523 self._generateAttr(node, node.attrname, classes) 524 525 def _generateAttr(self, node, attrname, classes): 526 527 """ 528 Generate code for the access to 'attrname' using the given 'classes'. 529 """ 530 531 AddressInstruction, AddressContextInstruction, AttrInstruction, AttrIndexInstruction = classes 532 533 # Where the last operation (defining the attribute owner) yields a 534 # constant... 535 536 if self._have_constant_input(): 537 last = self.active 538 539 # Get the details of the access. 540 541 if isinstance(last.attr, Const): 542 target_name = last.attr.value_type_name() 543 else: 544 target = last.attr.value 545 546 if isinstance(target, Const): 547 target_name = target.value_type_name() 548 elif isinstance(target, Instance): 549 target_name = None # skip production of optimised code 550 else: 551 target_name = target.full_name() 552 553 # Only try and discover the position if the target can be resolved. 554 555 if target_name is not None: 556 557 # Access the object table to get the attribute position. 558 559 try: 560 table_entry = self.objtable.table[target_name] 561 except KeyError: 562 raise TranslateError(self.module.full_name(), node, 563 "No object entry exists for target %r." % target_name) 564 565 try: 566 pos = table_entry[attrname] 567 except KeyError: 568 raise TranslateError(self.module.full_name(), node, 569 "No attribute entry exists for name %r in target %r." % (attrname, target_name)) 570 571 # Produce a suitable instruction. 572 573 if AddressInstruction is not None: 574 self.replace_op(AddressInstruction(pos)) 575 else: 576 raise TranslateError(self.module.full_name(), node, 577 "Storing of class or module attribute %r via an object is not permitted." % attrname) 578 579 return 580 581 # Where the last operation involves the special 'self' name, check to 582 # see if the attribute is acceptably positioned and produce a direct 583 # access to the attribute. 584 585 elif self._optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction), node): 586 return 587 588 # Otherwise, perform a normal operation. 589 590 try: 591 index = self.objtable.get_index(attrname) 592 except self.objtable.TableError: 593 raise TranslateError(self.module.full_name(), node, 594 "No attribute entry exists for name %r." % attrname) 595 596 self.new_op(AttrIndexInstruction(index)) 597 598 # Invocations involve the following: 599 # 600 # 1. Reservation of a frame for the arguments 601 # 2. Identification of the target which is then held in temporary storage 602 # 3. Optional inclusion of a context (important for methods) 603 # 4. Preparation of the argument frame 604 # 5. Invocation of the target 605 # 6. Discarding of the frame 606 # 607 # In order to support nested invocations - eg. a(b(c)) - use of the 608 # temporary storage is essential. 609 610 def _startCallFunc(self): 611 612 "Record the location of the invocation." 613 614 self.new_op(MakeFrame()) # records the start of the frame 615 616 def _generateCallFunc(self, args, node): 617 618 """ 619 Support a generic function invocation using the given 'args', occurring 620 on the given 'node', where the expression providing the invocation 621 target has just been generated. 622 623 In other situations, the invocation is much simpler and does not need to 624 handle the full flexibility of a typical Python invocation. Internal 625 invocations, such as those employed by operators and certain 626 control-flow mechanisms, use predetermined arguments and arguably do not 627 need to support the same things as the more general invocations. 628 """ 629 630 target, context, temp = self._generateCallFuncContext() 631 self._generateCallFuncArgs(target, context, temp, args, node) 632 return temp 633 634 def _generateCallFuncContext(self): 635 636 """ 637 Produce code which loads and checks the context of the current 638 invocation, the instructions for whose target have already been 639 produced, returning a list of instructions which reference the 640 invocation target. 641 """ 642 643 t = self._optimise_known_target() 644 if t: 645 target, context = t 646 else: 647 target, context = None, None 648 649 # Store the target in temporary storage for subsequent referencing. 650 651 temp = self._optimise_temp_storage() 652 653 # Where a target or context are not known or where an instance is known 654 # to be the context, load the context. 655 656 if context is None or isinstance(context, Instance): 657 self.new_op(temp) 658 self.new_op(LoadContext()) 659 self.new_op(StoreFrame(0)) 660 661 # Otherwise omit the context. 662 663 else: 664 pass # NOTE: Class methods should be supported. 665 666 return target, context, temp 667 668 def _generateCallFuncArgs(self, target, context, temp, args, node): 669 670 """ 671 Given invocation 'target' and 'context' information, the 'temp' 672 reference to the target, a list of nodes representing the 'args' 673 (arguments), generate instructions which load the arguments for the 674 invocation defined by the given 'node'. 675 """ 676 677 # Evaluate the arguments. 678 679 employed_positions = set() 680 extra_keywords = [] 681 682 # Note the presence of the context in the frame where appropriate. 683 684 if context is None or isinstance(context, Instance): 685 ncontext = 1 686 expect_context = 0 687 elif isinstance(context, Class): 688 ncontext = 0 689 expect_context = 1 690 else: 691 ncontext = 0 692 expect_context = 0 693 694 first = 1 695 frame_pos = ncontext 696 697 for arg in args: 698 699 # Handle positional and keyword arguments separately. 700 701 if isinstance(arg, compiler.ast.Keyword): 702 703 # Optimise where the target is known now. 704 705 if target is not None: 706 707 # Find the parameter table entry for the target. 708 709 target_name = target.full_name() 710 711 # Look for a callable with the precise target name. 712 713 table_entry = self.paramtable.table[target_name] 714 715 # Look the name up in the parameter table entry. 716 717 try: 718 pos = table_entry[arg.name] 719 720 # Where no position is found, this could be an extra keyword 721 # argument. 722 723 except KeyError: 724 extra_keywords.append(arg) 725 continue 726 727 # Test for illegal conditions. 728 729 if pos in employed_positions: 730 raise TranslateError(self.module.full_name(), node, 731 "Keyword argument %r overwrites parameter %r." % (arg.name, pos)) 732 733 employed_positions.add(pos) 734 735 # Generate code for the keyword and the positioning 736 # operation. 737 738 self.dispatch(arg.expr) 739 self.new_op(StoreFrame(pos)) 740 741 # Otherwise, generate the code needed to obtain the details of 742 # the parameter location. 743 744 else: 745 746 # Combine the target details with the name to get the location. 747 # See the access method on the List class. 748 749 try: 750 paramindex = self.paramtable.get_index(arg.name) 751 752 # Where no position is found, this could be an extra keyword 753 # argument. 754 755 except self.paramtable.TableError: 756 extra_keywords.append(arg) 757 continue 758 759 # Generate code for the keyword and the positioning 760 # operation. 761 762 self.dispatch(arg.expr) 763 self.new_op(StoreFrameIndex(paramindex)) 764 765 # use (callable+0)+paramindex+table 766 # checks embedded offset against (callable+0) 767 # moves the current value to frame+position 768 769 else: 770 self.dispatch(arg) 771 self.new_op(StoreFrame(frame_pos)) 772 773 employed_positions.add(frame_pos) 774 775 # Check to see if the first argument is appropriate (compatible with 776 # the target where methods are being invoked via classes). 777 778 if first and expect_context: 779 continue_label = self.new_label() 780 self.new_op(CheckSelf()) 781 self.new_op(JumpIfTrue(continue_label)) 782 783 # Where the context is inappropriate, drop the incomplete frame and 784 # raise an exception. 785 786 self.new_op(DropFrame()) 787 788 self.new_op(LoadResult()) 789 790 self.load_builtin("TypeError", node) 791 self.new_op(StoreException()) 792 self.new_op(RaiseException()) 793 self.set_label(continue_label) 794 795 first = 0 796 frame_pos += 1 797 798 # NOTE: Extra keywords are not supported. 799 # NOTE: Somehow, the above needs to be combined with * arguments. 800 801 # Either test for a complete set of arguments. 802 803 if target is not None: 804 805 # Make sure that enough arguments have been given. 806 807 nargs_max = len(target.positional_names) 808 ndefaults = len(target.defaults) 809 nargs_min = nargs_max - ndefaults 810 811 for i in range(ncontext, nargs_min): 812 if i not in employed_positions: 813 raise TranslateError(self.module.full_name(), node, 814 "Argument %r not supplied for %r: need at least %d arguments." % (i+1, target.name, nargs_min)) 815 816 nargs = len(args) 817 818 if nargs > nargs_max and not target.has_star and not target.has_dstar: 819 raise TranslateError(self.module.full_name(), node, 820 "Too many arguments for %r: need at most %d arguments." % (target.name, nargs_max)) 821 822 # Where defaults are involved, put them into the frame. 823 824 self._generateCallFuncDefaultArgs(target, temp, nargs_min, nargs_max, employed_positions) 825 826 # Or generate instructions to do this at run-time. 827 # NOTE: CheckFrame has to check the number of arguments and to fill in 828 # NOTE: defaults; it also has to shift the invocation frame according to 829 # NOTE: the context in use. 830 831 else: 832 self.new_op(CheckFrame()) 833 834 def _generateCallFuncDefaultArgs(self, target, temp, nargs_min, nargs_max, employed_positions): 835 836 """ 837 For the given 'target' and 'temp' reference to the target, generate 838 default arguments for those positions in the range 'nargs_min'... 839 'nargs_max' which are not present in the 'employed_positions' 840 collection. 841 """ 842 843 # Where a lambda is involved, construct a dynamic object to hold the 844 # defaults. 845 846 dynamic = target.name is None 847 848 # Here, we use negative index values to visit the right hand end of 849 # the defaults list. 850 851 for pos in range(nargs_min, nargs_max): 852 if pos not in employed_positions: 853 if dynamic: 854 self.new_op(temp) 855 self.new_op(LoadAttr(target.default_attrs[pos - nargs_min])) 856 else: 857 self.new_op(LoadAddress(target.default_attrs[pos - nargs_min])) 858 self.new_op(StoreFrame(pos)) 859 860 def _doCallFunc(self, instruction): 861 862 "Make the invocation." 863 864 self.new_op(instruction) 865 self.new_op(JumpWithFrame()) 866 867 def _endCallFunc(self, instruction=None): 868 869 "Finish the invocation and tidy up afterwards." 870 871 self.new_op(DropFrame()) 872 self.new_op(LoadResult()) 873 874 # Discard any temporary storage instructions. 875 876 if instruction is not None: 877 self.discard_temp(instruction) 878 879 def _generateFunctionDefaults(self, function): 880 881 """ 882 Generate the default initialisation code for 'function', returning 883 a temporary storage reference if a dynamic object was created for the 884 function. 885 """ 886 887 attr_to_default = zip(function.default_attrs, function.defaults) 888 if not attr_to_default: 889 return None 890 891 # Where a lambda is involved, construct a dynamic object to hold the 892 # defaults. 893 894 dynamic = function.name is None 895 896 if dynamic: 897 self.new_op(MakeObject(len(attr_to_default))) 898 temp = self.get_temp() 899 900 for attr, default in attr_to_default: 901 self.dispatch(default) 902 903 self.record_value() 904 if dynamic: 905 self.new_op(temp) 906 self.new_op(StoreAttr(attr)) 907 else: 908 self.new_op(StoreAddress(attr)) 909 self.set_source() 910 self.discard_value() 911 912 if dynamic: 913 return temp 914 else: 915 return None 916 917 def _visitName(self, node, classes): 918 919 """ 920 Visit the name-related 'node', generating instructions based on the 921 given 'classes'. 922 """ 923 924 name = node.name 925 scope = self.get_scope(name) 926 #print self.module.name, node.lineno, name, scope 927 self._generateName(name, scope, classes, node) 928 929 def _generateName(self, name, scope, classes, node): 930 931 """ 932 Generate code for the access to 'name' in 'scope' using the given 933 'classes', and using the given 'node' as the source of the access. 934 """ 935 936 NameInstruction, AddressInstruction = classes 937 938 if scope == "local": 939 unit = self.unit 940 if isinstance(unit, Function): 941 self.new_op(NameInstruction(unit.all_locals()[name])) 942 elif isinstance(unit, Class): 943 self.new_op(AddressInstruction(unit.all_class_attributes()[name])) 944 elif isinstance(unit, Module): 945 self.new_op(AddressInstruction(unit.module_attributes()[name])) 946 else: 947 raise TranslateError(self.module.full_name(), node, "Program unit %r has no local %r." % (unit, name)) 948 949 elif scope == "global": 950 globals = self.module.module_attributes() 951 if globals.has_key(name): 952 self.new_op(AddressInstruction(globals[name])) 953 else: 954 raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r." % (self.module, name)) 955 956 else: 957 self.new_op(AddressInstruction(self.get_builtin(name, node))) 958 959 def _visitUnary(self, node, method): 960 961 """ 962 _t = node.expr 963 try: 964 _result = _t.__pos__() 965 except AttributeError: 966 raise TypeError 967 """ 968 969 end_call_label = self.new_label() 970 end_label = self.new_label() 971 972 # Evaluate and store the operand in temporary storage. 973 974 self.dispatch(node.expr) 975 temp = self._optimise_temp_storage() 976 977 # Produce the invocation. 978 979 self._startCallFunc() 980 self.new_op(temp) 981 982 # Get the method on temp. 983 984 self._generateAttr(node, method, self.attribute_load_instructions) 985 986 # Add exception handling to the method acquisition instructions where 987 # the attribute access cannot be resolved at compile-time. 988 989 if not self._optimise_known_target(): 990 self.load_builtin("AttributeError", node) 991 self.new_op(CheckException()) 992 self.new_op(JumpIfTrue(end_call_label)) 993 994 temp_method = self._optimise_temp_storage() 995 996 # Add arguments. 997 # NOTE: No support for defaults. 998 999 self.new_op(temp) # Explicit context as first argument. 1000 self._doCallFunc(temp_method) 1001 self._endCallFunc(temp_method) 1002 self.new_op(Jump(end_label)) 1003 1004 # End method attempt. 1005 1006 self.set_label(end_call_label) 1007 self._endCallFunc() # From the method call. 1008 1009 # Raise a TypeError. 1010 1011 self.load_builtin("TypeError", node) 1012 self.new_op(StoreException()) 1013 self.new_op(RaiseException()) 1014 1015 self.set_label(end_label) 1016 1017 # Compilation duties... 1018 1019 self.discard_temp(temp) 1020 1021 def _visitBinary(self, node, left_method, right_method): 1022 1023 """ 1024 _t1 = node.left 1025 _t2 = node.right 1026 try: 1027 _result = _t1.__add__(_t2) 1028 if _result is NotImplemented: 1029 raise AttributeError 1030 except AttributeError: 1031 try: 1032 _result = _t2.__radd__(_t1) 1033 if _result is NotImplemented: 1034 raise AttributeError 1035 except AttributeError: 1036 raise TypeError 1037 """ 1038 1039 end_left_label = self.new_label() 1040 right_label = self.new_label() 1041 end_right_label = self.new_label() 1042 type_error_label = self.new_label() 1043 end_label = self.new_label() 1044 1045 # Evaluate and store the left operand in temporary storage. 1046 1047 self.dispatch(node.left) 1048 temp1 = self._optimise_temp_storage() 1049 1050 # Evaluate and store the right operand in temporary storage. 1051 1052 self.dispatch(node.right) 1053 temp2 = self._optimise_temp_storage() 1054 1055 # Left method. 1056 1057 self._startCallFunc() 1058 self.new_op(temp1) 1059 1060 # Get left method on temp1. 1061 1062 self._generateAttr(node, left_method, self.attribute_load_instructions) 1063 1064 # Add exception handling to the method acquisition instructions where 1065 # the attribute access cannot be resolved at compile-time. 1066 1067 if not self._optimise_known_target(): 1068 self.load_builtin("AttributeError", node) 1069 self.new_op(CheckException()) 1070 self.new_op(JumpIfTrue(end_left_label)) 1071 1072 temp_method = self._optimise_temp_storage() 1073 1074 # Add arguments. 1075 # NOTE: No support for defaults. 1076 1077 self.new_op(temp1) # Explicit context as first argument. 1078 self.new_op(temp2) 1079 self._doCallFunc(temp_method) 1080 self._endCallFunc(temp_method) 1081 1082 # Test for NotImplemented. 1083 # Don't actually raise an exception. 1084 1085 self.new_op(TestIdentityAddress(self.get_builtin("NotImplemented", node))) 1086 self.new_op(JumpIfTrue(right_label)) 1087 self.new_op(Jump(end_label)) 1088 1089 # End left method attempt. 1090 1091 self.set_label(end_left_label) 1092 self._endCallFunc() # From the left method call. 1093 1094 # Right method. 1095 1096 self.set_label(right_label) 1097 self._startCallFunc() 1098 self.new_op(temp2) 1099 1100 # Get right method on temp2. 1101 1102 self._generateAttr(node, right_method, self.attribute_load_instructions) 1103 1104 # Add exception handling to the method acquisition instructions where 1105 # the attribute access cannot be resolved at compile-time. 1106 1107 if not self._optimise_known_target(): 1108 self.load_builtin("AttributeError", node) 1109 self.new_op(CheckException()) 1110 self.new_op(JumpIfTrue(end_right_label)) 1111 1112 temp_method = self._optimise_temp_storage() 1113 1114 # Add arguments. 1115 # NOTE: No support for defaults. 1116 1117 self.new_op(temp2) # Explicit context as first argument. 1118 self.new_op(temp1) 1119 self._doCallFunc(temp_method) 1120 self._endCallFunc(temp_method) 1121 1122 # Test for NotImplemented. 1123 # Don't actually raise an exception. 1124 1125 self.new_op(TestIdentityAddress(self.get_builtin("NotImplemented", node))) 1126 self.new_op(JumpIfTrue(type_error_label)) 1127 self.new_op(Jump(end_label)) 1128 1129 # End right method attempt. 1130 1131 self.set_label(end_right_label) 1132 self._endCallFunc() # From the right method call. 1133 1134 # Raise a TypeError. 1135 1136 self.set_label(type_error_label) 1137 self.load_builtin("TypeError", node) 1138 self.new_op(StoreException()) 1139 self.new_op(RaiseException()) 1140 1141 self.set_label(end_label) 1142 1143 # Compilation duties... 1144 1145 self.discard_temp(temp1) 1146 self.discard_temp(temp2) 1147 1148 # Concrete visitor methods. 1149 1150 def visitAdd(self, node): 1151 self._visitBinary(node, "__add__", "__radd__") 1152 1153 def visitAnd(self, node): 1154 next_label = self.new_label() 1155 1156 for n in node.nodes[:-1]: 1157 self.dispatch(n) 1158 self.new_op(TestBoolean()) 1159 self.new_op(JumpIfFalse(next_label)) 1160 1161 self.dispatch(node.nodes[-1]) 1162 self.set_label(next_label) 1163 1164 # Prevent incorrect optimisation. 1165 1166 self.active = None 1167 1168 def visitAssert(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Assert") 1169 1170 def visitAssign(self, node): 1171 self.dispatch(node.expr) 1172 self.record_value() 1173 1174 for n in node.nodes: 1175 self.dispatch(n) 1176 1177 self.discard_value() 1178 1179 def visitAssAttr(self, node): 1180 self._visitAttr(node, self.attribute_store_instructions) 1181 self.set_source() 1182 1183 def visitAssList(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "AssList") 1184 1185 def visitAssName(self, node): 1186 self._visitName(node, self.name_store_instructions) 1187 self.set_source() 1188 1189 visitAssTuple = visitAssList 1190 1191 def visitAugAssign(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "AugAssign") 1192 1193 def visitBackquote(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Backquote") 1194 1195 def visitBitand(self, node): 1196 self._visitBinary(node, "__and__", "__rand__") 1197 1198 def visitBitor(self, node): 1199 self._visitBinary(node, "__or__", "__ror__") 1200 1201 def visitBitxor(self, node): 1202 self._visitBinary(node, "__xor__", "__rxor__") 1203 1204 def visitBreak(self, node): 1205 next_label, exit_label = self.get_loop_labels() 1206 self.new_op(Jump(exit_label)) 1207 1208 def visitCallFunc(self, node): 1209 1210 """ 1211 Evaluate positional arguments, evaluate and store keyword arguments in 1212 the correct location, then invoke the function. 1213 """ 1214 1215 # Mark the frame, evaluate the target, generate the call. 1216 1217 self._startCallFunc() 1218 self.dispatch(node.node) 1219 temp = self._generateCallFunc(node.args, node) 1220 self._doCallFunc(temp) 1221 self._endCallFunc(temp) 1222 1223 def visitClass(self, node): 1224 1225 # Store the name. 1226 1227 self.new_op(LoadConst(node.unit)) 1228 self.record_value() 1229 self._visitName(node, self.name_store_instructions) 1230 self.set_source() 1231 self.discard_value() 1232 1233 # Visit the code. 1234 1235 unit = self.unit 1236 self.unit = node.unit 1237 self.unit.code_location = self.module.code_location # class body code is not independently addressable 1238 self.dispatch(node.code) 1239 self.unit = unit 1240 1241 def visitCompare(self, node): 1242 1243 """ 1244 self.dispatch(node.expr) 1245 for op_name, next_node in compare.ops: 1246 methods = self.comparison_methods[op_name] 1247 if methods is not None: 1248 # Generate method call using evaluated argument and next node. 1249 else: 1250 # Deal with the special operators. 1251 # Provide short-circuiting. 1252 """ 1253 1254 def visitConst(self, node): 1255 const = self.module.constant_values[node.value] 1256 self.new_op(LoadConst(const)) 1257 1258 def visitContinue(self, node): 1259 next_label, exit_label = self.get_loop_labels() 1260 self.new_op(Jump(next_label)) 1261 1262 def visitDecorators(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Decorators") 1263 1264 def visitDict(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Dict") 1265 1266 def visitDiscard(self, node): 1267 self.dispatch(node.expr) 1268 self._optimise_unused_results() 1269 1270 def visitDiv(self, node): 1271 self._visitBinary(node, "__div__", "__rdiv__") 1272 1273 def visitEllipsis(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Ellipsis") 1274 1275 def visitExec(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Exec") 1276 1277 def visitExpression(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Expression") 1278 1279 def visitFloorDiv(self, node): 1280 self._visitBinary(node, "__floordiv__", "__rfloordiv__") 1281 1282 def visitFor(self, node): 1283 exit_label = self.new_label() 1284 next_label = self.new_label() 1285 else_label = self.new_label() 1286 1287 # Get the "list" to be iterated over, obtain its iterator. 1288 1289 self._startCallFunc() 1290 self.dispatch(node.list) 1291 self._generateAttr(node, "__iter__", self.attribute_load_instructions) 1292 temp = self._generateCallFunc([], node) 1293 self._doCallFunc(temp) 1294 self._endCallFunc(temp) 1295 1296 temp_iterator = self._optimise_temp_storage() 1297 1298 # In the loop... 1299 1300 self.set_label(next_label) 1301 1302 # Use the iterator to get the next value. 1303 1304 self._startCallFunc() 1305 self.new_op(temp_iterator) 1306 self._generateAttr(node, "next", self.attribute_load_instructions) 1307 temp = self._generateCallFunc([], node) 1308 self._doCallFunc(temp) 1309 self._endCallFunc(temp) 1310 1311 # Test for StopIteration. 1312 1313 self.load_builtin("StopIteration", node) 1314 self.new_op(CheckException()) 1315 if node.else_ is not None: 1316 self.new_op(JumpIfTrue(else_label)) 1317 else: 1318 self.new_op(JumpIfTrue(exit_label)) 1319 1320 # Assign to the target. 1321 1322 self.dispatch(node.assign) 1323 1324 # Process the body with the current next and exit points. 1325 1326 self.add_loop_labels(next_label, exit_label) 1327 self.dispatch(node.body) 1328 self.drop_loop_labels() 1329 1330 # Repeat the loop. 1331 1332 self.new_op(Jump(next_label)) 1333 1334 # Produce the "else" section. 1335 1336 if node.else_ is not None: 1337 self.set_label(exit_label) 1338 self.dispatch(node.else_) 1339 1340 # After the loop... 1341 1342 self.set_label(exit_label) 1343 1344 # Compilation duties... 1345 1346 self.discard_temp(temp_iterator) 1347 1348 def visitFrom(self, node): pass 1349 1350 def visitFunction(self, node): 1351 1352 # Only store the name when visiting this node from outside. 1353 1354 if self.unit is not node.unit: 1355 self.new_op(LoadConst(node.unit)) 1356 1357 self.record_value() 1358 self._visitName(node, self.name_store_instructions) # AssName equivalent 1359 self.set_source() 1360 self.discard_value() 1361 1362 self._generateFunctionDefaults(node.unit) 1363 1364 # Visiting of the code occurs when get_code is invoked on this node. 1365 1366 else: 1367 self.dispatch(node.code) 1368 if not isinstance(self.last_op(), Return): 1369 self.dispatch(compiler.ast.Name("None")) 1370 self.new_op(StoreResult()) 1371 1372 self.new_op(Return()) 1373 1374 def visitGenExpr(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExpr") 1375 1376 def visitGenExprFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprFor") 1377 1378 def visitGenExprIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprIf") 1379 1380 def visitGenExprInner(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprInner") 1381 1382 def visitGetattr(self, node): 1383 self._visitAttr(node, self.attribute_load_instructions) 1384 1385 def visitGlobal(self, node): pass 1386 1387 def visitIf(self, node): 1388 first = 1 1389 exit_label = self.new_label() 1390 1391 clauses = node.tests + [(None, node.else_)] 1392 last_clause = clauses[-1] 1393 1394 for clause in clauses: 1395 test, body = clause 1396 if body is None: 1397 break 1398 if not first: 1399 self.set_label(next_label) 1400 if test is not None: 1401 self.dispatch(test) 1402 next_label = self.new_label() 1403 self.new_op(JumpIfFalse(next_label)) 1404 self.dispatch(body) 1405 if clause is not last_clause: 1406 self.new_op(Jump(exit_label)) 1407 first = 0 1408 1409 self.set_label(exit_label) 1410 1411 def visitImport(self, node): pass 1412 1413 def visitInvert(self, node): 1414 self._visitUnary(node, "__invert__") 1415 1416 def visitKeyword(self, node): pass 1417 1418 def visitLambda(self, node): 1419 1420 # Produce the reference to this function when visiting this node from 1421 # outside. 1422 1423 if self.unit is not node.unit: 1424 temp = self._generateFunctionDefaults(node.unit) 1425 self.new_op(LoadConst(node.unit)) 1426 1427 # Populate the new object required for the function. 1428 1429 if temp is not None: 1430 self.record_value() 1431 self.new_op(temp) 1432 self.new_op(StoreCallable()) 1433 self.set_source() 1434 self.discard_value() 1435 1436 self.new_op(temp) 1437 self.discard_temp(temp) 1438 1439 # Visiting of the code occurs when get_code is invoked on this node. 1440 1441 else: 1442 self.dispatch(node.code) 1443 self.new_op(StoreResult()) 1444 self.new_op(Return()) 1445 1446 def visitLeftShift(self, node): 1447 self._visitBinary(node, "__lshift__", "__rlshift__") 1448 1449 def visitList(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "List") 1450 1451 def visitListComp(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListComp") 1452 1453 def visitListCompFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompFor") 1454 1455 def visitListCompIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompIf") 1456 1457 def visitMod(self, node): 1458 self._visitBinary(node, "__mod__", "__rmod__") 1459 1460 def visitModule(self, node): 1461 self.dispatch(node.node) 1462 1463 def visitMul(self, node): 1464 self._visitBinary(node, "__mul__", "__rmul__") 1465 1466 def visitName(self, node): 1467 if node.name == "None": 1468 const = self.module.constant_values[None] 1469 self.new_op(LoadConst(const)) 1470 else: 1471 self._visitName(node, self.name_load_instructions) 1472 1473 def visitNot(self, node): 1474 next_label = self.new_label() 1475 true_label = self.new_label() 1476 1477 self.dispatch(node.expr) 1478 self.new_op(TestBoolean()) 1479 self.new_op(JumpIfTrue(true_label)) 1480 self.load_builtin("True", node) 1481 self.new_op(Jump(next_label)) 1482 1483 self.set_label(true_label) 1484 self.load_builtin("False", node) 1485 self.set_label(next_label) 1486 1487 # Prevent incorrect optimisation. 1488 1489 self.active = None 1490 1491 def visitOr(self, node): 1492 next_label = self.new_label() 1493 1494 for n in node.nodes[:-1]: 1495 self.dispatch(n) 1496 self.new_op(TestBoolean()) 1497 self.new_op(JumpIfTrue(next_label)) 1498 1499 self.dispatch(node.nodes[-1]) 1500 self.set_label(next_label) 1501 1502 # Prevent incorrect optimisation. 1503 1504 self.active = None 1505 1506 def visitPass(self, node): pass 1507 1508 def visitPower(self, node): 1509 self._visitBinary(node, "__pow__", "__rpow__") 1510 1511 def visitPrint(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Print") 1512 1513 def visitPrintnl(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Printnl") 1514 1515 def visitRaise(self, node): 1516 # NOTE: expr1 only => instance provided 1517 self.dispatch(node.expr1) 1518 1519 if node.expr2 is not None: 1520 temp = self._optimise_temp_storage() 1521 1522 self.dispatch(node.expr2) 1523 temp_arg = self._optimise_temp_storage() 1524 1525 self._startCallFunc() 1526 self.new_op(temp_arg) 1527 self.new_op(StoreFrame(0)) 1528 self._doCallFunc(temp) 1529 self._endCallFunc(temp) 1530 1531 self.discard_temp(temp_arg) 1532 1533 self.new_op(StoreException()) 1534 self.new_op(RaiseException()) 1535 1536 def visitReturn(self, node): 1537 if node.value is not None: 1538 self.dispatch(node.value) 1539 else: 1540 self.dispatch(compiler.ast.Name("None")) 1541 1542 self.new_op(StoreResult()) 1543 self.new_op(Return()) 1544 1545 def visitRightShift(self, node): 1546 self._visitBinary(node, "__rshift__", "__rrshift__") 1547 1548 def visitSlice(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Slice") 1549 1550 def visitStmt(self, node): 1551 for n in node.nodes: 1552 self.dispatch(n) 1553 1554 def visitSub(self, node): 1555 self._visitBinary(node, "__sub__", "__rsub__") 1556 1557 def visitSubscript(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Subscript") 1558 1559 def visitTryExcept(self, node): 1560 exit_label = self.new_label() 1561 success_label = self.new_label() 1562 handler_label = self.new_label() 1563 1564 self.add_exception_labels(handler_label, exit_label) 1565 1566 # Try... 1567 # Produce the code, then jump to the exit. 1568 1569 self.new_op(PushHandler(handler_label)) 1570 self.dispatch(node.body) 1571 self.new_op(PopHandler()) 1572 self.new_op(Jump(exit_label)) 1573 1574 # Start of handlers. 1575 1576 self.set_label(handler_label) 1577 self.new_op(PopHandler()) 1578 1579 for name, assignment, handler in node.handlers: 1580 next_label = self.new_label() 1581 1582 # Test the given exception against the current exception. 1583 1584 if name is not None: 1585 self.dispatch(name) 1586 self.new_op(CheckException()) 1587 self.new_op(JumpIfFalse(next_label)) 1588 1589 # Handle assignment to exception variable. 1590 1591 if assignment is not None: 1592 self.dispatch(assignment) 1593 1594 # Produce the handler code, then jump to the exit. 1595 1596 self.dispatch(handler) 1597 self.new_op(Jump(exit_label)) 1598 1599 self.set_label(next_label) 1600 1601 # Unhandled exceptions. 1602 1603 #self.new_op(LoadException()) 1604 self.new_op(RaiseException()) 1605 1606 # Optional else clause. 1607 1608 if node.else_ is not None: 1609 self.dispatch(node.else_) 1610 1611 self.set_label(exit_label) 1612 self.drop_exception_labels() 1613 1614 def visitTryFinally(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "TryFinally") 1615 1616 def visitTuple(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Tuple") 1617 1618 def visitUnaryAdd(self, node): 1619 self._visitUnary(node, "__pos__") 1620 1621 def visitUnarySub(self, node): 1622 self._visitUnary(node, "__neg__") 1623 1624 def visitWhile(self, node): 1625 exit_label = self.new_label() 1626 next_label = self.new_label() 1627 else_label = self.new_label() 1628 1629 self.set_label(next_label) 1630 self.dispatch(node.test) 1631 if node.else_ is not None: 1632 self.new_op(JumpIfFalse(else_label)) 1633 else: 1634 self.new_op(JumpIfFalse(exit_label)) 1635 1636 self.add_loop_labels(next_label, exit_label) 1637 1638 self.dispatch(node.body) 1639 self.new_op(Jump(next_label)) 1640 1641 if node.else_ is not None: 1642 self.set_label(else_label) 1643 self.dispatch(node.else_) 1644 1645 self.set_label(exit_label) 1646 self.drop_loop_labels() 1647 1648 # Prevent incorrect optimisation. 1649 1650 self.active = None 1651 1652 def visitWith(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "With") 1653 1654 def visitYield(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Yield") 1655 1656 # Useful data. 1657 1658 comparison_methods = { 1659 "==" : ("__eq__", "__ne__"), 1660 "!=" : ("__ne__", "__eq__"), 1661 "<" : ("__lt__", "__gt__"), 1662 "<=" : ("__le__", "__ge__"), 1663 ">=" : ("__ge__", "__le__"), 1664 ">" : ("__gt__", "__lt__"), 1665 "is" : None, 1666 "is not" : None, 1667 "in" : None, 1668 "not in" : None 1669 } 1670 1671 # vim: tabstop=4 expandtab shiftwidth=4