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