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