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