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