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