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