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