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 ntemp = self.max_temp_position + 1 643 extend.attr = ntemp + node.unit.local_usage # NOTE: See get_code for similar code. 644 645 # Code writing methods. 646 647 def new_op(self, op): 648 649 "Add 'op' to the generated code." 650 651 # Optimise load operations employed by this instruction. 652 653 self.optimiser.optimise_load_operations(op) 654 if self.optimiser.optimise_away_no_operations(op): 655 return 656 657 self.code.append(op) 658 self.active = op 659 660 # Record specific types of instructions for optimisation. 661 662 if isinstance(op, current_value_instructions): 663 self.active_value = op 664 665 def remove_op(self): 666 667 "Remove the last instruction." 668 669 op = self.code.pop() 670 self.active = None 671 672 def remove_active_value(self): 673 674 "Remove the value-providing active instruction if appropriate." 675 676 if self.active_value is self.active: 677 self.remove_op() 678 679 def replace_op(self, op): 680 681 "Replace the last added instruction with 'op'." 682 683 self.remove_op() 684 self.new_op(op) 685 686 def replace_active_value(self, op): 687 688 """ 689 Replace the value-providing active instruction with 'op' if appropriate. 690 """ 691 692 self.remove_active_value() 693 self.new_op(op) 694 695 def last_op(self): 696 697 "Return the last added instruction." 698 699 try: 700 return self.code[-1] 701 except IndexError: 702 return None 703 704 def clear_active(self): 705 706 "Prevent incorrect optimisation." 707 708 self.active = None 709 self.active_value = None 710 711 # Visitor methods. 712 713 def default(self, node, *args): 714 raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__) 715 716 def dispatch(self, node, *args): 717 return ASTVisitor.dispatch(self, node, *args) 718 719 # Internal helper methods. 720 721 def _visitAttr(self, node, classes): 722 723 """ 724 Visit the attribute-related 'node', generating instructions based on the 725 given 'classes'. 726 """ 727 728 self.dispatch(node.expr) 729 self._generateAttr(node, node.attrname, classes) 730 731 def _generateAttr(self, node, attrname, classes): 732 733 """ 734 Generate code for the access to 'attrname' using the given 'classes'. 735 """ 736 737 AddressInstruction, AddressContextInstruction, AttrInstruction, AttrIndexInstruction = classes 738 739 # Where the last operation (defining the attribute owner) yields a 740 # constant... 741 742 if self.optimiser.have_constant_input(): 743 last = self.active_value 744 745 # Get the details of the access. 746 747 if isinstance(last.attr, Const): 748 target_name = last.attr.value_type_name() 749 else: 750 target = last.attr.value 751 752 if isinstance(target, Const): 753 target_name = target.value_type_name() 754 elif isinstance(target, Instance): 755 target_name = None # skip production of optimised code 756 else: 757 target_name = target.full_name() 758 759 # Only try and discover the position if the target can be resolved. 760 761 if target_name is not None: 762 763 # Access the object table to get the attribute position. 764 765 try: 766 table_entry = self.objtable.table[target_name] 767 except KeyError: 768 raise TranslateError(self.module.full_name(), node, 769 "No object entry exists for target %r." % target_name) 770 771 try: 772 pos = table_entry[attrname] 773 except KeyError: 774 raise TranslateError(self.module.full_name(), node, 775 "No attribute entry exists for name %r in target %r." % (attrname, target_name)) 776 777 # Produce a suitable instruction. 778 779 if AddressInstruction is not None: 780 self.replace_active_value(AddressInstruction(pos)) 781 else: 782 raise TranslateError(self.module.full_name(), node, 783 "Storing of class or module attribute %r via an object is not permitted." % attrname) 784 785 return 786 787 # Where the last operation involves the special 'self' name, check to 788 # see if the attribute is acceptably positioned and produce a direct 789 # access to the attribute. 790 791 elif self.optimiser.optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction), node): 792 return 793 794 # Otherwise, perform a normal operation. 795 796 try: 797 index = self.objtable.get_index(attrname) 798 except self.objtable.TableError: 799 raise TranslateError(self.module.full_name(), node, 800 "No attribute entry exists for name %r." % attrname) 801 802 self.new_op(AttrIndexInstruction(index)) 803 804 # Invocations involve the following: 805 # 806 # 1. Reservation of a frame for the arguments 807 # 2. Identification of the target which is then held in temporary storage 808 # 3. Optional inclusion of a context (important for methods) 809 # 4. Preparation of the argument frame 810 # 5. Invocation of the target 811 # 6. Discarding of the frame 812 # 813 # In order to support nested invocations - eg. a(b(c)) - use of the 814 # temporary storage is essential. 815 816 def _startCallFunc(self): 817 818 "Record the location of the invocation." 819 820 op = MakeFrame() 821 self.new_op(op) # records the start of the frame 822 self.frame_makers.append(op) 823 824 def _generateCallFunc(self, args, node): 825 826 """ 827 Support a generic function invocation using the given 'args', occurring 828 on the given 'node', where the expression providing the invocation 829 target has just been generated. 830 831 In other situations, the invocation is much simpler and does not need to 832 handle the full flexibility of a typical Python invocation. Internal 833 invocations, such as those employed by operators and certain 834 control-flow mechanisms, use predetermined arguments and arguably do not 835 need to support the same things as the more general invocations. 836 """ 837 838 target, context, temp = self._generateCallFuncContext() 839 self._generateCallFuncArgs(target, context, temp, args, node) 840 return temp, target 841 842 def _generateCallFuncContext(self): 843 844 """ 845 Produce code which loads and checks the context of the current 846 invocation, the instructions for whose target have already been 847 produced, returning a list of instructions which reference the 848 invocation target. 849 """ 850 851 t = self.optimiser.optimise_known_target() 852 if t: 853 target, context = t 854 else: 855 target, context = None, None 856 857 # Store the target in temporary storage for subsequent referencing. 858 # NOTE: This may not be appropriate for class invocations 859 # NOTE: (instantiation). 860 861 temp = self.optimiser.optimise_temp_storage() 862 863 # Where a target or context are not known or where an instance is known 864 # to be the context, load the context. 865 866 if target is None or isinstance(context, Instance): 867 self.new_op(temp) 868 self.new_op(LoadContext()) 869 self.new_op(StoreFrame(0)) 870 871 # For known instantiations, provide a new object as the first argument 872 # to the __init__ method. 873 874 elif isinstance(target, Class): 875 self.make_object(target, len(target.instance_attributes())) 876 self.new_op(StoreFrame(0)) 877 878 # Otherwise omit the context. 879 880 else: 881 pass # NOTE: Class methods should be supported. 882 883 return target, context, temp 884 885 def _generateCallFuncArgs(self, target, context, temp, args, node): 886 887 """ 888 Given invocation 'target' and 'context' information, the 'temp' 889 reference to the target, a list of nodes representing the 'args' 890 (arguments), generate instructions which load the arguments for the 891 invocation defined by the given 'node'. 892 """ 893 894 # Evaluate the arguments. 895 896 employed_positions = set() 897 employed_keywords = set() 898 extra_keywords = [] 899 900 # Find keyword arguments in advance in order to help resolve targets. 901 902 for arg in args: 903 if isinstance(arg, compiler.ast.Keyword): 904 employed_keywords.add(arg.name) 905 906 possible_targets = self.paramtable.all_possible_objects(employed_keywords) 907 908 # Note the presence of the context in the frame where appropriate. 909 910 if target is None or isinstance(context, Instance): 911 ncontext = 1 912 expect_context = 0 913 914 # Handle calls to classes. 915 916 elif isinstance(target, Class): 917 ncontext = 1 918 expect_context = 0 919 target = target.get_init_method() 920 921 # Method calls via classes. 922 923 elif isinstance(context, Class): 924 ncontext = 0 925 expect_context = 1 926 927 # Function calls. 928 929 else: 930 ncontext = 0 931 expect_context = 0 932 933 first = 1 934 frame_pos = ncontext 935 max_keyword_pos = -1 936 937 for arg in args: 938 939 # Handle positional and keyword arguments separately. 940 941 if isinstance(arg, compiler.ast.Keyword): 942 943 # Optimise where the target is known now. 944 945 if target is not None: 946 947 # Find the parameter table entry for the target. 948 949 target_name = target.full_name() 950 951 # Look for a callable with the precise target name. 952 953 table_entry = self.paramtable.table[target_name] 954 955 # Look the name up in the parameter table entry. 956 957 try: 958 pos = table_entry[arg.name] 959 960 # Where no position is found, this could be an extra keyword 961 # argument. 962 963 except KeyError: 964 extra_keywords.append(arg) 965 continue 966 967 # Test for illegal conditions. 968 969 if pos in employed_positions: 970 raise TranslateError(self.module.full_name(), node, 971 "Keyword argument %r overwrites parameter %r." % (arg.name, pos)) 972 973 employed_positions.add(pos) 974 975 # Generate code for the keyword and the positioning 976 # operation. 977 978 self.dispatch(arg.expr) 979 self.new_op(StoreFrame(pos)) 980 981 # Otherwise, generate the code needed to obtain the details of 982 # the parameter location. 983 984 else: 985 986 # Combine the target details with the name to get the location. 987 # See the access method on the List class. 988 989 try: 990 paramindex = self.paramtable.get_index(arg.name) 991 992 # Where no position is found, this could be an extra keyword 993 # argument. 994 995 except self.paramtable.TableError: 996 extra_keywords.append(arg) 997 continue 998 999 # Generate code for the keyword and the positioning 1000 # operation. 1001 1002 self.dispatch(arg.expr) 1003 self.new_op(StoreFrameIndex(paramindex)) 1004 1005 # use (callable+0)+paramindex+table 1006 # checks embedded offset against (callable+0) 1007 # moves the current value to frame+position 1008 1009 # Record the highest possible frame position for this argument. 1010 1011 max_keyword_pos = max(max_keyword_pos, max(self.paramtable.all_attribute_positions(arg.name))) 1012 1013 else: 1014 self.dispatch(arg) 1015 self.new_op(StoreFrame(frame_pos)) 1016 1017 employed_positions.add(frame_pos) 1018 1019 # Check to see if the first argument is appropriate (compatible with 1020 # the target where methods are being invoked via classes). 1021 1022 if first and expect_context: 1023 1024 # Drop any test if the target and the context are known. 1025 1026 if not self.optimiser.have_correct_self_for_target(context): 1027 1028 continue_label = self.new_label() 1029 self.new_op(CheckSelf()) 1030 self.active.source = temp 1031 self.new_op(JumpIfTrue(continue_label)) 1032 1033 # Where the context is inappropriate, drop the incomplete frame and 1034 # raise an exception. 1035 1036 self.new_op(DropFrame()) 1037 self.new_op(LoadResult()) 1038 1039 self.load_builtin("TypeError", node) 1040 self.new_op(StoreException()) 1041 self.new_op(RaiseException()) 1042 self.set_label(continue_label) 1043 1044 first = 0 1045 frame_pos += 1 1046 1047 # NOTE: Extra keywords are not supported. 1048 # NOTE: Somehow, the above needs to be combined with * arguments. 1049 1050 if extra_keywords: 1051 print "Warning: extra keyword argument(s) %s not handled." % ", ".join([arg.name for arg in extra_keywords]) 1052 1053 # Either test for a complete set of arguments. 1054 1055 if target is not None: 1056 1057 # Make sure that enough arguments have been given. 1058 1059 nargs_max = len(target.positional_names) 1060 ndefaults = len(target.defaults) 1061 nargs_min = nargs_max - ndefaults 1062 1063 for i in range(ncontext, nargs_min): 1064 if i not in employed_positions: 1065 raise TranslateError(self.module.full_name(), node, 1066 "Argument %r not supplied for %r: need at least %d argument(s)." % (i+1, target.name, nargs_min)) 1067 1068 nargs = frame_pos 1069 1070 if nargs > nargs_max and not target.has_star and not target.has_dstar: 1071 raise TranslateError(self.module.full_name(), node, 1072 "Too many arguments for %r: need at most %d argument(s)." % (target.name, nargs_max)) 1073 1074 # Where defaults are involved, put them into the frame. 1075 1076 self._generateCallFuncDefaultArgs(target, temp, nargs_min, nargs_max, employed_positions) 1077 1078 # Set the frame size. 1079 1080 self._endCallFuncArgs(nargs_max) 1081 1082 # Or generate instructions to do this at run-time. 1083 # NOTE: CheckFrame has to check the number of arguments and to fill in 1084 # NOTE: defaults; it also has to shift the invocation frame according to 1085 # NOTE: the context in use. 1086 1087 else: 1088 max_pos = max(max(employed_positions or [-1]), max_keyword_pos, frame_pos - 1) 1089 1090 # Only check non-empty frames (using the callable's details). 1091 1092 if employed_positions or max_pos >= 0: 1093 self.new_op(temp) 1094 self.new_op(CheckFrame(max_pos + 1)) 1095 1096 # Set the frame size. 1097 1098 self._endCallFuncArgs(max_pos + 1) 1099 1100 def _generateCallFuncDefaultArgs(self, target, temp, nargs_min, nargs_max, employed_positions): 1101 1102 """ 1103 For the given 'target' and 'temp' reference to the target, generate 1104 default arguments for those positions in the range 'nargs_min'... 1105 'nargs_max' which are not present in the 'employed_positions' 1106 collection. 1107 """ 1108 1109 # Where a lambda is involved, construct a dynamic object to hold the 1110 # defaults. 1111 1112 dynamic = target.name is None 1113 1114 # Here, we use negative index values to visit the right hand end of 1115 # the defaults list. 1116 1117 for pos in range(nargs_min, nargs_max): 1118 if pos not in employed_positions: 1119 if dynamic: 1120 self.new_op(temp) 1121 self.new_op(LoadAttr(target.default_attrs[pos - nargs_min])) 1122 else: 1123 self.new_op(LoadAddress(target.default_attrs[pos - nargs_min])) 1124 self.new_op(StoreFrame(pos)) 1125 1126 def _doCallFunc(self, instruction, target=None): 1127 1128 "Make the invocation." 1129 1130 if isinstance(target, Class): 1131 self.new_op(LoadConst(target.get_init_method())) 1132 else: 1133 self.new_op(instruction) 1134 self.new_op(LoadCallable()) 1135 self.new_op(JumpWithFrame()) 1136 1137 def _endCallFuncArgs(self, nargs): 1138 1139 "Set the frame size." 1140 1141 self.frame_makers[-1].attr = nargs 1142 self.frame_makers.pop() 1143 1144 def _endCallFunc(self, instruction=None, target=None, load_result=1): 1145 1146 "Finish the invocation and tidy up afterwards." 1147 1148 if isinstance(target, Class): 1149 self.new_op(LoadName(target.get_init_method().all_locals()["self"])) # load the context in the invocation frame 1150 self.new_op(StoreResult()) 1151 self.new_op(DropFrame()) 1152 if load_result: 1153 self.new_op(LoadResult()) 1154 1155 # Discard any temporary storage instructions. 1156 1157 if instruction is not None: 1158 self.discard_temp(instruction) 1159 1160 def _generateFunctionDefaults(self, function): 1161 1162 """ 1163 Generate the default initialisation code for 'function', returning 1164 a temporary storage reference if a dynamic object was created for the 1165 function. 1166 """ 1167 1168 attr_to_default = zip(function.default_attrs, function.defaults) 1169 if not attr_to_default: 1170 return None 1171 1172 # Where a lambda is involved, construct a dynamic object to hold the 1173 # defaults. 1174 1175 dynamic = function.name is None 1176 1177 if dynamic: 1178 self.make_object(self.get_builtin_class("function", function), len(attr_to_default)) 1179 temp = self.get_temp() 1180 1181 for attr, default in attr_to_default: 1182 self.dispatch(default) 1183 1184 self.record_value() 1185 if dynamic: 1186 self.new_op(temp) 1187 self.new_op(StoreAttr(attr)) 1188 else: 1189 self.new_op(StoreAddress(attr)) 1190 self.set_source() 1191 self.discard_value() 1192 1193 if dynamic: 1194 return temp 1195 else: 1196 return None 1197 1198 def _visitName(self, node, classes): 1199 1200 """ 1201 Visit the name-related 'node', generating instructions based on the 1202 given 'classes'. 1203 """ 1204 1205 name = node.name 1206 scope = self.get_scope(name) 1207 #print self.module.name, node.lineno, name, scope 1208 self._generateName(name, scope, classes, node) 1209 1210 def _generateName(self, name, scope, classes, node): 1211 1212 """ 1213 Generate code for the access to 'name' in 'scope' using the given 1214 'classes', and using the given 'node' as the source of the access. 1215 """ 1216 1217 NameInstruction, AddressInstruction = classes 1218 1219 if scope == "local": 1220 unit = self.unit 1221 if isinstance(unit, Function): 1222 self.new_op(NameInstruction(unit.all_locals()[name])) 1223 elif isinstance(unit, Class): 1224 self.new_op(AddressInstruction(unit.all_class_attributes()[name])) 1225 elif isinstance(unit, Module): 1226 self.new_op(AddressInstruction(unit.module_attributes()[name])) 1227 else: 1228 raise TranslateError(self.module.full_name(), node, "Program unit %r has no local %r." % (unit, name)) 1229 1230 elif scope == "global": 1231 globals = self.module.module_attributes() 1232 if globals.has_key(name): 1233 self.new_op(AddressInstruction(globals[name])) 1234 else: 1235 raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r." % (self.module, name)) 1236 1237 else: 1238 self.new_op(AddressInstruction(self.get_builtin(name, node))) 1239 1240 def _visitUnary(self, node, method): 1241 1242 """ 1243 _t = node.expr 1244 try: 1245 _result = _t.__pos__() 1246 except AttributeError: 1247 raise TypeError 1248 """ 1249 1250 end_call_label = self.new_label() 1251 end_label = self.new_label() 1252 1253 # Evaluate and store the operand in temporary storage. 1254 1255 self.dispatch(node.expr) 1256 temp = self.optimiser.optimise_temp_storage() 1257 1258 # Produce the invocation. 1259 1260 self._startCallFunc() 1261 self.new_op(temp) 1262 1263 # Get the method on temp. 1264 1265 self._generateAttr(node, method, self.attribute_load_instructions) 1266 temp_method = self.optimiser.optimise_temp_storage() 1267 1268 self._handleAttributeError(node, end_call_label) 1269 1270 # Add arguments. 1271 # NOTE: No support for defaults. 1272 1273 self.new_op(temp) # Explicit context as first argument. 1274 self.new_op(StoreFrame(0)) 1275 self._endCallFuncArgs(1) 1276 self._doCallFunc(temp_method) 1277 self._endCallFunc(temp_method) 1278 self.new_op(Jump(end_label)) 1279 1280 # End method attempt. 1281 1282 self.set_label(end_call_label) 1283 self._endCallFunc() # From the method call. 1284 1285 # Raise a TypeError. 1286 1287 self.load_builtin("TypeError", node) 1288 self.new_op(StoreException()) 1289 self.new_op(RaiseException()) 1290 1291 self.set_label(end_label) 1292 1293 # Compilation duties... 1294 1295 self.discard_temp(temp) 1296 1297 def _visitBinary(self, node, left_method, right_method): 1298 1299 """ 1300 _t1 = node.left 1301 _t2 = node.right 1302 try: 1303 _result = _t1.__add__(_t2) 1304 if _result is NotImplemented: 1305 raise AttributeError 1306 except AttributeError: 1307 try: 1308 _result = _t2.__radd__(_t1) 1309 if _result is NotImplemented: 1310 raise AttributeError 1311 except AttributeError: 1312 raise TypeError 1313 """ 1314 1315 # Evaluate and store the left operand in temporary storage. 1316 1317 self.dispatch(node.left) 1318 temp1 = self.optimiser.optimise_temp_storage() 1319 1320 # Evaluate and store the right operand in temporary storage. 1321 1322 self.dispatch(node.right) 1323 temp2 = self.optimiser.optimise_temp_storage() 1324 1325 self._generateBinary(node, temp1, temp2, left_method, right_method) 1326 1327 # Compilation duties... 1328 1329 self.discard_temp(temp1) 1330 self.discard_temp(temp2) 1331 1332 def _generateBinary(self, node, temp1, temp2, left_method, right_method): 1333 1334 """ 1335 For the given 'node', generate the binary operator pattern for the 1336 operands 'temp1' and 'temp2', employing 'left_method' and 'right_method' 1337 as defined for binary operators, but also used in comparisons (for which 1338 this method is provided). 1339 """ 1340 1341 right_label = self.new_label() 1342 type_error_label = self.new_label() 1343 end_label = self.new_label() 1344 1345 # Left method. 1346 1347 self._generateOpMethod(node, temp1, temp2, left_method, right_label, end_label) 1348 1349 # Right method. 1350 1351 self.set_label(right_label) 1352 self._generateOpMethod(node, temp2, temp1, right_method, type_error_label, end_label) 1353 1354 # Raise a TypeError. 1355 1356 self.set_label(type_error_label) 1357 self.load_builtin("TypeError", node) 1358 self.new_op(StoreException()) 1359 self.new_op(RaiseException()) 1360 1361 self.set_label(end_label) 1362 1363 def _generateOpMethod(self, node, temp1, temp2, method_name, next_method_label, end_label): 1364 1365 """ 1366 For the given 'node', generate the operator method invocation using the 1367 operands 'temp1' and 'temp2', employing the given 'method_name', and 1368 jumping appropriately to 'next_method_label' where a NotImplemented 1369 result is returned, or to 'end_label' if the method call was successful. 1370 """ 1371 1372 end_attempt_label = self.new_label() 1373 1374 self.new_op(temp1) 1375 1376 # Get method on temp1. 1377 1378 self._generateAttr(node, method_name, self.attribute_load_instructions) 1379 temp_method = self.optimiser.optimise_temp_storage() 1380 1381 self._handleAttributeError(node, end_attempt_label) 1382 1383 # Add arguments. 1384 # NOTE: No support for defaults. 1385 1386 self._startCallFunc() 1387 self.new_op(temp1) 1388 self.new_op(StoreFrame(0)) 1389 self.new_op(temp2) 1390 self.new_op(StoreFrame(1)) 1391 self._endCallFuncArgs(2) 1392 self._doCallFunc(temp_method) 1393 self._endCallFunc(temp_method) 1394 1395 # Test for NotImplemented. 1396 # Don't actually raise an exception. 1397 1398 self.new_op(TestIdentityAddress(self.get_builtin("NotImplemented", node))) 1399 self.new_op(JumpIfTrue(next_method_label)) 1400 self.new_op(Jump(end_label)) 1401 1402 # End method attempt. 1403 1404 self.set_label(end_attempt_label) 1405 1406 def _handleAttributeError(self, node, end_call_label): 1407 1408 """ 1409 Add exception handling to the method acquisition instructions where the 1410 attribute access cannot be resolved at compile-time. 1411 """ 1412 1413 if not self.optimiser.optimise_known_target(): 1414 self.load_builtin("AttributeError", node) 1415 self.new_op(CheckException()) 1416 self.new_op(JumpIfTrue(end_call_label)) 1417 1418 def _generateSequence(self, sequence_type, node): 1419 1420 "Make a sequence of 'sequence_type' for the given program 'node'." 1421 1422 self.make_object(self.get_builtin_class(sequence_type, node), len(node.nodes)) 1423 temp = self.get_temp() 1424 1425 for i, n in enumerate(node.nodes): 1426 self.dispatch(n) 1427 self.record_value() 1428 self.new_op(temp) 1429 self.new_op(StoreAttr(Attr(i, None, None, None))) 1430 self.set_source() 1431 self.discard_value() 1432 1433 self.new_op(temp) 1434 self.discard_temp(temp) 1435 1436 def _generateTestBoolean(self, node, temp): 1437 1438 """ 1439 Generate a test of the boolean status of the current value for the given 1440 program 'node'. 1441 """ 1442 1443 # Get method on temp. 1444 # NOTE: Using __bool__ instead of __nonzero__. 1445 1446 self._generateAttr(node, "__bool__", self.attribute_load_instructions) 1447 temp_method = self.optimiser.optimise_temp_storage() 1448 1449 self._startCallFunc() 1450 self.new_op(temp) 1451 self.new_op(StoreFrame(0)) 1452 self._endCallFuncArgs(1) 1453 self._doCallFunc(temp_method) 1454 self._endCallFunc(temp_method) 1455 1456 self.discard_temp(temp_method) 1457 1458 # Convert result to boolean (a StoreBoolean operation). 1459 1460 self.new_op(TestIdentityAddress(self.get_builtin("True", node))) 1461 1462 def _generateLoadBoolean(self, node): 1463 1464 """ 1465 Generate instructions to load the appropriate value given the current 1466 boolean status. 1467 """ 1468 1469 true_label = self.new_label() 1470 end_label = self.new_label() 1471 1472 self.new_op(JumpIfTrue(true_label)) 1473 self.load_builtin("False", node) 1474 self.new_op(Jump(end_label)) 1475 1476 self.set_label(true_label) 1477 self.load_builtin("True", node) 1478 1479 self.set_label(end_label) 1480 1481 # Concrete visitor methods. 1482 1483 def visitAdd(self, node): 1484 self._visitBinary(node, "__add__", "__radd__") 1485 1486 def visitAnd(self, node): 1487 end_label = self.new_label() 1488 temp_pos = self.reserve_temp() 1489 temp = LoadTemp(temp_pos) 1490 1491 for n in node.nodes[:-1]: 1492 self.dispatch(n) 1493 self.new_op(StoreTemp(temp_pos)) 1494 1495 self._generateTestBoolean(n, temp) 1496 self.new_op(JumpIfFalse(end_label)) 1497 1498 self.dispatch(node.nodes[-1]) 1499 self.new_op(StoreTemp(temp_pos)) 1500 1501 self.set_label(end_label) 1502 1503 # Prevent incorrect optimisation. 1504 1505 self.clear_active() 1506 1507 self.new_op(temp) 1508 self.discard_temp(temp) 1509 1510 def visitAssert(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Assert") 1511 1512 def visitAssign(self, node): 1513 self.dispatch(node.expr) 1514 self.record_value(0) 1515 1516 for n in node.nodes: 1517 self.dispatch(n) 1518 1519 self.discard_value() 1520 1521 def visitAssAttr(self, node): 1522 self._visitAttr(node, self.attribute_store_instructions) 1523 self.set_source() 1524 1525 def visitAssList(self, node): 1526 for i, n in enumerate(node.nodes): 1527 self._startCallFunc() 1528 self.new_op(self.expr_temp[-1]) 1529 self._generateAttr(node, "__getitem__", self.attribute_load_instructions) 1530 temp, target = self._generateCallFunc([compiler.ast.Const(i)], node) 1531 self._doCallFunc(temp, target) 1532 self._endCallFunc(temp, target) 1533 1534 # Provide a different source value. 1535 1536 self.record_value(0) 1537 self.dispatch(n) 1538 self.discard_value() 1539 1540 def visitAssName(self, node): 1541 self._visitName(node, self.name_store_instructions) 1542 self.set_source() 1543 1544 visitAssTuple = visitAssList 1545 1546 def visitAugAssign(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "AugAssign") 1547 1548 def visitBackquote(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Backquote") 1549 1550 def visitBitand(self, node): 1551 self._visitBinary(node, "__and__", "__rand__") 1552 1553 def visitBitor(self, node): 1554 self._visitBinary(node, "__or__", "__ror__") 1555 1556 def visitBitxor(self, node): 1557 self._visitBinary(node, "__xor__", "__rxor__") 1558 1559 def visitBreak(self, node): 1560 next_label, exit_label = self.get_loop_labels() 1561 self.new_op(Jump(exit_label)) 1562 1563 def visitCallFunc(self, node): 1564 1565 """ 1566 Evaluate positional arguments, evaluate and store keyword arguments in 1567 the correct location, then invoke the function. 1568 """ 1569 1570 # Mark the frame, evaluate the target, generate the call. 1571 1572 self._startCallFunc() 1573 self.dispatch(node.node) 1574 temp, target = self._generateCallFunc(node.args, node) 1575 self._doCallFunc(temp, target) 1576 self._endCallFunc(temp, target) 1577 1578 def visitClass(self, node): 1579 1580 # Store the name. 1581 1582 self.new_op(LoadConst(node.unit)) 1583 self.record_value() 1584 self._visitName(node, self.name_store_instructions) 1585 self.set_source() 1586 self.discard_value() 1587 1588 # Visit the code. 1589 1590 unit = self.unit 1591 self.unit = node.unit 1592 self.unit.code_location = self.module.code_location # class body code is not independently addressable 1593 self.dispatch(node.code) 1594 self.unit = unit 1595 1596 def visitCompare(self, node): 1597 1598 """ 1599 _t1 = node.expr 1600 _t1 op1 _t2 and _t2 op2 _t3 and ... 1601 """ 1602 1603 end_label = self.new_label() 1604 temp_pos = self.reserve_temp() 1605 temp_result = LoadTemp(temp_pos) 1606 1607 self.dispatch(node.expr) 1608 temp2 = self.optimiser.optimise_temp_storage() 1609 1610 last_op = node.ops[-1] 1611 1612 for op in node.ops: 1613 op_name, next_node = op 1614 methods = self.comparison_methods[op_name] 1615 1616 temp1 = temp2 1617 self.dispatch(next_node) 1618 temp2 = self.optimiser.optimise_temp_storage() 1619 1620 # Use the appropriate mechanism, setting the boolean status for the 1621 # comparison. 1622 1623 if methods is not None: 1624 left_method, right_method = methods 1625 1626 # Generate method call using evaluated argument and next node. 1627 1628 self._generateBinary(node, temp1, temp2, left_method, right_method) 1629 self.new_op(StoreTemp(temp_pos)) 1630 self._generateTestBoolean(node, temp_result) 1631 1632 else: 1633 # Deal with the special operators. 1634 1635 if op_name.startswith("is"): 1636 self.new_op(temp1) 1637 self.record_value() 1638 self.new_op(temp2) 1639 self.new_op(TestIdentity()) 1640 self.set_source() 1641 self.discard_value() 1642 1643 elif op_name.endswith("in"): 1644 self._startCallFunc() 1645 self.new_op(temp2) 1646 1647 # Get method on temp2. 1648 1649 self._generateAttr(node, "__contains__", self.attribute_load_instructions) 1650 temp_method = self.optimiser.optimise_temp_storage() 1651 1652 # Add arguments. 1653 # NOTE: No support for defaults. 1654 1655 self.new_op(temp2) 1656 self.new_op(StoreFrame(0)) 1657 self.new_op(temp1) 1658 self.new_op(StoreFrame(1)) 1659 self._endCallFuncArgs(2) 1660 self._doCallFunc(temp_method) 1661 self._endCallFunc(temp_method) 1662 1663 self.new_op(StoreTemp(temp_pos)) 1664 self._generateTestBoolean(node, temp_result) 1665 1666 if op_name.find("not") != -1: 1667 self.new_op(InvertBoolean()) 1668 1669 # Test the result and jump to the end label if false. 1670 1671 if op is not last_op: 1672 self.new_op(JumpIfFalse(end_label)) 1673 1674 # Compilation duties... 1675 1676 self.discard_temp(temp1) 1677 1678 self.discard_temp(temp2) 1679 self.discard_temp(temp_result) 1680 self.set_label(end_label) 1681 1682 # Yield the appropriate value. 1683 1684 self._generateLoadBoolean(node) 1685 1686 def visitConst(self, node): 1687 const = self.module.constant_values[node.value] 1688 self.new_op(LoadConst(const)) 1689 1690 def visitContinue(self, node): 1691 next_label, exit_label = self.get_loop_labels() 1692 self.new_op(Jump(next_label)) 1693 1694 def visitDecorators(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Decorators") 1695 1696 def visitDict(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Dict") 1697 1698 def visitDiscard(self, node): 1699 self.dispatch(node.expr) 1700 self.optimiser.optimise_unused_results() 1701 1702 def visitDiv(self, node): 1703 self._visitBinary(node, "__div__", "__rdiv__") 1704 1705 def visitEllipsis(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Ellipsis") 1706 1707 def visitExec(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Exec") 1708 1709 def visitExpression(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Expression") 1710 1711 def visitFloorDiv(self, node): 1712 self._visitBinary(node, "__floordiv__", "__rfloordiv__") 1713 1714 def visitFor(self, node): 1715 exit_label = self.new_label() 1716 next_label = self.new_label() 1717 else_label = self.new_label() 1718 1719 # Get the "list" to be iterated over, obtain its iterator. 1720 1721 self._startCallFunc() 1722 self.dispatch(node.list) 1723 self._generateAttr(node, "__iter__", self.attribute_load_instructions) 1724 temp, target = self._generateCallFunc([], node) 1725 self._doCallFunc(temp, target) 1726 self._endCallFunc(temp, target) 1727 1728 temp_iterator = self.optimiser.optimise_temp_storage() 1729 1730 # In the loop... 1731 1732 self.set_label(next_label) 1733 1734 # Use the iterator to get the next value. 1735 1736 self._startCallFunc() 1737 self.new_op(temp_iterator) 1738 self._generateAttr(node, "next", self.attribute_load_instructions) 1739 temp, target = self._generateCallFunc([], node) 1740 self._doCallFunc(temp, target) 1741 self._endCallFunc(temp, target) 1742 1743 # Record the value to be assigned. 1744 1745 self.record_value() 1746 1747 # Test for StopIteration. 1748 1749 self.load_builtin("StopIteration", node) 1750 self.new_op(CheckException()) 1751 if node.else_ is not None: 1752 self.new_op(JumpIfTrue(else_label)) 1753 else: 1754 self.new_op(JumpIfTrue(exit_label)) 1755 1756 # Assign to the target. 1757 1758 self.dispatch(node.assign) 1759 self.discard_value() 1760 1761 # Process the body with the current next and exit points. 1762 1763 self.add_loop_labels(next_label, exit_label) 1764 self.dispatch(node.body) 1765 self.drop_loop_labels() 1766 1767 # Repeat the loop. 1768 1769 self.new_op(Jump(next_label)) 1770 1771 # Produce the "else" section. 1772 1773 if node.else_ is not None: 1774 self.set_label(exit_label) 1775 self.dispatch(node.else_) 1776 1777 # After the loop... 1778 1779 self.set_label(exit_label) 1780 1781 # Compilation duties... 1782 1783 self.discard_temp(temp_iterator) 1784 1785 def visitFrom(self, node): pass 1786 1787 def visitFunction(self, node): 1788 1789 # Only store the name when visiting this node from outside. 1790 1791 if self.unit is not node.unit: 1792 self.new_op(LoadConst(node.unit)) 1793 1794 self.record_value() 1795 self._visitName(node, self.name_store_instructions) # AssName equivalent 1796 self.set_source() 1797 self.discard_value() 1798 1799 self._generateFunctionDefaults(node.unit) 1800 1801 # Visiting of the code occurs when get_code is invoked on this node. 1802 1803 else: 1804 extend = ExtendFrame() 1805 self.new_op(extend) 1806 1807 self.dispatch(node.code) 1808 if not isinstance(self.last_op(), Return): 1809 self.dispatch(compiler.ast.Name("None")) 1810 self.new_op(StoreResult()) 1811 1812 self.new_op(Return()) 1813 1814 self.set_frame_usage(node, extend) 1815 1816 def visitGenExpr(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExpr") 1817 1818 def visitGenExprFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprFor") 1819 1820 def visitGenExprIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprIf") 1821 1822 def visitGenExprInner(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprInner") 1823 1824 def visitGetattr(self, node): 1825 self._visitAttr(node, self.attribute_load_instructions) 1826 1827 def visitGlobal(self, node): pass 1828 1829 def visitIf(self, node): 1830 first = 1 1831 exit_label = self.new_label() 1832 1833 clauses = node.tests + [(None, node.else_)] 1834 last_clause = clauses[-1] 1835 1836 for clause in clauses: 1837 test, body = clause 1838 if body is None: 1839 break 1840 if not first: 1841 self.set_label(next_label) 1842 if test is not None: 1843 self.dispatch(test) 1844 next_label = self.new_label() 1845 self.new_op(JumpIfFalse(next_label)) 1846 self.dispatch(body) 1847 if clause is not last_clause: 1848 self.new_op(Jump(exit_label)) 1849 first = 0 1850 1851 self.set_label(exit_label) 1852 1853 def visitImport(self, node): pass 1854 1855 def visitInvert(self, node): 1856 self._visitUnary(node, "__invert__") 1857 1858 def visitKeyword(self, node): pass 1859 1860 def visitLambda(self, node): 1861 1862 """ 1863 Lambda functions can be represented as globally defined functions 1864 provided they do not define any default parameter values, since these 1865 may defined in a non-global scope. 1866 1867 Where defaults are defined, an object must be created and its content 1868 defined: the callable member of the object's structure must be set to 1869 the lambda function definition; each default must be attached to the 1870 object as an attribute, as is the case with normal functions and 1871 methods. 1872 """ 1873 1874 # Produce the reference to this function when visiting this node from 1875 # outside. 1876 1877 if self.unit is not node.unit: 1878 temp = self._generateFunctionDefaults(node.unit) 1879 self.new_op(LoadConst(node.unit)) 1880 1881 # Populate the new object required for the function. 1882 1883 if temp is not None: 1884 self.new_op(LoadCallable()) 1885 self.new_op(temp) 1886 self.new_op(StoreCallable()) 1887 1888 self.new_op(temp) 1889 #self.discard_temp(temp) 1890 1891 # Visiting of the code occurs when get_code is invoked on this node. 1892 1893 else: 1894 self.dispatch(node.code) 1895 self.new_op(StoreResult()) 1896 self.new_op(Return()) 1897 1898 def visitLeftShift(self, node): 1899 self._visitBinary(node, "__lshift__", "__rlshift__") 1900 1901 def visitList(self, node): 1902 self._generateSequence("list", node) 1903 1904 def visitListComp(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListComp") 1905 1906 def visitListCompFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompFor") 1907 1908 def visitListCompIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompIf") 1909 1910 def visitMod(self, node): 1911 self._visitBinary(node, "__mod__", "__rmod__") 1912 1913 def visitModule(self, node): 1914 extend = ExtendFrame() 1915 self.new_op(extend) 1916 self.dispatch(node.node) 1917 self.set_frame_usage(node, extend) 1918 1919 def visitMul(self, node): 1920 self._visitBinary(node, "__mul__", "__rmul__") 1921 1922 def visitName(self, node): 1923 if node.name == "None": 1924 const = self.module.constant_values[None] 1925 self.new_op(LoadConst(const)) 1926 else: 1927 self._visitName(node, self.name_load_instructions) 1928 1929 def visitNot(self, node): 1930 self.dispatch(node.expr) 1931 1932 temp = self.optimiser.optimise_temp_storage() 1933 self._generateTestBoolean(node.expr, temp) 1934 self.discard_temp(temp) 1935 1936 self.new_op(InvertBoolean()) 1937 self._generateLoadBoolean(node) 1938 1939 # Prevent incorrect optimisation. 1940 1941 self.clear_active() 1942 1943 def visitOr(self, node): 1944 end_label = self.new_label() 1945 temp_pos = self.reserve_temp() 1946 temp = LoadTemp(temp_pos) 1947 1948 for n in node.nodes[:-1]: 1949 self.dispatch(n) 1950 self.new_op(StoreTemp(temp_pos)) 1951 1952 self._generateTestBoolean(n, temp) 1953 self.new_op(JumpIfTrue(end_label)) 1954 1955 self.dispatch(node.nodes[-1]) 1956 self.new_op(StoreTemp(temp_pos)) 1957 1958 self.set_label(end_label) 1959 1960 # Prevent incorrect optimisation. 1961 1962 self.clear_active() 1963 1964 self.new_op(temp) 1965 self.discard_temp(temp) 1966 1967 def visitPass(self, node): pass 1968 1969 def visitPower(self, node): 1970 self._visitBinary(node, "__pow__", "__rpow__") 1971 1972 def visitPrint(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Print") 1973 1974 def visitPrintnl(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Printnl") 1975 1976 def visitRaise(self, node): 1977 # NOTE: expr1 only => instance provided 1978 self.dispatch(node.expr1) 1979 1980 if node.expr2 is not None: 1981 temp = self.optimiser.optimise_temp_storage() 1982 1983 self.dispatch(node.expr2) 1984 temp_arg = self.optimiser.optimise_temp_storage() 1985 1986 self._startCallFunc() 1987 self.new_op(temp_arg) 1988 self.new_op(StoreFrame(0)) 1989 self._endCallFuncArgs(1) 1990 self._doCallFunc(temp) 1991 self._endCallFunc(temp) 1992 1993 self.discard_temp(temp_arg) 1994 1995 self.new_op(StoreException()) 1996 self.new_op(RaiseException()) 1997 1998 def visitReturn(self, node): 1999 if node.value is not None: 2000 self.dispatch(node.value) 2001 else: 2002 self.dispatch(compiler.ast.Name("None")) 2003 2004 self.new_op(StoreResult()) 2005 self.new_op(Return()) 2006 2007 def visitRightShift(self, node): 2008 self._visitBinary(node, "__rshift__", "__rrshift__") 2009 2010 def visitSlice(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Slice") 2011 2012 def visitStmt(self, node): 2013 for n in node.nodes: 2014 self.dispatch(n) 2015 if self.temp_positions: 2016 #print "Had temp", self.temp_positions 2017 self.temp_positions = set() 2018 2019 def visitSub(self, node): 2020 self._visitBinary(node, "__sub__", "__rsub__") 2021 2022 def visitSubscript(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Subscript") 2023 2024 def visitTryExcept(self, node): 2025 exit_label = self.new_label() 2026 success_label = self.new_label() 2027 handler_label = self.new_label() 2028 2029 self.add_exception_labels(handler_label, exit_label) 2030 2031 # Try... 2032 # Produce the code, then jump to the exit. 2033 2034 self.new_op(PushHandler(handler_label)) 2035 self.dispatch(node.body) 2036 self.new_op(PopHandler()) 2037 self.new_op(Jump(exit_label)) 2038 2039 # Start of handlers. 2040 2041 self.set_label(handler_label) 2042 self.new_op(PopHandler()) 2043 2044 for name, assignment, handler in node.handlers: 2045 next_label = self.new_label() 2046 2047 # Test the given exception against the current exception. 2048 2049 if name is not None: 2050 self.dispatch(name) 2051 self.new_op(CheckException()) 2052 self.new_op(JumpIfFalse(next_label)) 2053 2054 # Handle assignment to exception variable. 2055 2056 if assignment is not None: 2057 self.dispatch(assignment) 2058 2059 # Produce the handler code, then jump to the exit. 2060 2061 self.dispatch(handler) 2062 self.new_op(Jump(exit_label)) 2063 2064 self.set_label(next_label) 2065 2066 # Unhandled exceptions. 2067 2068 #self.new_op(LoadException()) 2069 self.new_op(RaiseException()) 2070 2071 # Optional else clause. 2072 2073 if node.else_ is not None: 2074 self.dispatch(node.else_) 2075 2076 self.set_label(exit_label) 2077 self.drop_exception_labels() 2078 2079 def visitTryFinally(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "TryFinally") 2080 2081 def visitTuple(self, node): 2082 self._generateSequence("tuple", node) 2083 2084 def visitUnaryAdd(self, node): 2085 self._visitUnary(node, "__pos__") 2086 2087 def visitUnarySub(self, node): 2088 self._visitUnary(node, "__neg__") 2089 2090 def visitWhile(self, node): 2091 exit_label = self.new_label() 2092 next_label = self.new_label() 2093 else_label = self.new_label() 2094 2095 self.set_label(next_label) 2096 self.dispatch(node.test) 2097 if node.else_ is not None: 2098 self.new_op(JumpIfFalse(else_label)) 2099 else: 2100 self.new_op(JumpIfFalse(exit_label)) 2101 2102 self.add_loop_labels(next_label, exit_label) 2103 2104 self.dispatch(node.body) 2105 self.new_op(Jump(next_label)) 2106 2107 if node.else_ is not None: 2108 self.set_label(else_label) 2109 self.dispatch(node.else_) 2110 2111 self.set_label(exit_label) 2112 self.drop_loop_labels() 2113 2114 # Prevent incorrect optimisation. 2115 2116 self.clear_active() 2117 2118 def visitWith(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "With") 2119 2120 def visitYield(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Yield") 2121 2122 # Useful data. 2123 2124 comparison_methods = { 2125 "==" : ("__eq__", "__ne__"), 2126 "!=" : ("__ne__", "__eq__"), 2127 "<" : ("__lt__", "__gt__"), 2128 "<=" : ("__le__", "__ge__"), 2129 ">=" : ("__ge__", "__le__"), 2130 ">" : ("__gt__", "__lt__"), 2131 "is" : None, 2132 "is not" : None, 2133 "in" : None, 2134 "not in" : None 2135 } 2136 2137 # vim: tabstop=4 expandtab shiftwidth=4