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