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 class Optimiser: 29 30 "A code optimiser." 31 32 supported_optimisations = [ 33 "constant_storage", "source_storage", "known_target", "self_access", 34 "temp_storage", "load_operations", "no_operations", "unused_results", 35 "superfluous_temp_operations" 36 ] 37 38 def __init__(self, translation, optimisations=None): 39 40 """ 41 Provide for the given 'translation' an optimiser for the desired 42 'optimisations'. See the 'supported_optimisations' attribute of this 43 class for permitted values. 44 """ 45 46 self.translation = translation 47 self.optimisations = set(optimisations or []) 48 49 # Optimisation tests. 50 51 def should_optimise_constant_storage(self): 52 return "constant_storage" in self.optimisations 53 54 def should_optimise_source_storage(self): 55 return "source_storage" in self.optimisations 56 57 def should_optimise_known_target(self): 58 return "known_target" in self.optimisations 59 60 def should_optimise_self_access(self): 61 return "self_access" in self.optimisations 62 63 def should_optimise_temp_storage(self): 64 return "temp_storage" in self.optimisations 65 66 def should_optimise_load_operations(self): 67 return "load_operations" in self.optimisations 68 69 def should_optimise_away_no_operations(self): 70 return "no_operations" in self.optimisations 71 72 def should_optimise_away_superfluous_temp_operations(self): 73 return "superfluous_temp_operations" in self.optimisations 74 75 def should_optimise_unused_results(self): 76 return "unused_results" in self.optimisations 77 78 # Simple tests. 79 80 def is_constant_input(self, instruction): 81 82 "Return whether 'instruction' provides a constant input." 83 84 return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 or \ 85 isinstance(instruction, LoadConst) 86 87 def is_constant_target(self, instruction): 88 89 "Return whether 'instruction' provides a constant target." 90 91 return isinstance(instruction, (StoreName, StoreAddress)) and \ 92 instruction.attr.assignments == 1 93 94 def is_simple_input(self, instruction): 95 96 """ 97 Return whether 'instruction' provides a simple input (typically a load 98 instruction). A simple input is something which would be represented by 99 a load operation from a CPU register or special memory location. 100 """ 101 102 return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadAddress)) 103 104 def is_simple_input_user(self, instruction): 105 106 """ 107 Return whether 'instruction' can use simple input from the current 108 value. Such instructions would, in a low-level implementation, be able 109 to have the simple input registers as operands. 110 """ 111 112 return isinstance(instruction, ( 113 StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored 114 LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced 115 StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced 116 LoadCallable, 117 TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands 118 CheckFrame, MakeObject, 119 LoadContext # as the object providing the result 120 )) 121 122 def is_resultant_no_operation(self, instruction): 123 124 """ 125 Return whether 'instruction' merely stores its input where the input 126 originally came from. 127 """ 128 129 return ( 130 isinstance(instruction.input, LoadTemp) and isinstance(instruction, StoreTemp) and 131 instruction.input.attr == instruction.attr) or ( 132 isinstance(instruction.input, LoadResult) and isinstance(instruction, StoreResult) 133 ) 134 135 def is_superfluous_temp_operation(self, instruction): 136 137 """ 138 Return whether 'instruction' merely loads its input from a recent 139 temporary storage operation. 140 """ 141 142 return ( 143 isinstance(instruction.source, LoadTemp) and isinstance(self.translation.active_source, StoreTemp) and 144 instruction.source.attr == self.translation.active_source.attr 145 ) 146 147 def is_input(self, instruction): 148 149 "Return whether 'instruction' provides an input." 150 151 return isinstance(instruction, current_value_instructions) 152 153 # Convenience tests on outputs. 154 155 def have_constant_target(self): 156 157 "Return whether the active instruction provides a constant target." 158 159 return self.is_constant_target(self.translation.active) 160 161 def have_constant_source(self): 162 163 "Return whether the active instruction has a constant source." 164 165 return self.is_constant_input(self.translation.active.source) 166 167 # Convenience tests on inputs. 168 169 def have_constant_input(self): 170 171 "Return whether the active instruction provides a constant input." 172 173 return self.is_constant_input(self.translation.active_value) 174 175 have_known_target = have_constant_input 176 177 def have_simple_input(self): 178 179 "Return whether the active instruction provides a simple input." 180 181 return self.is_simple_input(self.translation.active_value) 182 183 def have_input(self): 184 185 "Return whether the active instruction provides an input." 186 187 return self.is_input(self.translation.active_value) 188 189 def have_self_input(self): 190 191 "Return whether the active instruction is a reference to self." 192 193 return isinstance(self.translation.unit, Function) and \ 194 self.translation.unit.is_method() and isinstance(self.translation.active_value, LoadName) and \ 195 self.translation.active_value.attr.name == "self" 196 197 def have_temp_compatible_access(self): 198 199 """ 200 Indicate whether the active instruction can be used in place of access 201 to a temporary variable retaining the result of the last instruction. 202 """ 203 204 # LoadResult cannot be relied upon in general since the result register 205 # could be updated since first being referenced. 206 207 return isinstance(self.translation.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst)) or \ 208 isinstance(self.translation.active_value, LoadResult) and self.translation.active_value is self.translation.active 209 210 def have_correct_self_for_target(self, context): 211 212 "Return whether the 'context' is compatible with the current value." 213 214 if context is not None and self.have_self_input(): 215 216 parent = self.translation.unit.parent 217 if parent is context or parent.has_subclass(context) or context.has_subclass(parent): 218 return 1 219 220 return 0 221 222 # Optimisation methods. See the supported_optimisations class attribute. 223 224 def optimise_constant_storage(self): 225 226 """ 227 Where the last operation stores a constant into a target which is also 228 constant, optimise away both operations. 229 """ 230 231 if self.should_optimise_constant_storage() and \ 232 self.have_constant_target() and \ 233 self.have_constant_source(): 234 235 self.translation.remove_op() 236 return 1 237 else: 238 return 0 239 240 def optimise_source_storage(self): 241 242 """ 243 Where the source value in an assignment can be inserted into the 244 eventual target without intermediate storage, optimise away the storage 245 instruction. 246 """ 247 248 if self.should_optimise_source_storage() and \ 249 self.translation.active_source is not None and \ 250 self.translation.active_source.source is None and \ 251 self.translation.active_source.input is None and \ 252 self.translation.active_source is self.translation.active: 253 254 self.translation.remove_op() 255 return 1 256 else: 257 return 0 258 259 def optimise_known_target(self): 260 261 """ 262 Where the target of an invocation is known, provide information about it 263 and its context. If a class is being invoked and the conditions are 264 appropriate, get information about the specific initialiser. 265 """ 266 267 if self.should_optimise_known_target() and self.have_known_target(): 268 last = self.translation.active_value 269 target = last.attr.value 270 context = last.attr.context 271 272 return target, context 273 else: 274 return None 275 276 def optimise_self_access(self, attrname, classes, node): 277 278 """ 279 Where the provided 'attrname' accesses an attribute which occupies the 280 same position in all possible objects which can be accessed, generate an 281 instruction using one of the given 'classes', accessing the attribute 282 directly. 283 """ 284 285 AddressInstruction, AddressContextInstruction, AttrInstruction = classes 286 287 if self.should_optimise_self_access() and self.have_self_input() and \ 288 not self.translation.unit.is_relocated(attrname): 289 290 # Either generate an instruction operating on an instance attribute. 291 292 try: 293 attr = self.translation.unit.parent.instance_attributes()[attrname] 294 self.translation.new_op(AttrInstruction(attr)) 295 296 # Or generate an instruction operating on a class attribute. 297 298 except KeyError: 299 attr = self.translation.unit.parent.all_attributes()[attrname] 300 301 # Switch the context if the class attribute is compatible with 302 # the instance. 303 304 if attr.defined_within_hierarchy(): 305 306 # Only permit loading (not storing) of class attributes via self. 307 308 if AddressContextInstruction is not None: 309 self.translation.new_op(AddressContextInstruction(attr)) 310 else: 311 raise TranslateError(self.translation.module.full_name(), node, 312 "Storing of class attribute %r via self not permitted." % attrname) 313 314 # Preserve the context if the class attribute comes from an 315 # incompatible class. 316 317 else: 318 if AddressInstruction is not None: 319 self.translation.new_op(AddressInstruction(attr)) 320 else: 321 raise TranslateError(self.translation.module.full_name(), node, 322 "Storing of class attribute %r via self not permitted." % attrname) 323 324 return 1 325 else: 326 return 0 327 328 def optimise_temp_storage(self): 329 330 """ 331 Where the next operation would involve storing a value into temporary 332 storage at 'temp_position', record and remove any simple instruction 333 which produced the value to be stored such that instead of subsequently 334 accessing the temporary storage, that instruction is substituted. 335 336 If no optimisation can be achieved, a StoreTemp instruction is produced 337 and the appropriate LoadTemp instruction is returned. 338 339 Restriction: for use only in situations where the source of the 340 temporary data will not be disturbed between its first access and its 341 subsequent use. 342 """ 343 344 if self.should_optimise_temp_storage() and \ 345 self.have_temp_compatible_access(): 346 347 removed = self.translation.active 348 self.translation.remove_active_value() 349 return removed 350 else: 351 return self.translation.get_temp() 352 353 def optimise_load_operations(self, instruction): 354 355 """ 356 Incorporate previous load operations into other operations. 357 """ 358 359 if self.should_optimise_load_operations() and \ 360 self.have_simple_input() and \ 361 self.is_simple_input_user(instruction): 362 363 self.translation.remove_active_value() 364 instruction.input = self.translation.active_value 365 366 def optimise_away_no_operations(self, instruction): 367 368 """ 369 Optimise away operations which just store their inputs in the place 370 the inputs originally came from. 371 """ 372 373 if self.should_optimise_away_no_operations() and \ 374 self.is_resultant_no_operation(instruction): 375 376 return 1 377 else: 378 return 0 379 380 def optimise_away_superfluous_temp_operations(self, instruction): 381 382 """ 383 Optimise away operations which just store temporary values for 384 immediate retrieval. 385 """ 386 387 if self.should_optimise_away_superfluous_temp_operations() and \ 388 self.is_superfluous_temp_operation(instruction) and \ 389 self.translation.active_source == self.translation.active: 390 391 instruction.source = self.translation.active_source.input 392 self.translation.remove_op() 393 394 def optimise_unused_results(self): 395 396 "Discard results which will not be used." 397 398 if self.have_simple_input(): 399 self.translation.remove_active_value() 400 401 # Program visitors. 402 403 class Translation(ASTVisitor): 404 405 "A translated module." 406 407 supported_optimisations = Optimiser.supported_optimisations 408 409 # Attribute access instructions, for use with the appropriate handlers. 410 411 attribute_load_instructions = (LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex) 412 attribute_store_instructions = (None, None, StoreAttr, StoreAttrIndex) 413 414 # Name access instructions, for use with the appropriate handlers. 415 416 name_load_instructions = (LoadName, LoadAddress) 417 name_store_instructions = (StoreName, StoreAddress) 418 419 def __init__(self, module, importer, optimisations=None): 420 421 """ 422 Initialise the translation with an inspected 'module', the 'importer' 423 and optional 'optimisations'. See the 'supported_optimisations' 424 attribute of this class for permitted values. 425 """ 426 427 ASTVisitor.__init__(self) 428 self.visitor = self 429 self.module = module 430 431 # Global program dependencies. 432 433 self.importer = importer 434 self.objtable = self.importer.get_object_table() 435 self.paramtable = self.importer.get_parameter_table() 436 self.builtins = self.importer.modules.get("__builtins__") 437 438 # Optimisation. 439 440 self.optimiser = Optimiser(self, optimisations) 441 442 # The current unit being translated. 443 444 self.unit = None 445 446 # The current "active" instruction. 447 # As a rule, this will become the last instruction, but some 448 # control-flow operations will flush the "active" instruction. 449 450 self.active = None 451 self.active_value = None 452 453 # The temporary storage used by the current assignment expression. 454 455 self.expr_temp = [] 456 457 # Wiring within the code. 458 459 self.labels = {} 460 self.label_number = 0 461 self.loop_labels = [] 462 self.exception_labels = [] 463 464 # The code itself. This is limited to the code for a particular block 465 # being processed. Also retained is information about temporary values 466 # and instructions which construct frames. 467 468 self.code = None 469 self.temp_positions = set() 470 self.max_temp_position = -1 471 self.frame_makers = [] 472 473 def __repr__(self): 474 return "Translation(%r)" % self.module 475 476 def get_module_code(self, final=0): 477 478 """ 479 Return the top-level module code including finalising code if 'final' is 480 set to a true value. 481 """ 482 483 self.unit = self.module 484 self.code = [] 485 self.temp_positions = set() 486 self.max_temp_position = -1 487 488 if self.module.module is not None: 489 self.dispatch(self.module.module) 490 491 # Finish off the translated program if appropriate. 492 493 if final: 494 self.new_op(Return()) 495 496 self.unit.temp_usage = self.max_temp_position + 1 497 return self.code 498 499 def get_code(self, unit): 500 501 "Return the code for the given 'unit'." 502 503 self.unit = unit 504 self.code = [] 505 self.temp_positions = set() 506 self.max_temp_position = -1 507 508 if unit.astnode is not None: 509 self.dispatch(unit.astnode) 510 511 self.unit.temp_usage = self.max_temp_position + 1 512 return self.code 513 514 def get_instantiator_code(self, cls): 515 516 "Return the code for the given class 'cls'." 517 518 self.unit = cls.get_instantiator() 519 self.code = [] 520 self.temp_positions = set() 521 self.max_temp_position = -1 522 523 init_method = cls.get_init_method() 524 525 # Convert this frame back to being an invocation frame. 526 527 self.new_op(RecoverFrame()) 528 529 # Fix the current frame to include a new storage slot at the beginning. 530 531 self.new_op(AdjustFrame(-1)) 532 533 # Make an object. 534 535 self.make_object(cls, len(cls.instance_attributes())) 536 self.new_op(StoreFrame(0)) 537 538 # Invoke the appropriate initialiser. 539 540 self.new_op(LoadConst(init_method)) 541 self.new_op(LoadCallable()) 542 self.new_op(JumpWithFrame()) 543 544 # Store the object as the result. 545 546 self.new_op(LoadName(init_method.all_locals()["self"])) # load the context in the invocation frame 547 self.new_op(StoreResult()) 548 self.new_op(Return()) 549 550 return self.code 551 552 # Allocation-related methods. 553 554 def make_object(self, cls, n): 555 556 """ 557 Request a new object with the given class 'cls' and with 'n' attributes. 558 """ 559 560 # NOTE: Object headers are one location. 561 562 self.new_op(LoadConst(cls)) 563 self.new_op(MakeObject(n + 1)) 564 565 # Name-related methods. 566 567 def get_scope(self, name): 568 569 "Return the scope for the given 'name'." 570 571 if self.unit.has_key(name): 572 return "local" 573 elif self.module.has_key(name): 574 return "global" 575 else: 576 return "builtins" 577 578 def load_builtin(self, name, node): 579 580 "Generate an instruction loading 'name' for the given 'node'." 581 582 self.new_op(LoadAddress(self.get_builtin(name, node))) 583 584 def get_builtin_class(self, name, node): 585 return self.get_builtin(name, node).value 586 587 def get_builtin(self, name, node): 588 589 """ 590 Return the built-in module definition for the given 'name', used by the 591 given 'node'. 592 """ 593 594 if self.builtins is not None: 595 try: 596 return self.builtins[name] 597 except KeyError: 598 raise TranslateError(self.module.full_name(), node, "No __builtins__ definition is available for name %r." % name) 599 else: 600 raise TranslateError(self.module.full_name(), node, "No __builtins__ module is available for name %r." % name) 601 602 # Code feature methods. 603 604 def new_label(self): 605 606 "Return a new label object for use with set_label." 607 608 number = self.label_number 609 label = Label(number) 610 self.labels[label] = label 611 self.label_number += 1 612 return label 613 614 def set_label(self, label): 615 616 """ 617 Set the location of 'label' to that within the entire image: the 618 location within the code combined with location of the code unit. 619 """ 620 621 label.location = len(self.code) + self.unit.code_location 622 623 def get_loop_labels(self): 624 return self.loop_labels[-1] 625 626 def add_loop_labels(self, next_label, exit_label): 627 self.loop_labels.append((next_label, exit_label)) 628 629 def drop_loop_labels(self): 630 self.loop_labels.pop() 631 632 def get_exception_labels(self): 633 return self.exception_labels[-1] 634 635 def add_exception_labels(self, handler_label, exit_label): 636 self.exception_labels.append((handler_label, exit_label)) 637 638 def drop_exception_labels(self): 639 self.exception_labels.pop() 640 641 # Assignment expression values. 642 643 def record_value(self): 644 self.expr_temp.append(self.get_temp()) 645 self.active_source = self.active 646 647 def discard_value(self): 648 self.discard_temp(self.expr_temp.pop()) 649 self.active_source = None 650 651 def set_source(self): 652 if self.active is not None: 653 self.active.source = self.expr_temp[-1] 654 655 # Optimise away constant storage if appropriate. 656 657 self.optimiser.optimise_constant_storage() 658 659 # Temporary storage administration. 660 661 def get_temp(self): 662 663 """ 664 Add a temporary storage instruction for the current value and return a 665 sequence of access instructions. 666 """ 667 668 position_in_frame = self.reserve_temp() 669 self.new_op(StoreTemp(position_in_frame)) 670 return LoadTemp(position_in_frame) 671 672 def reserve_temp(self): 673 if not self.temp_positions: 674 temp_position = 0 675 else: 676 temp_position = max(self.temp_positions) + 1 677 self.temp_positions.add(temp_position) 678 self.max_temp_position = max(self.max_temp_position, temp_position) 679 return self.unit.all_local_usage + temp_position # position in frame 680 681 def discard_temp(self, instruction=None): 682 if isinstance(instruction, LoadTemp): 683 temp_position = instruction.attr - self.unit.all_local_usage 684 self.free_temp(temp_position) 685 686 def free_temp(self, temp_position): 687 if temp_position in self.temp_positions: 688 self.temp_positions.remove(temp_position) 689 690 def set_frame_usage(self, node, extend): 691 extend.attr = self.max_temp_position + node.unit.local_usage # NOTE: See get_code for similar code. 692 693 # Code writing methods. 694 695 def new_op(self, op): 696 697 "Add 'op' to the generated code." 698 699 # Optimise load operations employed by this instruction. 700 701 self.optimiser.optimise_load_operations(op) 702 if self.optimiser.optimise_away_no_operations(op): 703 return 704 self.optimiser.optimise_away_superfluous_temp_operations(op) 705 706 self.code.append(op) 707 self.active = op 708 709 # Record specific types of instructions for optimisation. 710 711 if isinstance(op, current_value_instructions): 712 self.active_value = op 713 714 def remove_op(self): 715 716 "Remove the last instruction." 717 718 op = self.code.pop() 719 self.active = None 720 721 def remove_active_value(self): 722 723 "Remove the value-providing active instruction if appropriate." 724 725 if self.active_value is self.active: 726 self.remove_op() 727 728 def replace_op(self, op): 729 730 "Replace the last added instruction with 'op'." 731 732 self.remove_op() 733 self.new_op(op) 734 735 def replace_active_value(self, op): 736 737 """ 738 Replace the value-providing active instruction with 'op' if appropriate. 739 """ 740 741 self.remove_active_value() 742 self.new_op(op) 743 744 def last_op(self): 745 746 "Return the last added instruction." 747 748 try: 749 return self.code[-1] 750 except IndexError: 751 return None 752 753 def clear_active(self): 754 755 "Prevent incorrect optimisation." 756 757 self.active = None 758 self.active_value = None 759 self.active_source = None 760 761 # Visitor methods. 762 763 def default(self, node, *args): 764 raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__) 765 766 def dispatch(self, node, *args): 767 return ASTVisitor.dispatch(self, node, *args) 768 769 # Internal helper methods. 770 771 def _visitAttr(self, node, classes): 772 773 """ 774 Visit the attribute-related 'node', generating instructions based on the 775 given 'classes'. 776 """ 777 778 self.dispatch(node.expr) 779 self._generateAttr(node, node.attrname, classes) 780 781 def _generateAttr(self, node, attrname, classes): 782 783 """ 784 Generate code for the access to 'attrname' using the given 'classes'. 785 """ 786 787 AddressInstruction, AddressContextInstruction, AttrInstruction, AttrIndexInstruction = classes 788 789 # Where the last operation (defining the attribute owner) yields a 790 # constant... 791 792 if self.optimiser.have_constant_input(): 793 last = self.active_value 794 795 # Get the details of the access. 796 797 if isinstance(last.attr, Const): 798 target_name = last.attr.value_type_name() 799 else: 800 target = last.attr.value 801 802 if isinstance(target, Const): 803 target_name = target.value_type_name() 804 elif isinstance(target, Instance): 805 target_name = None # skip production of optimised code 806 else: 807 target_name = target.full_name() 808 809 # Only try and discover the position if the target can be resolved. 810 811 if target_name is not None: 812 813 # Access the object table to get the attribute position. 814 815 try: 816 table_entry = self.objtable.table[target_name] 817 except KeyError: 818 raise TranslateError(self.module.full_name(), node, 819 "No object entry exists for target %r." % target_name) 820 821 try: 822 pos = table_entry[attrname] 823 except KeyError: 824 raise TranslateError(self.module.full_name(), node, 825 "No attribute entry exists for name %r in target %r." % (attrname, target_name)) 826 827 # Produce a suitable instruction. 828 829 if AddressInstruction is not None: 830 self.replace_active_value(AddressInstruction(pos)) 831 else: 832 raise TranslateError(self.module.full_name(), node, 833 "Storing of class or module attribute %r via an object is not permitted." % attrname) 834 835 return 836 837 # Where the last operation involves the special 'self' name, check to 838 # see if the attribute is acceptably positioned and produce a direct 839 # access to the attribute. 840 841 elif self.optimiser.optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction), node): 842 return 843 844 # Otherwise, perform a normal operation. 845 846 try: 847 index = self.objtable.get_index(attrname) 848 except self.objtable.TableError: 849 raise TranslateError(self.module.full_name(), node, 850 "No attribute entry exists for name %r." % attrname) 851 852 self.new_op(AttrIndexInstruction(index)) 853 854 # Invocations involve the following: 855 # 856 # 1. Reservation of a frame for the arguments 857 # 2. Identification of the target which is then held in temporary storage 858 # 3. Optional inclusion of a context (important for methods) 859 # 4. Preparation of the argument frame 860 # 5. Invocation of the target 861 # 6. Discarding of the frame 862 # 863 # In order to support nested invocations - eg. a(b(c)) - use of the 864 # temporary storage is essential. 865 866 def _startCallFunc(self): 867 868 "Record the location of the invocation." 869 870 op = MakeFrame() 871 self.new_op(op) # records the start of the frame 872 self.frame_makers.append(op) 873 874 def _generateCallFunc(self, args, node): 875 876 """ 877 Support a generic function invocation using the given 'args', occurring 878 on the given 'node', where the expression providing the invocation 879 target has just been generated. 880 881 In other situations, the invocation is much simpler and does not need to 882 handle the full flexibility of a typical Python invocation. Internal 883 invocations, such as those employed by operators and certain 884 control-flow mechanisms, use predetermined arguments and arguably do not 885 need to support the same things as the more general invocations. 886 """ 887 888 target, context, temp = self._generateCallFuncContext() 889 self._generateCallFuncArgs(target, context, temp, args, node) 890 return temp, target 891 892 def _generateCallFuncContext(self): 893 894 """ 895 Produce code which loads and checks the context of the current 896 invocation, the instructions for whose target have already been 897 produced, returning a list of instructions which reference the 898 invocation target. 899 """ 900 901 t = self.optimiser.optimise_known_target() 902 if t: 903 target, context = t 904 else: 905 target, context = None, None 906 907 # Store the target in temporary storage for subsequent referencing. 908 # NOTE: This may not be appropriate for class invocations 909 # NOTE: (instantiation). 910 911 temp = self.optimiser.optimise_temp_storage() 912 913 # Where a target or context are not known or where an instance is known 914 # to be the context, load the context. 915 916 if target is None or isinstance(context, Instance): 917 self.new_op(temp) 918 self.new_op(LoadContext()) 919 self.new_op(StoreFrame(0)) 920 921 # For known instantiations, provide a new object as the first argument 922 # to the __init__ method. 923 924 elif isinstance(target, Class): 925 self.make_object(target, len(target.instance_attributes())) 926 self.new_op(StoreFrame(0)) 927 928 # Otherwise omit the context. 929 930 else: 931 pass # NOTE: Class methods should be supported. 932 933 return target, context, temp 934 935 def _generateCallFuncArgs(self, target, context, temp, args, node): 936 937 """ 938 Given invocation 'target' and 'context' information, the 'temp' 939 reference to the target, a list of nodes representing the 'args' 940 (arguments), generate instructions which load the arguments for the 941 invocation defined by the given 'node'. 942 """ 943 944 # Evaluate the arguments. 945 946 employed_positions = set() 947 employed_keywords = set() 948 extra_keywords = [] 949 950 # Find keyword arguments in advance in order to help resolve targets. 951 952 for arg in args: 953 if isinstance(arg, compiler.ast.Keyword): 954 employed_keywords.add(arg.name) 955 956 possible_targets = self.paramtable.all_possible_objects(employed_keywords) 957 958 # Note the presence of the context in the frame where appropriate. 959 960 if target is None or isinstance(context, Instance): 961 ncontext = 1 962 expect_context = 0 963 964 # Handle calls to classes. 965 966 elif isinstance(target, Class): 967 ncontext = 1 968 expect_context = 0 969 target = target.get_init_method() 970 971 # Method calls via classes. 972 973 elif isinstance(context, Class): 974 ncontext = 0 975 expect_context = 1 976 977 # Function calls. 978 979 else: 980 ncontext = 0 981 expect_context = 0 982 983 first = 1 984 frame_pos = ncontext 985 max_keyword_pos = -1 986 987 for arg in args: 988 989 # Handle positional and keyword arguments separately. 990 991 if isinstance(arg, compiler.ast.Keyword): 992 993 # Optimise where the target is known now. 994 995 if target is not None: 996 997 # Find the parameter table entry for the target. 998 999 target_name = target.full_name() 1000 1001 # Look for a callable with the precise target name. 1002 1003 table_entry = self.paramtable.table[target_name] 1004 1005 # Look the name up in the parameter table entry. 1006 1007 try: 1008 pos = table_entry[arg.name] 1009 1010 # Where no position is found, this could be an extra keyword 1011 # argument. 1012 1013 except KeyError: 1014 extra_keywords.append(arg) 1015 continue 1016 1017 # Test for illegal conditions. 1018 1019 if pos in employed_positions: 1020 raise TranslateError(self.module.full_name(), node, 1021 "Keyword argument %r overwrites parameter %r." % (arg.name, pos)) 1022 1023 employed_positions.add(pos) 1024 1025 # Generate code for the keyword and the positioning 1026 # operation. 1027 1028 self.dispatch(arg.expr) 1029 self.new_op(StoreFrame(pos)) 1030 1031 # Otherwise, generate the code needed to obtain the details of 1032 # the parameter location. 1033 1034 else: 1035 1036 # Combine the target details with the name to get the location. 1037 # See the access method on the List class. 1038 1039 try: 1040 paramindex = self.paramtable.get_index(arg.name) 1041 1042 # Where no position is found, this could be an extra keyword 1043 # argument. 1044 1045 except self.paramtable.TableError: 1046 extra_keywords.append(arg) 1047 continue 1048 1049 # Generate code for the keyword and the positioning 1050 # operation. 1051 1052 self.dispatch(arg.expr) 1053 self.new_op(StoreFrameIndex(paramindex)) 1054 1055 # use (callable+0)+paramindex+table 1056 # checks embedded offset against (callable+0) 1057 # moves the current value to frame+position 1058 1059 # Record the highest possible frame position for this argument. 1060 1061 max_keyword_pos = max(max_keyword_pos, max(self.paramtable.all_attribute_positions(arg.name))) 1062 1063 else: 1064 self.dispatch(arg) 1065 self.new_op(StoreFrame(frame_pos)) 1066 1067 employed_positions.add(frame_pos) 1068 1069 # Check to see if the first argument is appropriate (compatible with 1070 # the target where methods are being invoked via classes). 1071 1072 if first and expect_context: 1073 1074 # Drop any test if the target and the context are known. 1075 1076 if not self.optimiser.have_correct_self_for_target(context): 1077 1078 continue_label = self.new_label() 1079 self.new_op(CheckSelf()) 1080 self.active.source = temp 1081 self.new_op(JumpIfTrue(continue_label)) 1082 1083 # Where the context is inappropriate, drop the incomplete frame and 1084 # raise an exception. 1085 1086 self.new_op(DropFrame()) 1087 self.new_op(LoadResult()) 1088 1089 self.load_builtin("TypeError", node) 1090 self.new_op(StoreException()) 1091 self.new_op(RaiseException()) 1092 self.set_label(continue_label) 1093 1094 first = 0 1095 frame_pos += 1 1096 1097 # NOTE: Extra keywords are not supported. 1098 # NOTE: Somehow, the above needs to be combined with * arguments. 1099 1100 if extra_keywords: 1101 print "Warning: extra keyword argument(s) %s not handled." % ", ".join([arg.name for arg in extra_keywords]) 1102 1103 # Either test for a complete set of arguments. 1104 1105 if target is not None: 1106 1107 # Make sure that enough arguments have been given. 1108 1109 nargs_max = len(target.positional_names) 1110 ndefaults = len(target.defaults) 1111 nargs_min = nargs_max - ndefaults 1112 1113 for i in range(ncontext, nargs_min): 1114 if i not in employed_positions: 1115 raise TranslateError(self.module.full_name(), node, 1116 "Argument %r not supplied for %r: need at least %d argument(s)." % (i+1, target.name, nargs_min)) 1117 1118 nargs = frame_pos 1119 1120 if nargs > nargs_max and not target.has_star and not target.has_dstar: 1121 raise TranslateError(self.module.full_name(), node, 1122 "Too many arguments for %r: need at most %d argument(s)." % (target.name, nargs_max)) 1123 1124 # Where defaults are involved, put them into the frame. 1125 1126 self._generateCallFuncDefaultArgs(target, temp, nargs_min, nargs_max, employed_positions) 1127 1128 # Set the frame size. 1129 1130 self._endCallFuncArgs(nargs_max) 1131 1132 # Or generate instructions to do this at run-time. 1133 # NOTE: CheckFrame has to check the number of arguments and to fill in 1134 # NOTE: defaults; it also has to shift the invocation frame according to 1135 # NOTE: the context in use. 1136 1137 else: 1138 max_pos = max(max(employed_positions or [-1]), max_keyword_pos, frame_pos - 1) 1139 1140 # Only check non-empty frames (using the callable's details). 1141 1142 if employed_positions or max_pos >= 0: 1143 self.new_op(temp) 1144 self.new_op(CheckFrame(max_pos + 1)) 1145 1146 # Set the frame size. 1147 1148 self._endCallFuncArgs(max_pos + 1) 1149 1150 def _generateCallFuncDefaultArgs(self, target, temp, nargs_min, nargs_max, employed_positions): 1151 1152 """ 1153 For the given 'target' and 'temp' reference to the target, generate 1154 default arguments for those positions in the range 'nargs_min'... 1155 'nargs_max' which are not present in the 'employed_positions' 1156 collection. 1157 """ 1158 1159 # Where a lambda is involved, construct a dynamic object to hold the 1160 # defaults. 1161 1162 dynamic = target.name is None 1163 1164 # Here, we use negative index values to visit the right hand end of 1165 # the defaults list. 1166 1167 for pos in range(nargs_min, nargs_max): 1168 if pos not in employed_positions: 1169 if dynamic: 1170 self.new_op(temp) 1171 self.new_op(LoadAttr(target.default_attrs[pos - nargs_min])) 1172 else: 1173 self.new_op(LoadAddress(target.default_attrs[pos - nargs_min])) 1174 self.new_op(StoreFrame(pos)) 1175 1176 def _doCallFunc(self, instruction, target=None): 1177 1178 "Make the invocation." 1179 1180 if isinstance(target, Class): 1181 self.new_op(LoadConst(target.get_init_method())) 1182 else: 1183 self.new_op(instruction) 1184 self.new_op(LoadCallable()) 1185 self.new_op(JumpWithFrame()) 1186 1187 def _endCallFuncArgs(self, nargs): 1188 1189 "Set the frame size." 1190 1191 self.frame_makers[-1].attr = nargs 1192 self.frame_makers.pop() 1193 1194 def _endCallFunc(self, instruction=None, target=None, load_result=1): 1195 1196 "Finish the invocation and tidy up afterwards." 1197 1198 if isinstance(target, Class): 1199 self.new_op(LoadName(target.get_init_method().all_locals()["self"])) # load the context in the invocation frame 1200 self.new_op(StoreResult()) 1201 self.new_op(DropFrame()) 1202 if load_result: 1203 self.new_op(LoadResult()) 1204 1205 # Discard any temporary storage instructions. 1206 1207 if instruction is not None: 1208 self.discard_temp(instruction) 1209 1210 def _generateFunctionDefaults(self, function): 1211 1212 """ 1213 Generate the default initialisation code for 'function', returning 1214 a temporary storage reference if a dynamic object was created for the 1215 function. 1216 """ 1217 1218 attr_to_default = zip(function.default_attrs, function.defaults) 1219 if not attr_to_default: 1220 return None 1221 1222 # Where a lambda is involved, construct a dynamic object to hold the 1223 # defaults. 1224 1225 dynamic = function.name is None 1226 1227 if dynamic: 1228 self.make_object(self.get_builtin_class("function", function), len(attr_to_default)) 1229 temp = self.get_temp() 1230 1231 for attr, default in attr_to_default: 1232 self.dispatch(default) 1233 1234 self.record_value() 1235 if dynamic: 1236 self.new_op(temp) 1237 self.new_op(StoreAttr(attr)) 1238 else: 1239 self.new_op(StoreAddress(attr)) 1240 self.set_source() 1241 self.discard_value() 1242 1243 if dynamic: 1244 return temp 1245 else: 1246 return None 1247 1248 def _visitName(self, node, classes): 1249 1250 """ 1251 Visit the name-related 'node', generating instructions based on the 1252 given 'classes'. 1253 """ 1254 1255 name = node.name 1256 scope = self.get_scope(name) 1257 #print self.module.name, node.lineno, name, scope 1258 self._generateName(name, scope, classes, node) 1259 1260 def _generateName(self, name, scope, classes, node): 1261 1262 """ 1263 Generate code for the access to 'name' in 'scope' using the given 1264 'classes', and using the given 'node' as the source of the access. 1265 """ 1266 1267 NameInstruction, AddressInstruction = classes 1268 1269 if scope == "local": 1270 unit = self.unit 1271 if isinstance(unit, Function): 1272 self.new_op(NameInstruction(unit.all_locals()[name])) 1273 elif isinstance(unit, Class): 1274 self.new_op(AddressInstruction(unit.all_class_attributes()[name])) 1275 elif isinstance(unit, Module): 1276 self.new_op(AddressInstruction(unit.module_attributes()[name])) 1277 else: 1278 raise TranslateError(self.module.full_name(), node, "Program unit %r has no local %r." % (unit, name)) 1279 1280 elif scope == "global": 1281 globals = self.module.module_attributes() 1282 if globals.has_key(name): 1283 self.new_op(AddressInstruction(globals[name])) 1284 else: 1285 raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r." % (self.module, name)) 1286 1287 else: 1288 self.new_op(AddressInstruction(self.get_builtin(name, node))) 1289 1290 def _visitUnary(self, node, method): 1291 1292 """ 1293 _t = node.expr 1294 try: 1295 _result = _t.__pos__() 1296 except AttributeError: 1297 raise TypeError 1298 """ 1299 1300 end_call_label = self.new_label() 1301 end_label = self.new_label() 1302 1303 # Evaluate and store the operand in temporary storage. 1304 1305 self.dispatch(node.expr) 1306 temp = self.optimiser.optimise_temp_storage() 1307 1308 # Produce the invocation. 1309 1310 self._startCallFunc() 1311 self.new_op(temp) 1312 1313 # Get the method on temp. 1314 1315 self._generateAttr(node, method, self.attribute_load_instructions) 1316 temp_method = self.optimiser.optimise_temp_storage() 1317 1318 self._handleAttributeError(node, end_call_label) 1319 1320 # Add arguments. 1321 # NOTE: No support for defaults. 1322 1323 self.new_op(temp) # Explicit context as first argument. 1324 self.new_op(StoreFrame(0)) 1325 self._endCallFuncArgs(1) 1326 self._doCallFunc(temp_method) 1327 self._endCallFunc(temp_method) 1328 self.new_op(Jump(end_label)) 1329 1330 # End method attempt. 1331 1332 self.set_label(end_call_label) 1333 self._endCallFunc() # From the method call. 1334 1335 # Raise a TypeError. 1336 1337 self.load_builtin("TypeError", node) 1338 self.new_op(StoreException()) 1339 self.new_op(RaiseException()) 1340 1341 self.set_label(end_label) 1342 1343 # Compilation duties... 1344 1345 self.discard_temp(temp) 1346 1347 def _visitBinary(self, node, left_method, right_method): 1348 1349 """ 1350 _t1 = node.left 1351 _t2 = node.right 1352 try: 1353 _result = _t1.__add__(_t2) 1354 if _result is NotImplemented: 1355 raise AttributeError 1356 except AttributeError: 1357 try: 1358 _result = _t2.__radd__(_t1) 1359 if _result is NotImplemented: 1360 raise AttributeError 1361 except AttributeError: 1362 raise TypeError 1363 """ 1364 1365 # Evaluate and store the left operand in temporary storage. 1366 1367 self.dispatch(node.left) 1368 temp1 = self.optimiser.optimise_temp_storage() 1369 1370 # Evaluate and store the right operand in temporary storage. 1371 1372 self.dispatch(node.right) 1373 temp2 = self.optimiser.optimise_temp_storage() 1374 1375 self._generateBinary(node, temp1, temp2, left_method, right_method) 1376 1377 # Compilation duties... 1378 1379 self.discard_temp(temp1) 1380 self.discard_temp(temp2) 1381 1382 def _generateBinary(self, node, temp1, temp2, left_method, right_method): 1383 1384 """ 1385 For the given 'node', generate the binary operator pattern for the 1386 operands 'temp1' and 'temp2', employing 'left_method' and 'right_method' 1387 as defined for binary operators, but also used in comparisons (for which 1388 this method is provided). 1389 """ 1390 1391 right_label = self.new_label() 1392 type_error_label = self.new_label() 1393 end_label = self.new_label() 1394 1395 # Left method. 1396 1397 self._generateOpMethod(node, temp1, temp2, left_method, right_label, end_label) 1398 1399 # Right method. 1400 1401 self.set_label(right_label) 1402 self._generateOpMethod(node, temp2, temp1, right_method, type_error_label, end_label) 1403 1404 # Raise a TypeError. 1405 1406 self.set_label(type_error_label) 1407 self.load_builtin("TypeError", node) 1408 self.new_op(StoreException()) 1409 self.new_op(RaiseException()) 1410 1411 self.set_label(end_label) 1412 1413 def _generateOpMethod(self, node, temp1, temp2, method_name, next_method_label, end_label): 1414 1415 """ 1416 For the given 'node', generate the operator method invocation using the 1417 operands 'temp1' and 'temp2', employing the given 'method_name', and 1418 jumping appropriately to 'next_method_label' where a NotImplemented 1419 result is returned, or to 'end_label' if the method call was successful. 1420 """ 1421 1422 end_attempt_label = self.new_label() 1423 1424 self.new_op(temp1) 1425 1426 # Get method on temp1. 1427 1428 self._generateAttr(node, method_name, self.attribute_load_instructions) 1429 temp_method = self.optimiser.optimise_temp_storage() 1430 1431 self._handleAttributeError(node, end_attempt_label) 1432 1433 # Add arguments. 1434 # NOTE: No support for defaults. 1435 1436 self._startCallFunc() 1437 self.new_op(temp1) 1438 self.new_op(StoreFrame(0)) 1439 self.new_op(temp2) 1440 self.new_op(StoreFrame(1)) 1441 self._endCallFuncArgs(2) 1442 self._doCallFunc(temp_method) 1443 self._endCallFunc(temp_method) 1444 1445 # Test for NotImplemented. 1446 # Don't actually raise an exception. 1447 1448 self.new_op(TestIdentityAddress(self.get_builtin("NotImplemented", node))) 1449 self.new_op(JumpIfTrue(next_method_label)) 1450 self.new_op(Jump(end_label)) 1451 1452 # End method attempt. 1453 1454 self.set_label(end_attempt_label) 1455 1456 def _handleAttributeError(self, node, end_call_label): 1457 1458 """ 1459 Add exception handling to the method acquisition instructions where the 1460 attribute access cannot be resolved at compile-time. 1461 """ 1462 1463 if not self.optimiser.optimise_known_target(): 1464 self.load_builtin("AttributeError", node) 1465 self.new_op(CheckException()) 1466 self.new_op(JumpIfTrue(end_call_label)) 1467 1468 def _generateSequence(self, sequence_type, node): 1469 1470 "Make a sequence of 'sequence_type' for the given program 'node'." 1471 1472 self.make_object(self.get_builtin(sequence_type, node), len(node.nodes)) 1473 temp = self.get_temp() 1474 1475 for i, n in enumerate(node.nodes): 1476 self.dispatch(n) 1477 self.record_value() 1478 self.new_op(temp) 1479 self.new_op(StoreAttr(Attr(i, None, None, None))) 1480 self.set_source() 1481 self.discard_value() 1482 1483 self.new_op(temp) 1484 self.discard_temp(temp) 1485 1486 def _generateTestBoolean(self, node, temp): 1487 1488 """ 1489 Generate a test of the boolean status of the current value for the given 1490 program 'node'. 1491 """ 1492 1493 # Get method on temp. 1494 # NOTE: Using __bool__ instead of __nonzero__. 1495 1496 self._generateAttr(node, "__bool__", self.attribute_load_instructions) 1497 temp_method = self.optimiser.optimise_temp_storage() 1498 1499 self._startCallFunc() 1500 self.new_op(temp) 1501 self.new_op(StoreFrame(0)) 1502 self._endCallFuncArgs(1) 1503 self._doCallFunc(temp_method) 1504 self._endCallFunc(temp_method) 1505 1506 self.discard_temp(temp_method) 1507 1508 # Convert result to boolean (a StoreBoolean operation). 1509 1510 self.new_op(TestIdentityAddress(self.get_builtin("True", node))) 1511 1512 def _generateLoadBoolean(self, node): 1513 1514 """ 1515 Generate instructions to load the appropriate value given the current 1516 boolean status. 1517 """ 1518 1519 true_label = self.new_label() 1520 end_label = self.new_label() 1521 1522 self.new_op(JumpIfTrue(true_label)) 1523 self.load_builtin("False", node) 1524 self.new_op(Jump(end_label)) 1525 1526 self.set_label(true_label) 1527 self.load_builtin("True", node) 1528 1529 self.set_label(end_label) 1530 1531 # Concrete visitor methods. 1532 1533 def visitAdd(self, node): 1534 self._visitBinary(node, "__add__", "__radd__") 1535 1536 def visitAnd(self, node): 1537 end_label = self.new_label() 1538 temp_pos = self.reserve_temp() 1539 temp = LoadTemp(temp_pos) 1540 1541 for n in node.nodes[:-1]: 1542 self.dispatch(n) 1543 self.new_op(StoreTemp(temp_pos)) 1544 1545 self._generateTestBoolean(n, temp) 1546 self.new_op(JumpIfFalse(end_label)) 1547 1548 self.dispatch(node.nodes[-1]) 1549 self.new_op(StoreTemp(temp_pos)) 1550 1551 self.set_label(end_label) 1552 1553 # Prevent incorrect optimisation. 1554 1555 self.clear_active() 1556 1557 self.new_op(temp) 1558 self.discard_temp(temp) 1559 1560 def visitAssert(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Assert") 1561 1562 def visitAssign(self, node): 1563 self.dispatch(node.expr) 1564 self.record_value() 1565 1566 for n in node.nodes: 1567 self.dispatch(n, 1) 1568 1569 self.discard_value() 1570 1571 def visitAssAttr(self, node, top_level=0): 1572 self._visitAttr(node, self.attribute_store_instructions) 1573 self.set_source() 1574 1575 def visitAssList(self, node, top_level=1): 1576 for i, n in enumerate(node.nodes): 1577 self._startCallFunc() 1578 self.new_op(self.expr_temp[-1]) 1579 self._generateAttr(node, "__getitem__", self.attribute_load_instructions) 1580 temp, target = self._generateCallFunc([compiler.ast.Const(i)], node) 1581 self._doCallFunc(temp, target) 1582 self._endCallFunc(temp, target) 1583 1584 # Provide a different source value. 1585 1586 self.record_value() 1587 self.dispatch(n, 0) 1588 self.discard_value() 1589 1590 def visitAssName(self, node, top_level=1): 1591 1592 # Optimise away intermediate source storage. 1593 1594 if top_level: 1595 no_source = self.optimiser.optimise_source_storage() 1596 self._visitName(node, self.name_store_instructions) 1597 if not top_level or not no_source: 1598 self.set_source() 1599 1600 visitAssTuple = visitAssList 1601 1602 def visitAugAssign(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "AugAssign") 1603 1604 def visitBackquote(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Backquote") 1605 1606 def visitBitand(self, node): 1607 self._visitBinary(node, "__and__", "__rand__") 1608 1609 def visitBitor(self, node): 1610 self._visitBinary(node, "__or__", "__ror__") 1611 1612 def visitBitxor(self, node): 1613 self._visitBinary(node, "__xor__", "__rxor__") 1614 1615 def visitBreak(self, node): 1616 next_label, exit_label = self.get_loop_labels() 1617 self.new_op(Jump(exit_label)) 1618 1619 def visitCallFunc(self, node): 1620 1621 """ 1622 Evaluate positional arguments, evaluate and store keyword arguments in 1623 the correct location, then invoke the function. 1624 """ 1625 1626 # Mark the frame, evaluate the target, generate the call. 1627 1628 self._startCallFunc() 1629 self.dispatch(node.node) 1630 temp, target = self._generateCallFunc(node.args, node) 1631 self._doCallFunc(temp, target) 1632 self._endCallFunc(temp, target) 1633 1634 def visitClass(self, node): 1635 1636 # Store the name. 1637 1638 self.new_op(LoadConst(node.unit)) 1639 self.record_value() 1640 self._visitName(node, self.name_store_instructions) 1641 self.set_source() 1642 self.discard_value() 1643 1644 # Visit the code. 1645 1646 unit = self.unit 1647 self.unit = node.unit 1648 self.unit.code_location = self.module.code_location # class body code is not independently addressable 1649 self.dispatch(node.code) 1650 self.unit = unit 1651 1652 def visitCompare(self, node): 1653 1654 """ 1655 _t1 = node.expr 1656 _t1 op1 _t2 and _t2 op2 _t3 and ... 1657 """ 1658 1659 end_label = self.new_label() 1660 temp_pos = self.reserve_temp() 1661 temp_result = LoadTemp(temp_pos) 1662 1663 self.dispatch(node.expr) 1664 temp2 = self.optimiser.optimise_temp_storage() 1665 1666 last_op = node.ops[-1] 1667 1668 for op in node.ops: 1669 op_name, next_node = op 1670 methods = self.comparison_methods[op_name] 1671 1672 temp1 = temp2 1673 self.dispatch(next_node) 1674 temp2 = self.optimiser.optimise_temp_storage() 1675 1676 # Use the appropriate mechanism, setting the boolean status for the 1677 # comparison. 1678 1679 if methods is not None: 1680 left_method, right_method = methods 1681 1682 # Generate method call using evaluated argument and next node. 1683 1684 self._generateBinary(node, temp1, temp2, left_method, right_method) 1685 self.new_op(StoreTemp(temp_pos)) 1686 self._generateTestBoolean(node, temp_result) 1687 1688 else: 1689 # Deal with the special operators. 1690 1691 if op_name.startswith("is"): 1692 self.new_op(temp1) 1693 self.record_value() 1694 self.new_op(temp2) 1695 self.new_op(TestIdentity()) 1696 self.set_source() 1697 self.discard_value() 1698 1699 elif op_name.endswith("in"): 1700 self._startCallFunc() 1701 self.new_op(temp2) 1702 1703 # Get method on temp2. 1704 1705 self._generateAttr(node, "__contains__", self.attribute_load_instructions) 1706 temp_method = self.optimiser.optimise_temp_storage() 1707 1708 # Add arguments. 1709 # NOTE: No support for defaults. 1710 1711 self.new_op(temp2) 1712 self.new_op(StoreFrame(0)) 1713 self.new_op(temp1) 1714 self.new_op(StoreFrame(1)) 1715 self._endCallFuncArgs(2) 1716 self._doCallFunc(temp_method) 1717 self._endCallFunc(temp_method) 1718 1719 self.new_op(StoreTemp(temp_pos)) 1720 self._generateTestBoolean(node, temp_result) 1721 1722 if op_name.find("not") != -1: 1723 self.new_op(InvertBoolean()) 1724 1725 # Test the result and jump to the end label if false. 1726 1727 if op is not last_op: 1728 self.new_op(JumpIfFalse(end_label)) 1729 1730 # Compilation duties... 1731 1732 self.discard_temp(temp1) 1733 1734 self.discard_temp(temp2) 1735 self.discard_temp(temp_result) 1736 self.set_label(end_label) 1737 1738 # Yield the appropriate value. 1739 1740 self._generateLoadBoolean(node) 1741 1742 def visitConst(self, node): 1743 const = self.module.constant_values[node.value] 1744 self.new_op(LoadConst(const)) 1745 1746 def visitContinue(self, node): 1747 next_label, exit_label = self.get_loop_labels() 1748 self.new_op(Jump(next_label)) 1749 1750 def visitDecorators(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Decorators") 1751 1752 def visitDict(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Dict") 1753 1754 def visitDiscard(self, node): 1755 self.dispatch(node.expr) 1756 self.optimiser.optimise_unused_results() 1757 1758 def visitDiv(self, node): 1759 self._visitBinary(node, "__div__", "__rdiv__") 1760 1761 def visitEllipsis(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Ellipsis") 1762 1763 def visitExec(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Exec") 1764 1765 def visitExpression(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Expression") 1766 1767 def visitFloorDiv(self, node): 1768 self._visitBinary(node, "__floordiv__", "__rfloordiv__") 1769 1770 def visitFor(self, node): 1771 exit_label = self.new_label() 1772 next_label = self.new_label() 1773 else_label = self.new_label() 1774 1775 # Get the "list" to be iterated over, obtain its iterator. 1776 1777 self._startCallFunc() 1778 self.dispatch(node.list) 1779 self._generateAttr(node, "__iter__", self.attribute_load_instructions) 1780 temp, target = self._generateCallFunc([], node) 1781 self._doCallFunc(temp, target) 1782 self._endCallFunc(temp, target) 1783 1784 temp_iterator = self.optimiser.optimise_temp_storage() 1785 1786 # In the loop... 1787 1788 self.set_label(next_label) 1789 1790 # Use the iterator to get the next value. 1791 1792 self._startCallFunc() 1793 self.new_op(temp_iterator) 1794 self._generateAttr(node, "next", self.attribute_load_instructions) 1795 temp, target = self._generateCallFunc([], node) 1796 self._doCallFunc(temp, target) 1797 self._endCallFunc(temp, target) 1798 1799 # Record the value to be assigned. 1800 1801 self.record_value() 1802 1803 # Test for StopIteration. 1804 1805 self.load_builtin("StopIteration", node) 1806 self.new_op(CheckException()) 1807 if node.else_ is not None: 1808 self.new_op(JumpIfTrue(else_label)) 1809 else: 1810 self.new_op(JumpIfTrue(exit_label)) 1811 1812 # Assign to the target. 1813 1814 self.dispatch(node.assign) 1815 self.discard_value() 1816 1817 # Process the body with the current next and exit points. 1818 1819 self.add_loop_labels(next_label, exit_label) 1820 self.dispatch(node.body) 1821 self.drop_loop_labels() 1822 1823 # Repeat the loop. 1824 1825 self.new_op(Jump(next_label)) 1826 1827 # Produce the "else" section. 1828 1829 if node.else_ is not None: 1830 self.set_label(exit_label) 1831 self.dispatch(node.else_) 1832 1833 # After the loop... 1834 1835 self.set_label(exit_label) 1836 1837 # Compilation duties... 1838 1839 self.discard_temp(temp_iterator) 1840 1841 def visitFrom(self, node): pass 1842 1843 def visitFunction(self, node): 1844 1845 # Only store the name when visiting this node from outside. 1846 1847 if self.unit is not node.unit: 1848 self.new_op(LoadConst(node.unit)) 1849 1850 self.record_value() 1851 self._visitName(node, self.name_store_instructions) # AssName equivalent 1852 self.set_source() 1853 self.discard_value() 1854 1855 self._generateFunctionDefaults(node.unit) 1856 1857 # Visiting of the code occurs when get_code is invoked on this node. 1858 1859 else: 1860 extend = ExtendFrame() 1861 self.new_op(extend) 1862 1863 self.dispatch(node.code) 1864 if not isinstance(self.last_op(), Return): 1865 self.dispatch(compiler.ast.Name("None")) 1866 self.new_op(StoreResult()) 1867 1868 self.new_op(Return()) 1869 1870 self.set_frame_usage(node, extend) 1871 1872 def visitGenExpr(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExpr") 1873 1874 def visitGenExprFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprFor") 1875 1876 def visitGenExprIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprIf") 1877 1878 def visitGenExprInner(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprInner") 1879 1880 def visitGetattr(self, node): 1881 self._visitAttr(node, self.attribute_load_instructions) 1882 1883 def visitGlobal(self, node): pass 1884 1885 def visitIf(self, node): 1886 first = 1 1887 exit_label = self.new_label() 1888 1889 clauses = node.tests + [(None, node.else_)] 1890 last_clause = clauses[-1] 1891 1892 for clause in clauses: 1893 test, body = clause 1894 if body is None: 1895 break 1896 if not first: 1897 self.set_label(next_label) 1898 if test is not None: 1899 self.dispatch(test) 1900 next_label = self.new_label() 1901 self.new_op(JumpIfFalse(next_label)) 1902 self.dispatch(body) 1903 if clause is not last_clause: 1904 self.new_op(Jump(exit_label)) 1905 first = 0 1906 1907 self.set_label(exit_label) 1908 1909 def visitImport(self, node): pass 1910 1911 def visitInvert(self, node): 1912 self._visitUnary(node, "__invert__") 1913 1914 def visitKeyword(self, node): pass 1915 1916 def visitLambda(self, node): 1917 1918 """ 1919 Lambda functions can be represented as globally defined functions 1920 provided they do not define any default parameter values, since these 1921 may defined in a non-global scope. 1922 1923 Where defaults are defined, an object must be created and its content 1924 defined: the callable member of the object's structure must be set to 1925 the lambda function definition; each default must be attached to the 1926 object as an attribute, as is the case with normal functions and 1927 methods. 1928 """ 1929 1930 # Produce the reference to this function when visiting this node from 1931 # outside. 1932 1933 if self.unit is not node.unit: 1934 temp = self._generateFunctionDefaults(node.unit) 1935 self.new_op(LoadConst(node.unit)) 1936 1937 # Populate the new object required for the function. 1938 1939 if temp is not None: 1940 self.new_op(LoadCallable()) 1941 self.new_op(temp) 1942 self.new_op(StoreCallable()) 1943 1944 self.new_op(temp) 1945 #self.discard_temp(temp) 1946 1947 # Visiting of the code occurs when get_code is invoked on this node. 1948 1949 else: 1950 self.dispatch(node.code) 1951 self.new_op(StoreResult()) 1952 self.new_op(Return()) 1953 1954 def visitLeftShift(self, node): 1955 self._visitBinary(node, "__lshift__", "__rlshift__") 1956 1957 def visitList(self, node): 1958 self._generateSequence("list", node) 1959 1960 def visitListComp(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListComp") 1961 1962 def visitListCompFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompFor") 1963 1964 def visitListCompIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompIf") 1965 1966 def visitMod(self, node): 1967 self._visitBinary(node, "__mod__", "__rmod__") 1968 1969 def visitModule(self, node): 1970 self.dispatch(node.node) 1971 1972 def visitMul(self, node): 1973 self._visitBinary(node, "__mul__", "__rmul__") 1974 1975 def visitName(self, node): 1976 if node.name == "None": 1977 const = self.module.constant_values[None] 1978 self.new_op(LoadConst(const)) 1979 else: 1980 self._visitName(node, self.name_load_instructions) 1981 1982 def visitNot(self, node): 1983 self.dispatch(node.expr) 1984 1985 temp = self.optimiser.optimise_temp_storage() 1986 self._generateTestBoolean(node.expr, temp) 1987 self.discard_temp(temp) 1988 1989 self.new_op(InvertBoolean()) 1990 self._generateLoadBoolean(node) 1991 1992 # Prevent incorrect optimisation. 1993 1994 self.clear_active() 1995 1996 def visitOr(self, node): 1997 end_label = self.new_label() 1998 temp_pos = self.reserve_temp() 1999 temp = LoadTemp(temp_pos) 2000 2001 for n in node.nodes[:-1]: 2002 self.dispatch(n) 2003 self.new_op(StoreTemp(temp_pos)) 2004 2005 self._generateTestBoolean(n, temp) 2006 self.new_op(JumpIfTrue(end_label)) 2007 2008 self.dispatch(node.nodes[-1]) 2009 self.new_op(StoreTemp(temp_pos)) 2010 2011 self.set_label(end_label) 2012 2013 # Prevent incorrect optimisation. 2014 2015 self.clear_active() 2016 2017 self.new_op(temp) 2018 self.discard_temp(temp) 2019 2020 def visitPass(self, node): pass 2021 2022 def visitPower(self, node): 2023 self._visitBinary(node, "__pow__", "__rpow__") 2024 2025 def visitPrint(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Print") 2026 2027 def visitPrintnl(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Printnl") 2028 2029 def visitRaise(self, node): 2030 # NOTE: expr1 only => instance provided 2031 self.dispatch(node.expr1) 2032 2033 if node.expr2 is not None: 2034 temp = self.optimiser.optimise_temp_storage() 2035 2036 self.dispatch(node.expr2) 2037 temp_arg = self.optimiser.optimise_temp_storage() 2038 2039 self._startCallFunc() 2040 self.new_op(temp_arg) 2041 self.new_op(StoreFrame(0)) 2042 self._endCallFuncArgs(1) 2043 self._doCallFunc(temp) 2044 self._endCallFunc(temp) 2045 2046 self.discard_temp(temp_arg) 2047 2048 self.new_op(StoreException()) 2049 self.new_op(RaiseException()) 2050 2051 def visitReturn(self, node): 2052 if node.value is not None: 2053 self.dispatch(node.value) 2054 else: 2055 self.dispatch(compiler.ast.Name("None")) 2056 2057 self.new_op(StoreResult()) 2058 self.new_op(Return()) 2059 2060 def visitRightShift(self, node): 2061 self._visitBinary(node, "__rshift__", "__rrshift__") 2062 2063 def visitSlice(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Slice") 2064 2065 def visitStmt(self, node): 2066 for n in node.nodes: 2067 self.dispatch(n) 2068 2069 def visitSub(self, node): 2070 self._visitBinary(node, "__sub__", "__rsub__") 2071 2072 def visitSubscript(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Subscript") 2073 2074 def visitTryExcept(self, node): 2075 exit_label = self.new_label() 2076 success_label = self.new_label() 2077 handler_label = self.new_label() 2078 2079 self.add_exception_labels(handler_label, exit_label) 2080 2081 # Try... 2082 # Produce the code, then jump to the exit. 2083 2084 self.new_op(PushHandler(handler_label)) 2085 self.dispatch(node.body) 2086 self.new_op(PopHandler()) 2087 self.new_op(Jump(exit_label)) 2088 2089 # Start of handlers. 2090 2091 self.set_label(handler_label) 2092 self.new_op(PopHandler()) 2093 2094 for name, assignment, handler in node.handlers: 2095 next_label = self.new_label() 2096 2097 # Test the given exception against the current exception. 2098 2099 if name is not None: 2100 self.dispatch(name) 2101 self.new_op(CheckException()) 2102 self.new_op(JumpIfFalse(next_label)) 2103 2104 # Handle assignment to exception variable. 2105 2106 if assignment is not None: 2107 self.dispatch(assignment) 2108 2109 # Produce the handler code, then jump to the exit. 2110 2111 self.dispatch(handler) 2112 self.new_op(Jump(exit_label)) 2113 2114 self.set_label(next_label) 2115 2116 # Unhandled exceptions. 2117 2118 #self.new_op(LoadException()) 2119 self.new_op(RaiseException()) 2120 2121 # Optional else clause. 2122 2123 if node.else_ is not None: 2124 self.dispatch(node.else_) 2125 2126 self.set_label(exit_label) 2127 self.drop_exception_labels() 2128 2129 def visitTryFinally(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "TryFinally") 2130 2131 def visitTuple(self, node): 2132 self._generateSequence("tuple", node) 2133 2134 def visitUnaryAdd(self, node): 2135 self._visitUnary(node, "__pos__") 2136 2137 def visitUnarySub(self, node): 2138 self._visitUnary(node, "__neg__") 2139 2140 def visitWhile(self, node): 2141 exit_label = self.new_label() 2142 next_label = self.new_label() 2143 else_label = self.new_label() 2144 2145 self.set_label(next_label) 2146 self.dispatch(node.test) 2147 if node.else_ is not None: 2148 self.new_op(JumpIfFalse(else_label)) 2149 else: 2150 self.new_op(JumpIfFalse(exit_label)) 2151 2152 self.add_loop_labels(next_label, exit_label) 2153 2154 self.dispatch(node.body) 2155 self.new_op(Jump(next_label)) 2156 2157 if node.else_ is not None: 2158 self.set_label(else_label) 2159 self.dispatch(node.else_) 2160 2161 self.set_label(exit_label) 2162 self.drop_loop_labels() 2163 2164 # Prevent incorrect optimisation. 2165 2166 self.clear_active() 2167 2168 def visitWith(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "With") 2169 2170 def visitYield(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Yield") 2171 2172 # Useful data. 2173 2174 comparison_methods = { 2175 "==" : ("__eq__", "__ne__"), 2176 "!=" : ("__ne__", "__eq__"), 2177 "<" : ("__lt__", "__gt__"), 2178 "<=" : ("__le__", "__ge__"), 2179 ">=" : ("__ge__", "__le__"), 2180 ">" : ("__gt__", "__lt__"), 2181 "is" : None, 2182 "is not" : None, 2183 "in" : None, 2184 "not in" : None 2185 } 2186 2187 # vim: tabstop=4 expandtab shiftwidth=4