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