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