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 = [ 35 "constant_storage", "known_target", "self_access", "temp_storage", "load_operations", "no_operations", "unused_results" 36 ] 37 38 attribute_load_instructions = (LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex) 39 attribute_store_instructions = (None, None, StoreAttr, StoreAttrIndex) 40 name_load_instructions = (LoadName, LoadAddress) 41 name_store_instructions = (StoreName, StoreAddress) 42 43 def __init__(self, module, importer, optimisations=None): 44 45 """ 46 Initialise the translation with an inspected 'module', the 'importer' 47 and optional 'optimisations'. See the 'supported_optimisations' 48 attribute of this class for permitted values. 49 """ 50 51 ASTVisitor.__init__(self) 52 self.visitor = self 53 self.module = module 54 55 # Global program dependencies. 56 57 self.importer = importer 58 self.objtable = self.importer.get_object_table() 59 self.paramtable = self.importer.get_parameter_table() 60 self.builtins = self.importer.modules.get("__builtins__") 61 62 # Desired optimisations. 63 64 self.optimisations = set(optimisations or []) 65 66 # The current unit being translated. 67 68 self.unit = None 69 70 # The current "active" instruction. 71 # As a rule, this will become the last instruction, but some 72 # control-flow operations will flush the "active" instruction. 73 74 self.active = None 75 76 # The temporary storage used by the current assignment expression. 77 78 self.expr_temp = None 79 80 # Wiring within the code. 81 82 self.labels = {} 83 self.label_number = 0 84 self.loop_labels = [] 85 self.exception_labels = [] 86 87 # The code itself. This is limited to the code for a particular block 88 # being processed. Also retained is information about temporary values. 89 90 self.code = None 91 self.temp_positions = set() 92 self.max_temp_position = -1 93 94 def __repr__(self): 95 return "Translation(%r)" % self.module 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_positions = set() 104 105 if self.module.module is not None: 106 self.dispatch(self.module.module) 107 108 self.unit.temp_usage = self.max_temp_position + 1 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_positions = set() 118 119 if unit.astnode is not None: 120 self.dispatch(unit.astnode) 121 122 self.unit.temp_usage = self.max_temp_position + 1 123 return self.code 124 125 # Name-related methods. 126 127 def get_scope(self, name): 128 129 "Return the scope for the given 'name'." 130 131 if self.unit.has_key(name): 132 return "local" 133 elif self.module.has_key(name): 134 return "global" 135 else: 136 return "builtins" 137 138 def load_builtin(self, name, node): 139 140 "Generate an instruction loading 'name' for the given 'node'." 141 142 self.new_op(LoadAddress(self.get_builtin(name, node))) 143 144 def get_builtin(self, name, node): 145 146 """ 147 Return the built-in module definition for the given 'name', used by the 148 given 'node'. 149 """ 150 151 if self.builtins is not None: 152 try: 153 return self.builtins[name] 154 except KeyError: 155 raise TranslateError(self.module.full_name(), node, "No __builtins__ definition is available for name %r." % name) 156 else: 157 raise TranslateError(self.module.full_name(), node, "No __builtins__ module is available for name %r." % name) 158 159 # Code feature methods. 160 161 def new_label(self): 162 163 "Return a new label object for use with set_label." 164 165 number = self.label_number 166 label = Label(number) 167 self.labels[label] = label 168 self.label_number += 1 169 return label 170 171 def set_label(self, label): 172 173 """ 174 Set the location of 'label' to that within the entire image: the 175 location within the code combined with location of the code unit. 176 """ 177 178 label.location = len(self.code) + self.unit.code_location 179 180 def get_loop_labels(self): 181 return self.loop_labels[-1] 182 183 def add_loop_labels(self, next_label, exit_label): 184 self.loop_labels.append((next_label, exit_label)) 185 186 def drop_loop_labels(self): 187 self.loop_labels.pop() 188 189 def get_exception_labels(self): 190 return self.exception_labels[-1] 191 192 def add_exception_labels(self, handler_label, exit_label): 193 self.exception_labels.append((handler_label, exit_label)) 194 195 def drop_exception_labels(self): 196 self.exception_labels.pop() 197 198 # Assignment expression values. 199 200 def record_value(self): 201 self.expr_temp = self._optimise_temp_storage() 202 203 def discard_value(self): 204 self.discard_temp(self.expr_temp) 205 self.expr_temp = None 206 207 def set_source(self): 208 if self.active is not None: 209 self.active.source = self.expr_temp 210 211 # Optimise away constant storage if appropriate. 212 213 self._optimise_constant_storage() 214 215 # Temporary storage administration. 216 217 def get_temp(self): 218 219 """ 220 Add a temporary storage instruction for the current value and return a 221 sequence of access instructions. 222 """ 223 224 temp_position = self.reserve_temp() 225 self.new_op(StoreTemp(temp_position)) 226 return LoadTemp(temp_position) 227 228 def reserve_temp(self): 229 if not self.temp_positions: 230 temp_position = 0 231 else: 232 temp_position = max(self.temp_positions) + 1 233 self.temp_positions.add(temp_position) 234 self.max_temp_position = max(self.max_temp_position, temp_position) 235 return temp_position 236 237 def discard_temp(self, instruction=None): 238 if isinstance(instruction, LoadTemp): 239 self.temp_positions.remove(instruction.attr) 240 241 def cancel_temp(self, temp_position): 242 self.temp_positions.remove(temp_position) 243 244 # Code writing methods. 245 246 def new_op(self, op): 247 248 "Add 'op' to the generated code." 249 250 # Optimise load operations employed by this instruction. 251 252 self._optimise_load_operations(op) 253 if self._optimise_away_no_operations(op): 254 return 255 256 self.code.append(op) 257 self.active = op 258 259 def remove_op(self): 260 261 "Remove the last instruction." 262 263 op = self.code.pop() 264 self.active = None 265 266 def replace_op(self, op): 267 268 "Replace the last added instruction with 'op'." 269 270 self.remove_op() 271 self.new_op(op) 272 273 def last_op(self): 274 275 "Return the last added instruction." 276 277 try: 278 return self.code[-1] 279 except IndexError: 280 return None 281 282 # Optimisation tests. 283 284 def _should_optimise_constant_storage(self): 285 return "constant_storage" in self.optimisations 286 287 def _should_optimise_known_target(self): 288 return "known_target" in self.optimisations 289 290 def _should_optimise_self_access(self): 291 return "self_access" in self.optimisations 292 293 def _should_optimise_temp_storage(self): 294 return "temp_storage" in self.optimisations 295 296 def _should_optimise_load_operations(self): 297 return "load_operations" in self.optimisations 298 299 def _should_optimise_away_no_operations(self): 300 return "no_operations" in self.optimisations 301 302 def _should_optimise_unused_results(self): 303 return "unused_results" in self.optimisations 304 305 # Simple tests. 306 307 def _is_constant_input(self, instruction): 308 309 "Return whether 'instruction' provides a constant input." 310 311 return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 or \ 312 isinstance(instruction, LoadConst) 313 314 def _is_constant_target(self, instruction): 315 316 "Return whether 'instruction' provides a constant target." 317 318 return isinstance(instruction, (StoreName, StoreAddress)) and \ 319 instruction.attr.assignments == 1 320 321 def _is_simple_input(self, instruction): 322 323 "Return whether 'instruction' provides a simple input." 324 325 return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadAddress, MakeObject)) 326 327 def _is_simple_input_user(self, instruction): 328 329 "Return whether 'instruction' can use simple input from the current value." 330 331 return isinstance(instruction, ( 332 StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored 333 LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced 334 StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced 335 TestIdentity # as one of the operands 336 )) 337 338 def _is_resultant_no_operation(self, instruction): 339 340 """ 341 Return whether 'instruction' merely stores its input where the input 342 originally came from. 343 """ 344 345 return ( 346 isinstance(instruction.input, LoadTemp) and isinstance(instruction, StoreTemp) and 347 instruction.input.attr == instruction.attr) or ( 348 isinstance(instruction.input, LoadResult) and isinstance(instruction, StoreResult) 349 ) 350 351 def _is_input(self, instruction): 352 353 "Return whether 'instruction' provides an input." 354 355 return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadBoolean) + self.attribute_load_instructions) 356 357 # Convenience tests. 358 359 def _have_constant_input(self): 360 361 "Return whether the active instruction provides a constant input." 362 363 return self._is_constant_input(self.active) 364 365 _have_known_target = _have_constant_input 366 367 def _have_constant_target(self): 368 369 "Return whether the active instruction provides a constant target." 370 371 return self._is_constant_target(self.active) 372 373 def _have_constant_source(self): 374 375 "Return whether the active instruction has a constant source." 376 377 return self._is_constant_input(self.active.source) 378 379 def _have_simple_input(self): 380 381 "Return whether the active instruction provides a simple input." 382 383 return self._is_simple_input(self.active) 384 385 def _have_input(self): 386 387 "Return whether the active instruction provides an input." 388 389 return self._is_input(self.active) 390 391 def _have_self_input(self): 392 393 "Return whether the active instruction is a reference to self." 394 395 return isinstance(self.unit, Function) and \ 396 self.unit.is_method() and isinstance(self.active, LoadName) and \ 397 self.active.attr.name == "self" 398 399 def _have_temp_compatible_access(self): 400 401 """ 402 Indicate whether the active instruction can be used in place of access 403 to a temporary variable retaining the result of the last instruction. 404 """ 405 406 # LoadResult cannot be relied upon, since in general the result register 407 # could be updated since first being referenced. 408 409 return isinstance(self.active, (LoadName, LoadTemp, LoadAddress, LoadConst)) 410 411 # Optimisation methods. See the supported_optimisations class attribute. 412 413 def _optimise_constant_storage(self): 414 415 """ 416 Where the last operation stores a constant into a target which is also 417 constant, optimise away both operations. 418 """ 419 420 if self._should_optimise_constant_storage() and \ 421 self._have_constant_target() and \ 422 self._have_constant_source(): 423 424 self.remove_op() 425 return 1 426 else: 427 return 0 428 429 def _optimise_known_target(self): 430 431 """ 432 Where the target of an invocation is known, provide information about it 433 and its context. If a class is being invoked and the conditions are 434 appropriate, get information about the specific initialiser. 435 """ 436 437 if self._should_optimise_known_target() and self._have_known_target(): 438 last = self.last_op() 439 target = last.attr.value 440 context = last.attr.context 441 442 # Handle calls to classes. 443 444 if isinstance(target, Class): 445 target = target.get_instantiator() 446 context = Undefined() 447 448 # A special context is chosen to avoid generating unnecessary 449 # context loading and checking instructions. 450 451 return target, context 452 else: 453 return None 454 455 def _optimise_self_access(self, attrname, classes, node): 456 457 """ 458 Where the provided 'attrname' accesses an attribute which occupies the 459 same position in all possible objects which can be accessed, generate an 460 instruction using one of the given 'classes', accessing the attribute 461 directly. 462 """ 463 464 AddressInstruction, AddressContextInstruction, AttrInstruction = classes 465 466 if self._should_optimise_self_access() and self._have_self_input() and \ 467 not self.unit.is_relocated(attrname): 468 469 # Either generate an instruction operating on an instance attribute. 470 471 try: 472 attr = self.unit.parent.instance_attributes()[attrname] 473 self.new_op(AttrInstruction(attr)) 474 475 # Or generate an instruction operating on a class attribute. 476 477 except KeyError: 478 attr = self.unit.parent.all_attributes()[attrname] 479 new_attr = attr.via_instance() 480 481 # Only permit loading (not storing) of class attributes via self. 482 483 if AddressContextInstruction is not None: 484 self.new_op(AddressContextInstruction(new_attr)) 485 else: 486 raise TranslateError(self.module.full_name(), node, 487 "Storing of class attribute %r via self not permitted." % attrname) 488 489 return 1 490 else: 491 return 0 492 493 def _optimise_temp_storage(self): 494 495 """ 496 Where the next operation would involve storing a value into temporary 497 storage at 'temp_position', record and remove any simple instruction 498 which produced the value to be stored such that instead of subsequently 499 accessing the temporary storage, that instruction is substituted. 500 501 If no optimisation can be achieved, a StoreTemp instruction is produced 502 and the appropriate LoadTemp instruction is returned. 503 504 Restriction: for use only in situations where the source of the 505 temporary data will not be disturbed between its first access and its 506 subsequent use. 507 """ 508 509 if self._should_optimise_temp_storage() and \ 510 self._have_temp_compatible_access(): 511 512 last = self.last_op() 513 self.remove_op() 514 return last 515 else: 516 return self.get_temp() 517 518 def _optimise_load_operations(self, instruction): 519 520 """ 521 Incorporate previous load operations into other operations. 522 """ 523 524 if self._should_optimise_load_operations() and \ 525 self._have_simple_input() and \ 526 self._is_simple_input_user(instruction): 527 528 last = self.last_op() 529 self.remove_op() 530 instruction.input = last 531 532 def _optimise_away_no_operations(self, instruction): 533 534 """ 535 Optimise away operations which just store their inputs in the place 536 the inputs originally came from. 537 """ 538 539 if self._should_optimise_away_no_operations() and \ 540 self._is_resultant_no_operation(instruction): 541 542 return 1 543 else: 544 return 0 545 546 def _optimise_unused_results(self): 547 548 "Discard results which will not be used." 549 550 if self._have_input(): 551 self.remove_op() 552 553 # Visitor methods. 554 555 def default(self, node, *args): 556 raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__) 557 558 def dispatch(self, node, *args): 559 return ASTVisitor.dispatch(self, node, *args) 560 561 # Internal helper methods. 562 563 def _visitAttr(self, node, classes): 564 565 """ 566 Visit the attribute-related 'node', generating instructions based on the 567 given 'classes'. 568 """ 569 570 self.dispatch(node.expr) 571 self._generateAttr(node, node.attrname, classes) 572 573 def _generateAttr(self, node, attrname, classes): 574 575 """ 576 Generate code for the access to 'attrname' using the given 'classes'. 577 """ 578 579 AddressInstruction, AddressContextInstruction, AttrInstruction, AttrIndexInstruction = classes 580 581 # Where the last operation (defining the attribute owner) yields a 582 # constant... 583 584 if self._have_constant_input(): 585 last = self.active 586 587 # Get the details of the access. 588 589 if isinstance(last.attr, Const): 590 target_name = last.attr.value_type_name() 591 else: 592 target = last.attr.value 593 594 if isinstance(target, Const): 595 target_name = target.value_type_name() 596 elif isinstance(target, Instance): 597 target_name = None # skip production of optimised code 598 else: 599 target_name = target.full_name() 600 601 # Only try and discover the position if the target can be resolved. 602 603 if target_name is not None: 604 605 # Access the object table to get the attribute position. 606 607 try: 608 table_entry = self.objtable.table[target_name] 609 except KeyError: 610 raise TranslateError(self.module.full_name(), node, 611 "No object entry exists for target %r." % target_name) 612 613 try: 614 pos = table_entry[attrname] 615 except KeyError: 616 raise TranslateError(self.module.full_name(), node, 617 "No attribute entry exists for name %r in target %r." % (attrname, target_name)) 618 619 # Produce a suitable instruction. 620 621 if AddressInstruction is not None: 622 self.replace_op(AddressInstruction(pos)) 623 else: 624 raise TranslateError(self.module.full_name(), node, 625 "Storing of class or module attribute %r via an object is not permitted." % attrname) 626 627 return 628 629 # Where the last operation involves the special 'self' name, check to 630 # see if the attribute is acceptably positioned and produce a direct 631 # access to the attribute. 632 633 elif self._optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction), node): 634 return 635 636 # Otherwise, perform a normal operation. 637 638 try: 639 index = self.objtable.get_index(attrname) 640 except self.objtable.TableError: 641 raise TranslateError(self.module.full_name(), node, 642 "No attribute entry exists for name %r." % attrname) 643 644 self.new_op(AttrIndexInstruction(index)) 645 646 # Invocations involve the following: 647 # 648 # 1. Reservation of a frame for the arguments 649 # 2. Identification of the target which is then held in temporary storage 650 # 3. Optional inclusion of a context (important for methods) 651 # 4. Preparation of the argument frame 652 # 5. Invocation of the target 653 # 6. Discarding of the frame 654 # 655 # In order to support nested invocations - eg. a(b(c)) - use of the 656 # temporary storage is essential. 657 658 def _startCallFunc(self): 659 660 "Record the location of the invocation." 661 662 self.new_op(MakeFrame()) # records the start of the frame 663 664 def _generateCallFunc(self, args, node): 665 666 """ 667 Support a generic function invocation using the given 'args', occurring 668 on the given 'node', where the expression providing the invocation 669 target has just been generated. 670 671 In other situations, the invocation is much simpler and does not need to 672 handle the full flexibility of a typical Python invocation. Internal 673 invocations, such as those employed by operators and certain 674 control-flow mechanisms, use predetermined arguments and arguably do not 675 need to support the same things as the more general invocations. 676 """ 677 678 target, context, temp = self._generateCallFuncContext() 679 self._generateCallFuncArgs(target, context, temp, args, node) 680 return temp 681 682 def _generateCallFuncContext(self): 683 684 """ 685 Produce code which loads and checks the context of the current 686 invocation, the instructions for whose target have already been 687 produced, returning a list of instructions which reference the 688 invocation target. 689 """ 690 691 t = self._optimise_known_target() 692 if t: 693 target, context = t 694 else: 695 target, context = None, None 696 697 # Store the target in temporary storage for subsequent referencing. 698 699 temp = self._optimise_temp_storage() 700 701 # Where a target or context are not known or where an instance is known 702 # to be the context, load the context. 703 704 if context is None or isinstance(context, Instance): 705 self.new_op(temp) 706 self.new_op(LoadContext()) 707 self.new_op(StoreFrame(0)) 708 709 # Otherwise omit the context. 710 711 else: 712 pass # NOTE: Class methods should be supported. 713 714 return target, context, temp 715 716 def _generateCallFuncArgs(self, target, context, temp, args, node): 717 718 """ 719 Given invocation 'target' and 'context' information, the 'temp' 720 reference to the target, a list of nodes representing the 'args' 721 (arguments), generate instructions which load the arguments for the 722 invocation defined by the given 'node'. 723 """ 724 725 # Evaluate the arguments. 726 727 employed_positions = set() 728 extra_keywords = [] 729 730 # Note the presence of the context in the frame where appropriate. 731 732 if context is None or isinstance(context, Instance): 733 ncontext = 1 734 expect_context = 0 735 elif isinstance(context, Class): 736 ncontext = 0 737 expect_context = 1 738 else: 739 ncontext = 0 740 expect_context = 0 741 742 first = 1 743 frame_pos = ncontext 744 max_keyword_pos = -1 745 746 for arg in args: 747 748 # Handle positional and keyword arguments separately. 749 750 if isinstance(arg, compiler.ast.Keyword): 751 752 # Optimise where the target is known now. 753 754 if target is not None: 755 756 # Find the parameter table entry for the target. 757 758 target_name = target.full_name() 759 760 # Look for a callable with the precise target name. 761 762 table_entry = self.paramtable.table[target_name] 763 764 # Look the name up in the parameter table entry. 765 766 try: 767 pos = table_entry[arg.name] 768 769 # Where no position is found, this could be an extra keyword 770 # argument. 771 772 except KeyError: 773 extra_keywords.append(arg) 774 continue 775 776 # Test for illegal conditions. 777 778 if pos in employed_positions: 779 raise TranslateError(self.module.full_name(), node, 780 "Keyword argument %r overwrites parameter %r." % (arg.name, pos)) 781 782 employed_positions.add(pos) 783 784 # Generate code for the keyword and the positioning 785 # operation. 786 787 self.dispatch(arg.expr) 788 self.new_op(StoreFrame(pos)) 789 790 # Otherwise, generate the code needed to obtain the details of 791 # the parameter location. 792 793 else: 794 795 # Combine the target details with the name to get the location. 796 # See the access method on the List class. 797 798 try: 799 paramindex = self.paramtable.get_index(arg.name) 800 801 # Where no position is found, this could be an extra keyword 802 # argument. 803 804 except self.paramtable.TableError: 805 extra_keywords.append(arg) 806 continue 807 808 # Generate code for the keyword and the positioning 809 # operation. 810 811 self.dispatch(arg.expr) 812 self.new_op(StoreFrameIndex(paramindex)) 813 814 # use (callable+0)+paramindex+table 815 # checks embedded offset against (callable+0) 816 # moves the current value to frame+position 817 818 # Record the highest possible frame position for this argument. 819 820 max_keyword_pos = max(max_keyword_pos, max(self.paramtable.all_attribute_positions(arg.name))) 821 822 else: 823 self.dispatch(arg) 824 self.new_op(StoreFrame(frame_pos)) 825 826 employed_positions.add(frame_pos) 827 828 # Check to see if the first argument is appropriate (compatible with 829 # the target where methods are being invoked via classes). 830 831 if first and expect_context: 832 continue_label = self.new_label() 833 self.new_op(CheckSelf()) 834 self.new_op(JumpIfTrue(continue_label)) 835 836 # Where the context is inappropriate, drop the incomplete frame and 837 # raise an exception. 838 839 self.new_op(DropFrame()) 840 self.new_op(LoadResult()) 841 842 self.load_builtin("TypeError", node) 843 self.new_op(StoreException()) 844 self.new_op(RaiseException()) 845 self.set_label(continue_label) 846 847 first = 0 848 frame_pos += 1 849 850 # NOTE: Extra keywords are not supported. 851 # NOTE: Somehow, the above needs to be combined with * arguments. 852 853 if extra_keywords: 854 print "Warning: extra keyword argument(s) %s not handled." % ", ".join([arg.name for arg in extra_keywords]) 855 856 # Either test for a complete set of arguments. 857 858 if target is not None: 859 860 # Make sure that enough arguments have been given. 861 862 nargs_max = len(target.positional_names) 863 ndefaults = len(target.defaults) 864 nargs_min = nargs_max - ndefaults 865 866 for i in range(ncontext, nargs_min): 867 if i not in employed_positions: 868 raise TranslateError(self.module.full_name(), node, 869 "Argument %r not supplied for %r: need at least %d argument(s)." % (i+1, target.name, nargs_min)) 870 871 nargs = len(args) 872 873 if nargs > nargs_max and not target.has_star and not target.has_dstar: 874 raise TranslateError(self.module.full_name(), node, 875 "Too many arguments for %r: need at most %d argument(s)." % (target.name, nargs_max)) 876 877 # Where defaults are involved, put them into the frame. 878 879 self._generateCallFuncDefaultArgs(target, temp, nargs_min, nargs_max, employed_positions) 880 881 # Or generate instructions to do this at run-time. 882 # NOTE: CheckFrame has to check the number of arguments and to fill in 883 # NOTE: defaults; it also has to shift the invocation frame according to 884 # NOTE: the context in use. 885 886 else: 887 888 # Only check non-empty frames. 889 890 if employed_positions or max_keyword_pos >= 0: 891 max_pos = max(max(employed_positions), max_keyword_pos, frame_pos - 1) 892 self.new_op(CheckFrame(max_pos + 1)) 893 894 def _generateCallFuncDefaultArgs(self, target, temp, nargs_min, nargs_max, employed_positions): 895 896 """ 897 For the given 'target' and 'temp' reference to the target, generate 898 default arguments for those positions in the range 'nargs_min'... 899 'nargs_max' which are not present in the 'employed_positions' 900 collection. 901 """ 902 903 # Where a lambda is involved, construct a dynamic object to hold the 904 # defaults. 905 906 dynamic = target.name is None 907 908 # Here, we use negative index values to visit the right hand end of 909 # the defaults list. 910 911 for pos in range(nargs_min, nargs_max): 912 if pos not in employed_positions: 913 if dynamic: 914 self.new_op(temp) 915 self.new_op(LoadAttr(target.default_attrs[pos - nargs_min])) 916 else: 917 self.new_op(LoadAddress(target.default_attrs[pos - nargs_min])) 918 self.new_op(StoreFrame(pos)) 919 920 def _doCallFunc(self, instruction): 921 922 "Make the invocation." 923 924 self.new_op(instruction) 925 self.new_op(JumpWithFrame()) 926 927 def _endCallFunc(self, instruction=None, load_result=1): 928 929 "Finish the invocation and tidy up afterwards." 930 931 self.new_op(DropFrame()) 932 if load_result: 933 self.new_op(LoadResult()) 934 935 # Discard any temporary storage instructions. 936 937 if instruction is not None: 938 self.discard_temp(instruction) 939 940 def _generateFunctionDefaults(self, function): 941 942 """ 943 Generate the default initialisation code for 'function', returning 944 a temporary storage reference if a dynamic object was created for the 945 function. 946 """ 947 948 attr_to_default = zip(function.default_attrs, function.defaults) 949 if not attr_to_default: 950 return None 951 952 # Where a lambda is involved, construct a dynamic object to hold the 953 # defaults. 954 955 dynamic = function.name is None 956 957 if dynamic: 958 self.new_op(MakeObject(("function", len(attr_to_default)))) 959 temp = self.get_temp() 960 961 for attr, default in attr_to_default: 962 self.dispatch(default) 963 964 self.record_value() 965 if dynamic: 966 self.new_op(temp) 967 self.new_op(StoreAttr(attr)) 968 else: 969 self.new_op(StoreAddress(attr)) 970 self.set_source() 971 self.discard_value() 972 973 if dynamic: 974 return temp 975 else: 976 return None 977 978 def _visitName(self, node, classes): 979 980 """ 981 Visit the name-related 'node', generating instructions based on the 982 given 'classes'. 983 """ 984 985 name = node.name 986 scope = self.get_scope(name) 987 #print self.module.name, node.lineno, name, scope 988 self._generateName(name, scope, classes, node) 989 990 def _generateName(self, name, scope, classes, node): 991 992 """ 993 Generate code for the access to 'name' in 'scope' using the given 994 'classes', and using the given 'node' as the source of the access. 995 """ 996 997 NameInstruction, AddressInstruction = classes 998 999 if scope == "local": 1000 unit = self.unit 1001 if isinstance(unit, Function): 1002 self.new_op(NameInstruction(unit.all_locals()[name])) 1003 elif isinstance(unit, Class): 1004 self.new_op(AddressInstruction(unit.all_class_attributes()[name])) 1005 elif isinstance(unit, Module): 1006 self.new_op(AddressInstruction(unit.module_attributes()[name])) 1007 else: 1008 raise TranslateError(self.module.full_name(), node, "Program unit %r has no local %r." % (unit, name)) 1009 1010 elif scope == "global": 1011 globals = self.module.module_attributes() 1012 if globals.has_key(name): 1013 self.new_op(AddressInstruction(globals[name])) 1014 else: 1015 raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r." % (self.module, name)) 1016 1017 else: 1018 self.new_op(AddressInstruction(self.get_builtin(name, node))) 1019 1020 def _visitUnary(self, node, method): 1021 1022 """ 1023 _t = node.expr 1024 try: 1025 _result = _t.__pos__() 1026 except AttributeError: 1027 raise TypeError 1028 """ 1029 1030 end_call_label = self.new_label() 1031 end_label = self.new_label() 1032 1033 # Evaluate and store the operand in temporary storage. 1034 1035 self.dispatch(node.expr) 1036 temp = self._optimise_temp_storage() 1037 1038 # Produce the invocation. 1039 1040 self._startCallFunc() 1041 self.new_op(temp) 1042 1043 # Get the method on temp. 1044 1045 self._generateAttr(node, method, self.attribute_load_instructions) 1046 temp_method = self._optimise_temp_storage() 1047 1048 self._handleAttributeError(node, end_call_label) 1049 1050 # Add arguments. 1051 # NOTE: No support for defaults. 1052 1053 self.new_op(temp) # Explicit context as first argument. 1054 self.new_op(StoreFrame(0)) 1055 self._doCallFunc(temp_method) 1056 self._endCallFunc(temp_method) 1057 self.new_op(Jump(end_label)) 1058 1059 # End method attempt. 1060 1061 self.set_label(end_call_label) 1062 self._endCallFunc() # From the method call. 1063 1064 # Raise a TypeError. 1065 1066 self.load_builtin("TypeError", node) 1067 self.new_op(StoreException()) 1068 self.new_op(RaiseException()) 1069 1070 self.set_label(end_label) 1071 1072 # Compilation duties... 1073 1074 self.discard_temp(temp) 1075 1076 def _visitBinary(self, node, left_method, right_method): 1077 1078 """ 1079 _t1 = node.left 1080 _t2 = node.right 1081 try: 1082 _result = _t1.__add__(_t2) 1083 if _result is NotImplemented: 1084 raise AttributeError 1085 except AttributeError: 1086 try: 1087 _result = _t2.__radd__(_t1) 1088 if _result is NotImplemented: 1089 raise AttributeError 1090 except AttributeError: 1091 raise TypeError 1092 """ 1093 1094 # Evaluate and store the left operand in temporary storage. 1095 1096 self.dispatch(node.left) 1097 temp1 = self._optimise_temp_storage() 1098 1099 # Evaluate and store the right operand in temporary storage. 1100 1101 self.dispatch(node.right) 1102 temp2 = self._optimise_temp_storage() 1103 1104 self._generateBinary(node, temp1, temp2, left_method, right_method) 1105 1106 # Compilation duties... 1107 1108 self.discard_temp(temp1) 1109 self.discard_temp(temp2) 1110 1111 def _generateBinary(self, node, temp1, temp2, left_method, right_method): 1112 1113 """ 1114 For the given 'node', generate the binary operator pattern for the 1115 operands 'temp1' and 'temp2', employing 'left_method' and 'right_method' 1116 as defined for binary operators, but also used in comparisons (for which 1117 this method is provided). 1118 """ 1119 1120 right_label = self.new_label() 1121 type_error_label = self.new_label() 1122 end_label = self.new_label() 1123 1124 # Left method. 1125 1126 self._generateOpMethod(node, temp1, temp2, left_method, right_label, end_label) 1127 1128 # Right method. 1129 1130 self.set_label(right_label) 1131 self._generateOpMethod(node, temp2, temp1, right_method, type_error_label, end_label) 1132 1133 # Raise a TypeError. 1134 1135 self.set_label(type_error_label) 1136 self.load_builtin("TypeError", node) 1137 self.new_op(StoreException()) 1138 self.new_op(RaiseException()) 1139 1140 self.set_label(end_label) 1141 1142 def _generateOpMethod(self, node, temp1, temp2, method_name, next_method_label, end_label): 1143 1144 """ 1145 For the given 'node', generate the operator method invocation using the 1146 operands 'temp1' and 'temp2', employing the given 'method_name', and 1147 jumping appropriately to 'next_method_label' where a NotImplemented 1148 result is returned, or to 'end_label' if the method call was successful. 1149 """ 1150 1151 end_attempt_label = self.new_label() 1152 1153 self._startCallFunc() 1154 self.new_op(temp1) 1155 1156 # Get method on temp1. 1157 1158 self._generateAttr(node, method_name, self.attribute_load_instructions) 1159 temp_method = self._optimise_temp_storage() 1160 1161 self._handleAttributeError(node, end_attempt_label) 1162 1163 # Add arguments. 1164 # NOTE: No support for defaults. 1165 1166 self.new_op(temp1) 1167 self.new_op(StoreFrame(0)) 1168 self.new_op(temp2) 1169 self.new_op(StoreFrame(1)) 1170 self._doCallFunc(temp_method) 1171 self._endCallFunc(temp_method) 1172 1173 # Test for NotImplemented. 1174 # Don't actually raise an exception. 1175 1176 self.new_op(TestIdentityAddress(self.get_builtin("NotImplemented", node))) 1177 self.new_op(JumpIfTrue(next_method_label)) 1178 self.new_op(Jump(end_label)) 1179 1180 # End method attempt. 1181 1182 self.set_label(end_attempt_label) 1183 self._endCallFunc(load_result=0) # From the method call. 1184 1185 def _handleAttributeError(self, node, end_call_label): 1186 1187 """ 1188 Add exception handling to the method acquisition instructions where the 1189 attribute access cannot be resolved at compile-time. 1190 """ 1191 1192 if not self._optimise_known_target(): 1193 self.load_builtin("AttributeError", node) 1194 self.new_op(CheckException()) 1195 self.new_op(JumpIfTrue(end_call_label)) 1196 1197 def _propagateAttributeError(self, node): 1198 1199 """ 1200 Add exception raising to the method acquisition instructions where the 1201 attribute access cannot be resolved at compile-time. 1202 """ 1203 1204 if not self._optimise_known_target(): 1205 continue_label = self.new_label() 1206 1207 self.load_builtin("AttributeError", node) 1208 self.new_op(CheckException()) 1209 self.new_op(JumpIfFalse(continue_label)) 1210 self.new_op(RaiseException()) 1211 1212 self.set_label(continue_label) 1213 1214 def _generateSequence(self, sequence_type, node): 1215 1216 "Make a sequence of 'sequence_type' for the given program 'node'." 1217 1218 self.new_op(MakeObject((sequence_type, len(node.nodes)))) 1219 temp = self.get_temp() 1220 1221 for i, n in enumerate(node.nodes): 1222 self.dispatch(n) 1223 self.record_value() 1224 self.new_op(temp) 1225 self.new_op(StoreAttr(Attr(i, None, None, None))) 1226 self.set_source() 1227 self.discard_value() 1228 1229 self.new_op(temp) 1230 self.discard_temp(temp) 1231 1232 # Concrete visitor methods. 1233 1234 def visitAdd(self, node): 1235 self._visitBinary(node, "__add__", "__radd__") 1236 1237 def visitAnd(self, node): 1238 next_label = self.new_label() 1239 1240 for n in node.nodes[:-1]: 1241 self.dispatch(n) 1242 self.new_op(TestBoolean()) 1243 self.new_op(JumpIfFalse(next_label)) 1244 1245 self.dispatch(node.nodes[-1]) 1246 self.set_label(next_label) 1247 1248 # Prevent incorrect optimisation. 1249 1250 self.active = None 1251 1252 def visitAssert(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Assert") 1253 1254 def visitAssign(self, node): 1255 self.dispatch(node.expr) 1256 self.record_value() 1257 1258 for n in node.nodes: 1259 self.dispatch(n) 1260 1261 self.discard_value() 1262 1263 def visitAssAttr(self, node): 1264 self._visitAttr(node, self.attribute_store_instructions) 1265 self.set_source() 1266 1267 def visitAssList(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "AssList") 1268 1269 def visitAssName(self, node): 1270 self._visitName(node, self.name_store_instructions) 1271 self.set_source() 1272 1273 visitAssTuple = visitAssList 1274 1275 def visitAugAssign(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "AugAssign") 1276 1277 def visitBackquote(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Backquote") 1278 1279 def visitBitand(self, node): 1280 self._visitBinary(node, "__and__", "__rand__") 1281 1282 def visitBitor(self, node): 1283 self._visitBinary(node, "__or__", "__ror__") 1284 1285 def visitBitxor(self, node): 1286 self._visitBinary(node, "__xor__", "__rxor__") 1287 1288 def visitBreak(self, node): 1289 next_label, exit_label = self.get_loop_labels() 1290 self.new_op(Jump(exit_label)) 1291 1292 def visitCallFunc(self, node): 1293 1294 """ 1295 Evaluate positional arguments, evaluate and store keyword arguments in 1296 the correct location, then invoke the function. 1297 """ 1298 1299 # Mark the frame, evaluate the target, generate the call. 1300 1301 self._startCallFunc() 1302 self.dispatch(node.node) 1303 temp = self._generateCallFunc(node.args, node) 1304 self._doCallFunc(temp) 1305 self._endCallFunc(temp) 1306 1307 def visitClass(self, node): 1308 1309 # Store the name. 1310 1311 self.new_op(LoadConst(node.unit)) 1312 self.record_value() 1313 self._visitName(node, self.name_store_instructions) 1314 self.set_source() 1315 self.discard_value() 1316 1317 # Visit the code. 1318 1319 unit = self.unit 1320 self.unit = node.unit 1321 self.unit.code_location = self.module.code_location # class body code is not independently addressable 1322 self.dispatch(node.code) 1323 self.unit = unit 1324 1325 def visitCompare(self, node): 1326 1327 """ 1328 _t1 = node.expr 1329 _t1 op1 _t2 and _t2 op2 _t3 and ... 1330 """ 1331 1332 end_label = self.new_label() 1333 1334 self.dispatch(node.expr) 1335 temp2 = self._optimise_temp_storage() 1336 1337 last_op = node.ops[-1] 1338 1339 for op in node.ops: 1340 op_name, next_node = op 1341 methods = self.comparison_methods[op_name] 1342 1343 temp1 = temp2 1344 self.dispatch(next_node) 1345 temp2 = self._optimise_temp_storage() 1346 1347 # Use the appropriate mechanism, setting the boolean status for the 1348 # comparison. 1349 1350 if methods is not None: 1351 left_method, right_method = methods 1352 1353 # Generate method call using evaluated argument and next node. 1354 1355 self._generateBinary(node, temp1, temp2, left_method, right_method) 1356 self.new_op(TestBoolean()) 1357 1358 else: 1359 # Deal with the special operators. 1360 1361 if op_name.startswith("is"): 1362 self.new_op(temp1) 1363 self.record_value() 1364 self.new_op(temp2) 1365 self.new_op(TestIdentity()) 1366 self.set_source() 1367 self.discard_value() 1368 1369 elif op_name.endswith("in"): 1370 self._startCallFunc() 1371 self.new_op(temp2) 1372 1373 # Get method on temp2. 1374 1375 self._generateAttr(node, "__contains__", self.attribute_load_instructions) 1376 temp_method = self._optimise_temp_storage() 1377 1378 self._propagateAttributeError(node) 1379 1380 # Add arguments. 1381 # NOTE: No support for defaults. 1382 1383 self.new_op(temp2) 1384 self.new_op(StoreFrame(0)) 1385 self.new_op(temp1) 1386 self.new_op(StoreFrame(1)) 1387 self._doCallFunc(temp_method) 1388 self._endCallFunc(temp_method) 1389 self.new_op(TestBoolean()) 1390 1391 if op_name.find("not") != -1: 1392 self.new_op(InvertBoolean()) 1393 1394 # Test the result and jump to the end label if false. 1395 1396 if op is not last_op: 1397 self.new_op(JumpIfFalse(end_label)) 1398 1399 # Compilation duties... 1400 1401 self.discard_temp(temp1) 1402 1403 self.discard_temp(temp2) 1404 self.set_label(end_label) 1405 1406 # Yield the appropriate value. 1407 1408 self.new_op(LoadBoolean()) 1409 1410 def visitConst(self, node): 1411 const = self.module.constant_values[node.value] 1412 self.new_op(LoadConst(const)) 1413 1414 def visitContinue(self, node): 1415 next_label, exit_label = self.get_loop_labels() 1416 self.new_op(Jump(next_label)) 1417 1418 def visitDecorators(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Decorators") 1419 1420 def visitDict(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Dict") 1421 1422 def visitDiscard(self, node): 1423 self.dispatch(node.expr) 1424 self._optimise_unused_results() 1425 1426 def visitDiv(self, node): 1427 self._visitBinary(node, "__div__", "__rdiv__") 1428 1429 def visitEllipsis(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Ellipsis") 1430 1431 def visitExec(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Exec") 1432 1433 def visitExpression(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Expression") 1434 1435 def visitFloorDiv(self, node): 1436 self._visitBinary(node, "__floordiv__", "__rfloordiv__") 1437 1438 def visitFor(self, node): 1439 exit_label = self.new_label() 1440 next_label = self.new_label() 1441 else_label = self.new_label() 1442 1443 # Get the "list" to be iterated over, obtain its iterator. 1444 1445 self._startCallFunc() 1446 self.dispatch(node.list) 1447 self._generateAttr(node, "__iter__", self.attribute_load_instructions) 1448 temp = self._generateCallFunc([], node) 1449 self._doCallFunc(temp) 1450 self._endCallFunc(temp) 1451 1452 temp_iterator = self._optimise_temp_storage() 1453 1454 # In the loop... 1455 1456 self.set_label(next_label) 1457 1458 # Use the iterator to get the next value. 1459 1460 self._startCallFunc() 1461 self.new_op(temp_iterator) 1462 self._generateAttr(node, "next", self.attribute_load_instructions) 1463 temp = self._generateCallFunc([], node) 1464 self._doCallFunc(temp) 1465 self._endCallFunc(temp) 1466 1467 # Test for StopIteration. 1468 1469 self.load_builtin("StopIteration", node) 1470 self.new_op(CheckException()) 1471 if node.else_ is not None: 1472 self.new_op(JumpIfTrue(else_label)) 1473 else: 1474 self.new_op(JumpIfTrue(exit_label)) 1475 1476 # Assign to the target. 1477 1478 self.dispatch(node.assign) 1479 1480 # Process the body with the current next and exit points. 1481 1482 self.add_loop_labels(next_label, exit_label) 1483 self.dispatch(node.body) 1484 self.drop_loop_labels() 1485 1486 # Repeat the loop. 1487 1488 self.new_op(Jump(next_label)) 1489 1490 # Produce the "else" section. 1491 1492 if node.else_ is not None: 1493 self.set_label(exit_label) 1494 self.dispatch(node.else_) 1495 1496 # After the loop... 1497 1498 self.set_label(exit_label) 1499 1500 # Compilation duties... 1501 1502 self.discard_temp(temp_iterator) 1503 1504 def visitFrom(self, node): pass 1505 1506 def visitFunction(self, node): 1507 1508 # Only store the name when visiting this node from outside. 1509 1510 if self.unit is not node.unit: 1511 self.new_op(LoadConst(node.unit)) 1512 1513 self.record_value() 1514 self._visitName(node, self.name_store_instructions) # AssName equivalent 1515 self.set_source() 1516 self.discard_value() 1517 1518 self._generateFunctionDefaults(node.unit) 1519 1520 # Visiting of the code occurs when get_code is invoked on this node. 1521 1522 else: 1523 self.dispatch(node.code) 1524 if not isinstance(self.last_op(), Return): 1525 self.dispatch(compiler.ast.Name("None")) 1526 self.new_op(StoreResult()) 1527 1528 self.new_op(Return()) 1529 1530 def visitGenExpr(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExpr") 1531 1532 def visitGenExprFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprFor") 1533 1534 def visitGenExprIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprIf") 1535 1536 def visitGenExprInner(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprInner") 1537 1538 def visitGetattr(self, node): 1539 self._visitAttr(node, self.attribute_load_instructions) 1540 1541 def visitGlobal(self, node): pass 1542 1543 def visitIf(self, node): 1544 first = 1 1545 exit_label = self.new_label() 1546 1547 clauses = node.tests + [(None, node.else_)] 1548 last_clause = clauses[-1] 1549 1550 for clause in clauses: 1551 test, body = clause 1552 if body is None: 1553 break 1554 if not first: 1555 self.set_label(next_label) 1556 if test is not None: 1557 self.dispatch(test) 1558 next_label = self.new_label() 1559 self.new_op(JumpIfFalse(next_label)) 1560 self.dispatch(body) 1561 if clause is not last_clause: 1562 self.new_op(Jump(exit_label)) 1563 first = 0 1564 1565 self.set_label(exit_label) 1566 1567 def visitImport(self, node): pass 1568 1569 def visitInvert(self, node): 1570 self._visitUnary(node, "__invert__") 1571 1572 def visitKeyword(self, node): pass 1573 1574 def visitLambda(self, node): 1575 1576 """ 1577 Lambda functions can be represented as globally defined functions 1578 provided they do not define any default parameter values, since these 1579 may defined in a non-global scope. 1580 1581 Where defaults are defined, an object must be created and its content 1582 defined: the callable member of the object's structure must be set to 1583 the lambda function definition; each default must be attached to the 1584 object as an attribute, as is the case with normal functions and 1585 methods. 1586 """ 1587 1588 # Produce the reference to this function when visiting this node from 1589 # outside. 1590 1591 if self.unit is not node.unit: 1592 temp = self._generateFunctionDefaults(node.unit) 1593 self.new_op(LoadConst(node.unit)) 1594 1595 # Populate the new object required for the function. 1596 1597 if temp is not None: 1598 self.record_value() 1599 self.new_op(temp) 1600 self.new_op(StoreCallable()) 1601 self.set_source() 1602 self.discard_value() 1603 1604 self.new_op(temp) 1605 #self.discard_temp(temp) 1606 1607 # Visiting of the code occurs when get_code is invoked on this node. 1608 1609 else: 1610 self.dispatch(node.code) 1611 self.new_op(StoreResult()) 1612 self.new_op(Return()) 1613 1614 def visitLeftShift(self, node): 1615 self._visitBinary(node, "__lshift__", "__rlshift__") 1616 1617 def visitList(self, node): 1618 self._generateSequence("list", node) 1619 1620 def visitListComp(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListComp") 1621 1622 def visitListCompFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompFor") 1623 1624 def visitListCompIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompIf") 1625 1626 def visitMod(self, node): 1627 self._visitBinary(node, "__mod__", "__rmod__") 1628 1629 def visitModule(self, node): 1630 self.dispatch(node.node) 1631 1632 def visitMul(self, node): 1633 self._visitBinary(node, "__mul__", "__rmul__") 1634 1635 def visitName(self, node): 1636 if node.name == "None": 1637 const = self.module.constant_values[None] 1638 self.new_op(LoadConst(const)) 1639 else: 1640 self._visitName(node, self.name_load_instructions) 1641 1642 def visitNot(self, node): 1643 next_label = self.new_label() 1644 true_label = self.new_label() 1645 1646 self.dispatch(node.expr) 1647 self.new_op(TestBoolean()) 1648 self.new_op(InvertBoolean()) 1649 self.new_op(LoadBoolean()) 1650 1651 # The equivalent of InvertBoolean/LoadBoolean. 1652 1653 #self.new_op(JumpIfTrue(true_label)) 1654 #self.load_builtin("True", node) 1655 #self.new_op(Jump(next_label)) 1656 1657 #self.set_label(true_label) 1658 #self.load_builtin("False", node) 1659 #self.set_label(next_label) 1660 1661 # Prevent incorrect optimisation. 1662 1663 self.active = None 1664 1665 def visitOr(self, node): 1666 next_label = self.new_label() 1667 1668 for n in node.nodes[:-1]: 1669 self.dispatch(n) 1670 self.new_op(TestBoolean()) 1671 self.new_op(JumpIfTrue(next_label)) 1672 1673 self.dispatch(node.nodes[-1]) 1674 self.set_label(next_label) 1675 1676 # Prevent incorrect optimisation. 1677 1678 self.active = None 1679 1680 def visitPass(self, node): pass 1681 1682 def visitPower(self, node): 1683 self._visitBinary(node, "__pow__", "__rpow__") 1684 1685 def visitPrint(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Print") 1686 1687 def visitPrintnl(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Printnl") 1688 1689 def visitRaise(self, node): 1690 # NOTE: expr1 only => instance provided 1691 self.dispatch(node.expr1) 1692 1693 if node.expr2 is not None: 1694 temp = self._optimise_temp_storage() 1695 1696 self.dispatch(node.expr2) 1697 temp_arg = self._optimise_temp_storage() 1698 1699 self._startCallFunc() 1700 self.new_op(temp_arg) 1701 self.new_op(StoreFrame(0)) 1702 self._doCallFunc(temp) 1703 self._endCallFunc(temp) 1704 1705 self.discard_temp(temp_arg) 1706 1707 self.new_op(StoreException()) 1708 self.new_op(RaiseException()) 1709 1710 def visitReturn(self, node): 1711 if node.value is not None: 1712 self.dispatch(node.value) 1713 else: 1714 self.dispatch(compiler.ast.Name("None")) 1715 1716 self.new_op(StoreResult()) 1717 self.new_op(Return()) 1718 1719 def visitRightShift(self, node): 1720 self._visitBinary(node, "__rshift__", "__rrshift__") 1721 1722 def visitSlice(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Slice") 1723 1724 def visitStmt(self, node): 1725 for n in node.nodes: 1726 self.dispatch(n) 1727 1728 def visitSub(self, node): 1729 self._visitBinary(node, "__sub__", "__rsub__") 1730 1731 def visitSubscript(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Subscript") 1732 1733 def visitTryExcept(self, node): 1734 exit_label = self.new_label() 1735 success_label = self.new_label() 1736 handler_label = self.new_label() 1737 1738 self.add_exception_labels(handler_label, exit_label) 1739 1740 # Try... 1741 # Produce the code, then jump to the exit. 1742 1743 self.new_op(PushHandler(handler_label)) 1744 self.dispatch(node.body) 1745 self.new_op(PopHandler()) 1746 self.new_op(Jump(exit_label)) 1747 1748 # Start of handlers. 1749 1750 self.set_label(handler_label) 1751 self.new_op(PopHandler()) 1752 1753 for name, assignment, handler in node.handlers: 1754 next_label = self.new_label() 1755 1756 # Test the given exception against the current exception. 1757 1758 if name is not None: 1759 self.dispatch(name) 1760 self.new_op(CheckException()) 1761 self.new_op(JumpIfFalse(next_label)) 1762 1763 # Handle assignment to exception variable. 1764 1765 if assignment is not None: 1766 self.dispatch(assignment) 1767 1768 # Produce the handler code, then jump to the exit. 1769 1770 self.dispatch(handler) 1771 self.new_op(Jump(exit_label)) 1772 1773 self.set_label(next_label) 1774 1775 # Unhandled exceptions. 1776 1777 #self.new_op(LoadException()) 1778 self.new_op(RaiseException()) 1779 1780 # Optional else clause. 1781 1782 if node.else_ is not None: 1783 self.dispatch(node.else_) 1784 1785 self.set_label(exit_label) 1786 self.drop_exception_labels() 1787 1788 def visitTryFinally(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "TryFinally") 1789 1790 def visitTuple(self, node): 1791 self._generateSequence("tuple", node) 1792 1793 def visitUnaryAdd(self, node): 1794 self._visitUnary(node, "__pos__") 1795 1796 def visitUnarySub(self, node): 1797 self._visitUnary(node, "__neg__") 1798 1799 def visitWhile(self, node): 1800 exit_label = self.new_label() 1801 next_label = self.new_label() 1802 else_label = self.new_label() 1803 1804 self.set_label(next_label) 1805 self.dispatch(node.test) 1806 if node.else_ is not None: 1807 self.new_op(JumpIfFalse(else_label)) 1808 else: 1809 self.new_op(JumpIfFalse(exit_label)) 1810 1811 self.add_loop_labels(next_label, exit_label) 1812 1813 self.dispatch(node.body) 1814 self.new_op(Jump(next_label)) 1815 1816 if node.else_ is not None: 1817 self.set_label(else_label) 1818 self.dispatch(node.else_) 1819 1820 self.set_label(exit_label) 1821 self.drop_loop_labels() 1822 1823 # Prevent incorrect optimisation. 1824 1825 self.active = None 1826 1827 def visitWith(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "With") 1828 1829 def visitYield(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Yield") 1830 1831 # Useful data. 1832 1833 comparison_methods = { 1834 "==" : ("__eq__", "__ne__"), 1835 "!=" : ("__ne__", "__eq__"), 1836 "<" : ("__lt__", "__gt__"), 1837 "<=" : ("__le__", "__ge__"), 1838 ">=" : ("__ge__", "__le__"), 1839 ">" : ("__gt__", "__lt__"), 1840 "is" : None, 1841 "is not" : None, 1842 "in" : None, 1843 "not in" : None 1844 } 1845 1846 # vim: tabstop=4 expandtab shiftwidth=4