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