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