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