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