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