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