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