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