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