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