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, 2009 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 27 class Helper: 28 29 "Internal helper methods for AST visitors." 30 31 # Allocation-related methods. 32 33 def make_object(self, cls, n): 34 35 """ 36 Request a new object with the given class 'cls' and with 'n' attributes. 37 """ 38 39 # Load the class in order to locate the instance template. 40 41 self.new_op(LoadConst(cls)) 42 43 # NOTE: Object headers are one location. 44 45 self.new_op(MakeObject(n + 1)) 46 47 # Name-related methods. 48 49 def get_scope(self, name): 50 51 "Return the scope for the given 'name'." 52 53 if self.unit.has_key(name): 54 return "local" 55 elif self.module.has_key(name): 56 return "global" 57 else: 58 return "builtins" 59 60 def load_builtin(self, name, node): 61 62 "Generate an instruction loading 'name' for the given 'node'." 63 64 self.new_op(LoadAddress(self.get_builtin(name, node))) 65 66 def get_builtin_class(self, name, node): 67 68 "Return the built-in class with the given 'name' for the given 'node'." 69 70 return self.get_builtin(name, node).get_value() 71 72 def get_builtin(self, name, node): 73 74 """ 75 Return the built-in module definition for the given 'name', used by the 76 given 'node'. 77 """ 78 79 if self.builtins is not None: 80 try: 81 return self.builtins[name] 82 except KeyError: 83 raise TranslateError(self.module.full_name(), node, "No __builtins__ definition is available for name %r." % name) 84 else: 85 raise TranslateError(self.module.full_name(), node, "No __builtins__ module is available for name %r." % name) 86 87 # Code feature methods. 88 89 def new_block(self): 90 91 "Return a new code block." 92 93 return Block() 94 95 def set_block(self, block): 96 97 "Add the given 'block' to the unit's list of blocks." 98 99 self.optimiser.reset() 100 self.blocks.append(block) 101 102 def get_loop_blocks(self): 103 return self.loop_blocks[-1] 104 105 def add_loop_blocks(self, next_block, exit_block): 106 self.loop_blocks.append((next_block, exit_block)) 107 108 def drop_loop_blocks(self): 109 self.loop_blocks.pop() 110 111 def get_exception_blocks(self): 112 return self.exception_blocks[-1] 113 114 def add_exception_blocks(self, handler_block, exit_block): 115 self.exception_blocks.append((handler_block, exit_block)) 116 117 def drop_exception_blocks(self): 118 self.exception_blocks.pop() 119 120 # Assignment expression values. 121 122 def record_value(self, immediate=1): 123 124 """ 125 Record the current active value for an assignment. If the optional 126 'immediate' parameter if set to a false value always allocates new 127 temporary storage to hold the recorded value; otherwise, the 128 value-providing instruction may be replicated in order to provide the 129 active value later on. 130 """ 131 132 if immediate: 133 temp = self.optimiser.optimise_temp_storage() 134 else: 135 temp = self.get_temp() 136 self.expr_temp.append(temp) 137 138 def discard_value(self): 139 140 "Discard any temporary storage in use for the current assignment value." 141 142 self.discard_temp(self.expr_temp.pop()) 143 144 def set_source(self): 145 146 "Set the source of an assignment using the current assignment value." 147 148 self.optimiser.set_source(self.expr_temp[-1]) 149 150 # Optimise away constant storage if appropriate. 151 152 if self.optimiser.optimise_constant_storage(): 153 self.remove_op() 154 155 def is_immediate_user(self, node): 156 157 """ 158 Return whether 'node' is an immediate user of an assignment expression. 159 """ 160 161 return isinstance(node, (compiler.ast.AssName, compiler.ast.AssAttr)) 162 163 def has_immediate_usage(self, nodes): 164 165 """ 166 Return whether 'nodes' are all immediate users of an assignment expression. 167 """ 168 169 for n in nodes: 170 if not self.is_immediate_user(n): 171 return 0 172 return 1 173 174 # Temporary storage administration. 175 176 def get_temp(self): 177 178 """ 179 Add a temporary storage instruction for the current value and return a 180 sequence of access instructions. 181 """ 182 183 position_in_frame = self.reserve_temp() 184 self.new_op(StoreTemp(position_in_frame)) 185 return LoadTemp(position_in_frame) 186 187 def reserve_temp(self, temp_position=None): 188 189 """ 190 Reserve a new temporary storage position, or if the optional 191 'temp_position' is specified, ensure that this particular position is 192 reserved. 193 """ 194 195 if temp_position is not None: 196 pass 197 elif not self.temp_positions: 198 temp_position = 0 199 else: 200 temp_position = max(self.temp_positions) + 1 201 self.temp_positions.add(temp_position) 202 self.max_temp_position = max(self.max_temp_position, temp_position) 203 return self.unit.all_local_usage + temp_position # position in frame 204 205 def ensure_temp(self, instruction=None): 206 207 """ 208 Ensure that the 'instruction' is using a reserved temporary storage 209 position. 210 """ 211 212 if isinstance(instruction, LoadTemp): 213 temp_position = instruction.attr - self.unit.all_local_usage 214 self.reserve_temp(temp_position) 215 216 def discard_temp(self, instruction=None): 217 218 "Discard any temporary storage position used by 'instruction'." 219 220 if isinstance(instruction, LoadTemp): 221 temp_position = instruction.attr - self.unit.all_local_usage 222 self.free_temp(temp_position) 223 224 def free_temp(self, temp_position): 225 226 "Free the temporary storage position specified by 'temp_position'." 227 228 if temp_position in self.temp_positions: 229 self.temp_positions.remove(temp_position) 230 231 def set_frame_usage(self, node, extend): 232 233 """ 234 Ensure that the frame usage for the unit associated with 'node' is set 235 on the 'extend' instruction. 236 """ 237 238 ntemp = self.max_temp_position + 2 # include space for instantiators to expand backwards 239 extend.attr = ntemp + node.unit.local_usage # NOTE: See get_code for similar code. 240 241 # Code writing methods. 242 243 def new_op(self, op): 244 245 "Add 'op' to the generated code." 246 247 # Optimise load operations employed by this instruction. 248 249 self.optimiser.optimise_load_operations(op) 250 if self.optimiser.optimise_away_no_operations(op): 251 return 252 253 # Add the operation to the current block. 254 255 self.blocks[-1].code.append(op) 256 self.optimiser.set_new(op) 257 258 def remove_op(self): 259 260 "Remove the last instruction." 261 262 op = self.blocks[-1].code.pop() 263 self.optimiser.clear_active() 264 265 def replace_op(self, op): 266 267 "Replace the last added instruction with 'op'." 268 269 self.remove_op() 270 self.new_op(op) 271 272 def replace_active_value(self, op): 273 274 """ 275 Replace the value-providing active instruction with 'op' if appropriate. 276 """ 277 278 self.optimiser.remove_active_value() 279 self.new_op(op) 280 281 def last_op(self): 282 283 "Return the last added instruction." 284 285 try: 286 return self.blocks[-1].code[-1] 287 except IndexError: 288 return None 289 290 # Common methods. 291 292 def _visitAttr(self, node, classes): 293 294 """ 295 Visit the attribute-related 'node', generating instructions based on the 296 given 'classes'. 297 """ 298 299 self.dispatch(node.expr) 300 self._generateAttr(node, node.attrname, classes) 301 302 def _generateAttr(self, node, attrname, classes): 303 304 """ 305 Generate code for the access to 'attrname' using the given 'classes'. 306 """ 307 308 AddressInstruction, AddressContextInstruction, AddressContextCondInstruction, \ 309 AttrInstruction, AttrIndexInstruction, AttrIndexContextInstruction, \ 310 AttrIndexContextCondInstruction = classes 311 312 # Where the last operation (defining the attribute owner) yields a 313 # constant... 314 315 target_name = self.optimiser.optimise_constant_accessor() 316 317 # Only try and discover the position if the target can be resolved. 318 # Since instances cannot be constants, this involves classes and 319 # modules. 320 321 if target_name is not None: 322 323 # Access the object table to get the attribute position. 324 325 try: 326 table_entry = self.objtable.table[target_name] 327 except KeyError: 328 raise TranslateError(self.module.full_name(), node, 329 "No object entry exists for target %r." % target_name) 330 331 try: 332 pos = table_entry[attrname] 333 except KeyError: 334 raise TranslateError(self.module.full_name(), node, 335 "No attribute entry exists for name %r in target %r." % (attrname, target_name)) 336 337 # Produce a suitable instruction. 338 339 if AddressInstruction is not None: 340 self.replace_active_value(AddressInstruction(pos)) 341 else: 342 raise TranslateError(self.module.full_name(), node, 343 "Storing of class or module attribute %r via an object is not permitted." % attrname) 344 345 return 346 347 # Where the last operation involves the special 'self' name, check to 348 # see if the attribute is acceptably positioned and produce a direct 349 # access to the attribute. 350 351 # This is the only reliable way of detecting instance accesses at 352 # compile-time since in general, objects could be classes or modules, 353 # but 'self' should only refer to instances. 354 355 elif self.optimiser.optimise_self_access(self.unit, attrname): 356 357 # Either generate an instruction operating on an instance attribute. 358 359 try: 360 attr = self.unit.parent.instance_attributes()[attrname] 361 self.new_op(AttrInstruction(attr)) 362 return 363 364 # Or generate an instruction operating on a class attribute. 365 # NOTE: Any simple instruction providing self is not removed. 366 367 except KeyError: 368 369 try: 370 attr = self.unit.parent.all_attributes()[attrname] 371 372 # Switch the context if the class attribute is compatible with 373 # the instance. 374 375 if attr.defined_within_hierarchy(): 376 377 # Only permit loading (not storing) of class attributes via self. 378 379 if AddressContextInstruction is not None: 380 self.new_op(AddressContextInstruction(attr)) 381 else: 382 raise TranslateError(self.module.full_name(), node, 383 "Storing of class attribute %r via self not permitted." % attrname) 384 385 # Preserve the context if the class attribute comes from an 386 # incompatible class. 387 388 elif attr.defined_outside_hierarchy(): 389 390 # Only permit loading (not storing) of class attributes via self. 391 392 if AddressInstruction is not None: 393 self.new_op(AddressInstruction(attr)) 394 else: 395 raise TranslateError(self.module.full_name(), node, 396 "Storing of class attribute %r via self not permitted." % attrname) 397 398 # Otherwise, test for a suitable context at run-time. 399 400 else: 401 402 # Only permit loading (not storing) of class attributes via self. 403 404 if AddressContextCondInstruction is not None: 405 self.new_op(AddressContextCondInstruction(attr)) 406 else: 407 raise TranslateError(self.module.full_name(), node, 408 "Storing of class attribute %r via self not permitted." % attrname) 409 410 return 411 412 # Or delegate the attribute access to a general instruction 413 # since the kind of attribute cannot be deduced. 414 415 except KeyError: 416 pass 417 418 # Otherwise, perform a normal operation. 419 420 try: 421 index = self.objtable.get_index(attrname) 422 423 except self.objtable.TableError: 424 425 # If this error arises on generated code, check the names_used 426 # attribute on the Importer. 427 428 raise TranslateError(self.module.full_name(), node, 429 "No attribute entry exists for name %r." % attrname) 430 431 # NOTE: Test for class vs. instance attributes, generating 432 # NOTE: context-related instructions. 433 434 if AttrIndexContextCondInstruction is not None: 435 self.new_op(AttrIndexContextCondInstruction(index)) 436 437 # Store instructions do not need to consider context modifications. 438 439 else: 440 self.new_op(AttrIndexInstruction(index)) 441 442 # Invocations involve the following: 443 # 444 # 1. Reservation of a frame for the arguments 445 # 2. Identification of the target which is then held in temporary storage 446 # 3. Optional inclusion of a context (important for methods) 447 # 4. Preparation of the argument frame 448 # 5. Invocation of the target 449 # 6. Discarding of the frame 450 # 451 # In order to support nested invocations - such as a(b(c)) - use of the 452 # temporary storage is essential. 453 454 def _startCallFunc(self): 455 456 "Record the location of the invocation." 457 458 op = MakeFrame() 459 self.new_op(op) # records the start of the frame 460 self.frame_makers.append(op) 461 462 def _generateCallFunc(self, args, node): 463 464 """ 465 Support a generic function invocation using the given 'args', occurring 466 on the given 'node', where the expression providing the invocation 467 target has just been generated. 468 469 In other situations, the invocation is much simpler and does not need to 470 handle the full flexibility of a typical Python invocation. Internal 471 invocations, such as those employed by operators and certain 472 control-flow mechanisms, use predetermined arguments and arguably do not 473 need to support the same things as the more general invocations. 474 """ 475 476 target, context, temp = self._generateCallFuncContext() 477 self._generateCallFuncArgs(target, context, temp, args, node) 478 return temp, target 479 480 def _generateCallFuncContext(self): 481 482 """ 483 Produce code which loads and checks the context of the current 484 invocation, the instructions for whose target have already been 485 produced, returning a list of instructions which reference the 486 invocation target. 487 """ 488 489 t = self.optimiser.optimise_known_target() 490 if t: 491 target, context = t 492 if isinstance(target, Instance): # lambda object 493 target, context = None, None 494 else: 495 target, context = None, None 496 497 # Store the target in temporary storage for subsequent referencing. 498 # NOTE: This may not be appropriate for class invocations 499 # NOTE: (instantiation). 500 501 temp = self.optimiser.optimise_temp_storage() 502 503 # Where a target or context are not known or where an instance is known 504 # to be the context, load the context. 505 506 if target is None or isinstance(context, Instance): 507 self.new_op(temp) 508 self.new_op(LoadContext()) 509 self.new_op(StoreFrame(0)) 510 511 # Otherwise omit the context. 512 513 else: 514 pass # NOTE: Class methods should be supported. 515 516 return target, context, temp 517 518 def _generateCallFuncArgs(self, target, context, temp, args, node): 519 520 """ 521 Given invocation 'target' and 'context' information, the 'temp' 522 reference to the target, a list of nodes representing the 'args' 523 (arguments), generate instructions which load the arguments for the 524 invocation defined by the given 'node'. 525 """ 526 527 # Evaluate the arguments. 528 529 employed_positions = set() 530 employed_keywords = set() 531 extra_keywords = [] 532 533 # Find keyword arguments in advance in order to help resolve targets. 534 535 for arg in args: 536 if isinstance(arg, compiler.ast.Keyword): 537 employed_keywords.add(arg.name) 538 539 possible_targets = self.paramtable.all_possible_objects(employed_keywords) 540 541 # Note the presence of the context in the frame where appropriate. 542 543 if target is None or isinstance(context, Instance): 544 ncontext = 1 545 expect_context = 0 546 547 # Handle calls to classes. 548 # The resulting target must match that used in the actual invocation. 549 550 elif isinstance(target, Class): 551 ncontext = 0 552 expect_context = 0 553 target = target.get_instantiator() 554 555 # Method calls via classes. 556 557 elif isinstance(context, Class): 558 ncontext = 0 559 expect_context = 1 560 561 # Function calls. 562 563 else: 564 ncontext = 0 565 expect_context = 0 566 567 first = 1 568 frame_pos = ncontext 569 max_keyword_pos = -1 570 571 for arg in args: 572 573 # Handle positional and keyword arguments separately. 574 575 if isinstance(arg, compiler.ast.Keyword): 576 577 # Optimise where the target is known now. 578 579 if target is not None: 580 581 # Find the parameter table entry for the target. 582 583 target_name = target.full_name() 584 585 # Look for a callable with the precise target name. 586 587 table_entry = self.paramtable.table[target_name] 588 589 # Look the name up in the parameter table entry. 590 591 try: 592 pos = table_entry[arg.name] 593 594 # Where no position is found, this could be an extra keyword 595 # argument. 596 597 except KeyError: 598 extra_keywords.append(arg) 599 continue 600 601 # Test for illegal conditions. 602 603 if pos in employed_positions: 604 raise TranslateError(self.module.full_name(), node, 605 "Keyword argument %r overwrites parameter %r." % (arg.name, pos)) 606 607 employed_positions.add(pos) 608 609 # Generate code for the keyword and the positioning 610 # operation. 611 612 self.dispatch(arg.expr) 613 self.new_op(StoreFrame(pos)) 614 615 # Otherwise, generate the code needed to obtain the details of 616 # the parameter location. 617 618 else: 619 620 # Combine the target details with the name to get the location. 621 # See the access method on the List class. 622 623 try: 624 paramindex = self.paramtable.get_index(arg.name) 625 626 # Where no position is found, this could be an extra keyword 627 # argument. 628 629 except self.paramtable.TableError: 630 extra_keywords.append(arg) 631 continue 632 633 # Generate code for the keyword and the positioning 634 # operation. Get the value as the source of the assignment. 635 636 self.dispatch(arg.expr) 637 self.record_value() 638 639 # Store the source value using the callable's parameter 640 # table information. 641 642 self.new_op(temp) 643 self.new_op(StoreFrameIndex(paramindex)) 644 645 self.set_source() 646 self.discard_value() 647 648 # Record the highest possible frame position for this argument. 649 650 max_keyword_pos = max(max_keyword_pos, max(self.paramtable.all_attribute_positions(arg.name))) 651 652 else: 653 self.dispatch(arg) 654 self.new_op(StoreFrame(frame_pos)) 655 656 employed_positions.add(frame_pos) 657 658 # Check to see if the first argument is appropriate (compatible with 659 # the target where methods are being invoked via classes). 660 661 if first and expect_context: 662 663 # Drop any test if the target and the context are known. 664 665 if not self.optimiser.have_correct_self_for_target(context, self.unit): 666 667 continue_block = self.new_block() 668 669 self.new_op(CheckSelf()) 670 self.optimiser.set_source(temp) 671 self.new_op(JumpIfTrue(continue_block)) 672 673 # Where the context is inappropriate, drop the incomplete frame and 674 # raise an exception. 675 676 self.new_op(DropFrame()) 677 self.new_op(LoadResult()) 678 679 self.load_builtin("TypeError", node) 680 self.new_op(StoreException()) 681 self.new_op(RaiseException()) 682 683 self.set_block(continue_block) 684 685 first = 0 686 frame_pos += 1 687 688 # NOTE: Extra keywords are not supported. 689 # NOTE: Somehow, the above needs to be combined with * arguments. 690 691 if extra_keywords: 692 print "Warning: extra keyword argument(s) %s not handled." % ", ".join([arg.name for arg in extra_keywords]) 693 694 # Either test for a complete set of arguments. 695 696 if target is not None: 697 698 # Make sure that enough arguments have been given. 699 700 nargs_max = len(target.positional_names) 701 ndefaults = len(target.defaults) 702 nargs_min = nargs_max - ndefaults 703 704 for i in range(ncontext, nargs_min): 705 if i not in employed_positions: 706 raise TranslateError(self.module.full_name(), node, 707 "Argument %r not supplied for %r: need at least %d argument(s)." % (i+1, target.name, nargs_min)) 708 709 nargs = frame_pos 710 711 if nargs > nargs_max and not target.has_star and not target.has_dstar: 712 raise TranslateError(self.module.full_name(), node, 713 "Too many arguments for %r: need at most %d argument(s)." % (target.name, nargs_max)) 714 715 # Where defaults are involved, put them into the frame. 716 717 self._generateCallFuncDefaultArgs(target, temp, nargs_min, nargs_max, employed_positions) 718 719 # Set the frame size. 720 721 self._endCallFuncArgs(nargs_max) 722 723 # Or generate instructions to do this at run-time. 724 725 else: 726 max_pos = max(max(employed_positions or [-1]), max_keyword_pos, frame_pos - 1) 727 728 # Only check non-empty frames (using the callable's details). 729 730 if employed_positions or max_pos >= 0: 731 self.new_op(temp) 732 self.new_op(CheckFrame(max_pos + 1)) 733 734 # Set the frame size. 735 736 self._endCallFuncArgs(max_pos + 1) 737 738 def _generateCallFuncDefaultArgs(self, target, temp, nargs_min, nargs_max, employed_positions): 739 740 """ 741 For the given 'target' and 'temp' reference to the target, generate 742 default arguments for those positions in the range 'nargs_min'... 743 'nargs_max' which are not present in the 'employed_positions' 744 collection. 745 """ 746 747 # Where a lambda is involved, construct a dynamic object to hold the 748 # defaults. 749 750 dynamic = target.name is None 751 752 # Here, we use negative index values to visit the right hand end of 753 # the defaults list. 754 755 for pos in range(nargs_min, nargs_max): 756 if pos not in employed_positions: 757 if dynamic: 758 self.new_op(temp) 759 self.new_op(LoadAttr(target.default_attrs[pos - nargs_min])) 760 else: 761 self.new_op(LoadAddress(target.default_attrs[pos - nargs_min])) 762 self.new_op(StoreFrame(pos)) 763 764 def _doCallFunc(self, instruction, target=None): 765 766 "Make the invocation." 767 768 # For classes, the target itself is used, since the instantiator will be 769 # obtained via the class. 770 771 if isinstance(target, Class): 772 self.new_op(LoadConst(target)) 773 else: 774 self.new_op(instruction) 775 776 self.new_op(LoadCallable()) 777 self.new_op(JumpWithFrame()) 778 779 def _endCallFuncArgs(self, nargs): 780 781 "Set the frame size." 782 783 self.frame_makers[-1].attr = nargs 784 self.frame_makers.pop() 785 786 def _endCallFunc(self, instruction=None, target=None, load_result=1): 787 788 "Finish the invocation and tidy up afterwards." 789 790 self.new_op(DropFrame()) 791 if load_result: 792 self.new_op(LoadResult()) 793 794 # Discard any temporary storage instructions. 795 796 if instruction is not None: 797 self.discard_temp(instruction) 798 799 def _generateFunctionDefaults(self, function): 800 801 """ 802 Generate the default initialisation code for 'function', returning 803 a temporary storage reference if a dynamic object was created for the 804 function. 805 """ 806 807 attr_to_default = zip(function.default_attrs, function.defaults) 808 if not attr_to_default: 809 return None 810 811 # Where a lambda is involved, construct a dynamic object to hold the 812 # defaults. 813 814 dynamic = function.name is None 815 816 if dynamic: 817 self.make_object(self.get_builtin_class("function", function), len(attr_to_default)) 818 temp = self.get_temp() 819 820 for attr, default in attr_to_default: 821 self.dispatch(default) 822 823 self.record_value() 824 if dynamic: 825 self.new_op(temp) 826 self.new_op(StoreAttr(attr)) 827 else: 828 self.new_op(StoreAddress(attr)) 829 self.set_source() 830 self.discard_value() 831 832 if dynamic: 833 return temp 834 else: 835 return None 836 837 def _visitName(self, node, classes): 838 839 """ 840 Visit the name-related 'node', generating instructions based on the 841 given 'classes'. 842 """ 843 844 name = node.name 845 scope = self.get_scope(name) 846 #print self.module.name, node.lineno, name, scope 847 self._generateName(name, scope, classes, node) 848 849 def _generateName(self, name, scope, classes, node): 850 851 """ 852 Generate code for the access to 'name' in 'scope' using the given 853 'classes', and using the given 'node' as the source of the access. 854 """ 855 856 NameInstruction, AddressInstruction = classes 857 858 if scope == "local": 859 unit = self.unit 860 if isinstance(unit, Function): 861 self.new_op(NameInstruction(unit.all_locals()[name])) 862 elif isinstance(unit, Class): 863 self.new_op(AddressInstruction(unit.all_class_attributes()[name])) 864 elif isinstance(unit, Module): 865 self.new_op(AddressInstruction(unit.module_attributes()[name])) 866 else: 867 raise TranslateError(self.module.full_name(), node, "Program unit %r has no local %r." % (unit, name)) 868 869 elif scope == "global": 870 globals = self.module.module_attributes() 871 if globals.has_key(name): 872 self.new_op(AddressInstruction(globals[name])) 873 else: 874 raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r." % (self.module, name)) 875 876 else: 877 self.new_op(AddressInstruction(self.get_builtin(name, node))) 878 879 def _visitUnary(self, node): 880 881 """ 882 _t = node.expr 883 try: 884 _result = _t.__pos__() 885 except AttributeError: 886 raise TypeError 887 """ 888 889 method = unary_methods[node.__class__.__name__] 890 891 type_error_block = self.new_block() 892 end_block = self.new_block() 893 894 # Evaluate and store the operand in temporary storage. 895 896 self.dispatch(node.expr) 897 temp = self.optimiser.optimise_temp_storage() 898 899 self.new_op(temp) 900 901 # Get the method on temp. 902 903 self._generateAttr(node, method, self.attribute_load_instructions) 904 temp_method = self.optimiser.optimise_temp_storage() 905 906 self._handleAttributeError(node, type_error_block) 907 908 # Add arguments. 909 # NOTE: No support for defaults. 910 911 self._startCallFunc() 912 self.new_op(temp) # Explicit context as first argument. 913 self.new_op(StoreFrame(0)) 914 self._endCallFuncArgs(1) 915 self._doCallFunc(temp_method) 916 self._endCallFunc(temp_method) 917 self.new_op(Jump(end_block)) 918 919 # Store the result. 920 921 temp_out = self.get_temp() 922 923 # Raise a TypeError. 924 925 self.set_block(type_error_block) 926 self.load_builtin("TypeError", node) 927 self.new_op(StoreException()) 928 self.new_op(RaiseException()) 929 930 self.set_block(end_block) 931 932 # Produce the result. 933 934 self.new_op(temp_out) 935 936 # Compilation duties... 937 938 self.discard_temp(temp) 939 self.discard_temp(temp_out) 940 941 def _visitBinary(self, node): 942 943 """ 944 _t1 = node.left 945 _t2 = node.right 946 try: 947 _result = _t1.__add__(_t2) 948 if _result is NotImplemented: 949 raise AttributeError 950 except AttributeError: 951 try: 952 _result = _t2.__radd__(_t1) 953 if _result is NotImplemented: 954 raise AttributeError 955 except AttributeError: 956 raise TypeError 957 """ 958 959 left_method, right_method = binary_methods[node.__class__.__name__] 960 961 # Evaluate and store the left operand in temporary storage. 962 963 self.dispatch(node.left) 964 temp1 = self.optimiser.optimise_temp_storage() 965 966 # Evaluate and store the right operand in temporary storage. 967 968 self.dispatch(node.right) 969 temp2 = self.optimiser.optimise_temp_storage() 970 971 temp_out = self._generateBinary(node, temp1, temp2, left_method, right_method) 972 973 # Produce the result. 974 975 self.new_op(temp_out) 976 977 # Compilation duties... 978 979 self.discard_temp(temp1) 980 self.discard_temp(temp2) 981 self.discard_temp(temp_out) 982 983 def _generateBinary(self, node, temp1, temp2, left_method, right_method): 984 985 """ 986 For the given 'node', generate the binary operator pattern for the 987 operands 'temp1' and 'temp2', employing 'left_method' and 'right_method' 988 as defined for binary operators, but also used in comparisons (for which 989 this method is provided). 990 991 A temporary storage reference is returned from this method. 992 """ 993 994 right_block = self.new_block() 995 type_error_block = self.new_block() 996 end_block = self.new_block() 997 998 # Left method. 999 1000 temp_out = self._generateOpMethod(node, temp1, temp2, left_method, right_block, end_block) 1001 self.discard_temp(temp_out) # NOTE: Will re-use the same storage. 1002 1003 # Right method. 1004 1005 self.set_block(right_block) 1006 temp_out = self._generateOpMethod(node, temp2, temp1, right_method, type_error_block, end_block) 1007 1008 # Raise a TypeError. 1009 1010 self.set_block(type_error_block) 1011 self.load_builtin("TypeError", node) 1012 self.new_op(StoreException()) 1013 self.new_op(RaiseException()) 1014 1015 self.set_block(end_block) 1016 return temp_out 1017 1018 def _generateOpMethod(self, node, temp1, temp2, method_name, next_method_block, end_block): 1019 1020 """ 1021 For the given 'node', generate the operator method invocation using the 1022 operands 'temp1' and 'temp2', employing the given 'method_name', and 1023 jumping appropriately to 'next_method_block' where a NotImplemented 1024 result is returned, or to 'end_block' if the method call was successful. 1025 1026 A temporary storage reference is returned from this method. 1027 """ 1028 1029 end_attempt_block = self.new_block() 1030 1031 self.new_op(temp1) 1032 1033 # Get method on temp1. 1034 1035 self._generateAttr(node, method_name, self.attribute_load_instructions) 1036 temp_method = self.optimiser.optimise_temp_storage() 1037 1038 self._handleAttributeError(node, end_attempt_block) 1039 1040 # Add arguments. 1041 # NOTE: No support for defaults. 1042 1043 self._startCallFunc() 1044 self.new_op(temp1) 1045 self.new_op(StoreFrame(0)) 1046 self.new_op(temp2) 1047 self.new_op(StoreFrame(1)) 1048 self._endCallFuncArgs(2) 1049 self._doCallFunc(temp_method) 1050 self._endCallFunc(temp_method) 1051 1052 # Store the result. 1053 1054 temp_out = self.get_temp() 1055 1056 # Test for NotImplemented. 1057 # Don't actually raise an exception. 1058 1059 self.new_op(TestIdentityAddress(self.importer.get_predefined_constant("NotImplemented"))) 1060 self.new_op(JumpIfTrue(next_method_block)) 1061 self.new_op(Jump(end_block)) 1062 1063 # End method attempt. 1064 1065 self.set_block(end_attempt_block) 1066 return temp_out 1067 1068 def _handleAttributeError(self, node, end_call_block): 1069 1070 """ 1071 Add exception handling to the method acquisition instructions where the 1072 attribute access cannot be resolved at compile-time. 1073 """ 1074 1075 if not self.optimiser.optimise_known_target(): 1076 self.load_builtin("AttributeError", node) 1077 self.new_op(CheckException()) 1078 self.new_op(JumpIfTrue(end_call_block)) 1079 1080 def _generateSequence(self, sequence_type, node): 1081 1082 "Make a sequence of 'sequence_type' for the given program 'node'." 1083 1084 self.make_object(self.get_builtin_class(sequence_type, node), len(node.nodes)) 1085 temp = self.get_temp() 1086 1087 for i, n in enumerate(node.nodes): 1088 self.dispatch(n) 1089 self.record_value() 1090 self.new_op(temp) 1091 self.new_op(StoreAttr(Attr(i, None, None))) 1092 self.set_source() 1093 self.discard_value() 1094 1095 self.new_op(temp) 1096 self.discard_temp(temp) 1097 1098 def _generateTestBoolean(self, node, temp): 1099 1100 """ 1101 Generate a test of the boolean status of the current value for the given 1102 program 'node'. 1103 """ 1104 1105 # Get method on temp. 1106 # NOTE: Using __bool__ instead of __nonzero__. 1107 1108 self._generateAttr(node, "__bool__", self.attribute_load_instructions) 1109 temp_method = self.optimiser.optimise_temp_storage() 1110 1111 self._startCallFunc() 1112 self.new_op(temp) 1113 self.new_op(StoreFrame(0)) 1114 self._endCallFuncArgs(1) 1115 self._doCallFunc(temp_method) 1116 self._endCallFunc(temp_method) 1117 1118 self.discard_temp(temp_method) 1119 1120 # Convert result to boolean (a StoreBoolean operation). 1121 1122 self.new_op(TestIdentityAddress(self.importer.get_predefined_constant("True"))) 1123 1124 def _generateLoadBoolean(self, node): 1125 1126 """ 1127 Generate instructions to load the appropriate value given the current 1128 boolean status. 1129 """ 1130 1131 true_block = self.new_block() 1132 end_block = self.new_block() 1133 1134 self.new_op(JumpIfTrue(true_block)) 1135 self.new_op(LoadConst(self.importer.get_predefined_constant("False"))) 1136 self.new_op(Jump(end_block)) 1137 1138 self.set_block(true_block) 1139 self.new_op(LoadConst(self.importer.get_predefined_constant("True"))) 1140 1141 self.set_block(end_block) 1142 1143 # vim: tabstop=4 expandtab shiftwidth=4