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 import micropython.inspect 23 from micropython.rsvp import * 24 from micropython.common import * 25 import compiler.ast 26 from compiler.visitor import ASTVisitor 27 try: 28 set 29 except NameError: 30 from sets import Set as set 31 32 class TranslateError(NodeProcessingError): pass 33 34 class Label: 35 36 "A reference to a location." 37 38 def __init__(self, number, location=None): 39 self.number = number 40 self.location = location 41 42 def __repr__(self): 43 return "Label(%r, location=%r)" % (self.number, self.location) 44 45 # Program visitors. 46 47 class Translation(ASTVisitor): 48 49 "A translated module." 50 51 supported_optimisations = ["constant_storage", "known_target", "self_access"] 52 53 def __init__(self, module, objtable, paramtable, builtins=None, optimisations=None): 54 55 """ 56 Initialise the translation with an inspected 'module' and an attribute 57 table 'objtable' and parameter table 'paramtable'. 58 """ 59 60 ASTVisitor.__init__(self) 61 self.visitor = self 62 self.module = module 63 self.objtable = objtable 64 self.paramtable = paramtable 65 self.builtins = builtins 66 67 # Desired optimisations. 68 69 self.optimisations = set(optimisations or []) 70 71 # The current unit being translated. 72 73 self.unit = None 74 75 # Wiring within the code. 76 77 self.labels = {} 78 self.label_number = 0 79 self.loop_labels = [] 80 self.exception_labels = [] 81 82 # The code itself. 83 84 self.code = None 85 86 def get_module_code(self): 87 88 "Return the top-level module code." 89 90 self.unit = self.module 91 self.code = [] 92 if self.module.module is not None: 93 self.dispatch(self.module.module) 94 return self.code 95 96 def get_code(self, unit): 97 98 "Return the code for the given 'unit'." 99 100 self.unit = unit 101 self.code = [] 102 if unit.node is not None: 103 self.dispatch(unit.node) 104 return self.code 105 106 def get_default_code(self, unit): 107 108 "Return the code for the defaults in the given 'unit'." 109 110 self.code = [] 111 for attr, default in zip(unit.default_attrs, unit.defaults): 112 self.dispatch(default) 113 self.new_op(LoadConst(unit)) 114 self.new_op(StoreAttr(attr)) 115 return self.code 116 117 def __repr__(self): 118 return "Translation(%r)" % self.module 119 120 def get_scope(self, name): 121 if self.unit.has_key(name): 122 return "local" 123 elif self.module.has_key(name): 124 return "global" 125 else: 126 return "builtins" 127 128 # Code writing methods. 129 130 def new_label(self): 131 132 "Return a new label object for use with set_label." 133 134 number = self.label_number 135 label = Label(number) 136 self.labels[label] = label 137 self.label_number += 1 138 return label 139 140 def set_label(self, label): 141 142 """ 143 Set the location of 'label' to that within the entire image: the 144 location within the code combined with location of the code unit. 145 """ 146 147 label.location = len(self.code) + self.unit.code_location 148 149 def get_loop_labels(self): 150 return self.loop_labels[-1] 151 152 def add_loop_labels(self, next_label, exit_label): 153 self.loop_labels.append((next_label, exit_label)) 154 155 def drop_loop_labels(self): 156 self.loop_labels.pop() 157 158 def get_exception_labels(self): 159 return self.exception_labels[-1] 160 161 def add_exception_labels(self, handler_label, exit_label): 162 self.exception_labels.append((handler_label, exit_label)) 163 164 def drop_exception_labels(self): 165 self.exception_labels.pop() 166 167 def new_op(self, op): 168 169 "Add 'op' to the generated code." 170 171 self.code.append(op) 172 173 def replace_op(self, op): 174 175 "Replace the last added instruction with 'op'." 176 177 self.code[-1] = op 178 179 def remove_ops(self, n): 180 181 "Remove the last 'n' instructions." 182 183 del self.code[-n:] 184 185 def last_ops(self, n): 186 187 "Return the last 'n' added instructions in reverse chronological order." 188 189 ops = self.code[-n:] 190 ops.reverse() 191 return ops 192 193 def last_op(self): 194 195 "Return the last added instruction." 196 197 return self.code[-1] 198 199 # Internal helper methods. 200 201 def _visitAttr(self, node, classes): 202 203 """ 204 Visit the attribute-related 'node', generating instructions based on the 205 given 'classes'. 206 """ 207 208 self.dispatch(node.expr) 209 self._generateAttr(node, node.attrname, classes) 210 211 def _generateAttr(self, node, attrname, classes): 212 213 """ 214 Generate code for the access to 'attrname' using the given 'classes'. 215 """ 216 217 AttrInstruction, AttrIndexInstruction = classes 218 # NOTE: Only simple cases are used for optimisations. 219 220 last = self.last_op() 221 222 # Where the last operation (defining the attribute owner) yields a 223 # constant... 224 225 if self._have_constant_input(0): 226 227 # Optimise away the constant storage if appropriate. 228 229 if self._optimise_constant_storage(AttrInstruction, 1): 230 return 231 232 # Get the details of the access. 233 234 target = last.attr.value 235 target_name = target.full_name() 236 237 try: 238 table_entry = self.objtable.table[target_name] 239 except KeyError: 240 raise TranslateError(self.module.full_name(), node, 241 "No object entry exists for target %r." % target_name) 242 243 try: 244 pos = table_entry[attrname] 245 except KeyError: 246 raise TranslateError(self.module.full_name(), node, 247 "No attribute entry exists for name %r in target %r." % (attrname, target_name)) 248 249 self.replace_op(AttrInstruction(pos)) 250 251 # Where the last operation involves the special 'self' name, check to 252 # see if the attribute is acceptably positioned and produce a direct 253 # access to the attribute. 254 255 elif self._optimise_self_access(attrname, AttrInstruction): 256 pass 257 258 # Otherwise, perform a normal operation. 259 260 else: 261 try: 262 index = self.objtable.get_index(attrname) 263 except self.objtable.TableError: 264 raise TranslateError(self.module.full_name(), node, 265 "No attribute entry exists for name %r." % attrname) 266 267 self.new_op(AttrIndexInstruction(index)) 268 269 def _startCallFunc(self): 270 271 "Record the location of the invocation." 272 273 self.new_op(MakeFrame()) # records the start of the frame 274 275 def _generateCallFunc(self, args, node): 276 277 # NOTE: Only simple cases are used for optimisations. 278 279 target, context = self._optimise_known_target() 280 281 # Where a target is known and has a known context, avoid generating any 282 # first argument. Instance methods do not have a known target since they 283 # are accessed via an instance whose identity cannot generally be known 284 # at compile-time. 285 286 if context is None: 287 continue_label = self.new_label() 288 self.new_op(LoadContext()) 289 self.new_op(CheckContext()) 290 self.new_op(JumpIfTrue(continue_label)) 291 self.dispatch(compiler.ast.Name("TypeError")) 292 self.new_op(RaiseException()) 293 self.set_label(continue_label) 294 else: 295 pass # NOTE: Class methods should be supported. 296 297 # Evaluate the arguments. 298 299 employed_positions = set() 300 extra_keywords = [] 301 302 for frame_pos, arg in enumerate(args): 303 304 # Handle positional and keyword arguments separately. 305 306 if isinstance(arg, compiler.ast.Keyword): 307 308 # Optimise where the target is known now. 309 310 if target is not None: 311 312 # Find the parameter table entry for the target. 313 314 target_name = target.full_name() 315 316 # Look for a callable with the precise target name. 317 318 table_entry = self.paramtable.table[target_name] 319 320 # Look the name up in the parameter table entry. 321 322 try: 323 pos = table_entry[arg.name] 324 325 # Where no position is found, this could be an extra keyword 326 # argument. 327 328 except KeyError: 329 extra_keywords.append(arg) 330 continue 331 332 # Test for illegal conditions. 333 334 if pos in employed_positions: 335 raise TranslateError(self.module.full_name(), node, 336 "Keyword argument %r overwrites parameter %r." % (arg.name, pos)) 337 338 employed_positions.add(pos) 339 340 # Add space for arguments appearing before this one. 341 342 if frame_pos < pos: 343 self.new_op(ReserveFrame(pos - frame_pos) 344 345 # Generate code for the keyword and the positioning 346 # operation. 347 348 self.dispatch(arg.expr) 349 350 # If the position corresponds to the current frame element, 351 # skip generating the store instruction. 352 353 if frame_pos > pos: 354 self.new_op(StoreFrame(pos)) 355 356 # Otherwise, generate the code needed to obtain the details of 357 # the parameter location. 358 359 else: 360 361 # Combine the target details with the name to get the location. 362 # See the access method on the List class. 363 364 try: 365 paramindex = self.paramtable.get_index(arg.name) 366 367 # Where no position is found, this could be an extra keyword 368 # argument. 369 370 except ValueError: 371 extra_keywords.append(arg) 372 continue 373 374 # Generate code for the keyword and the positioning 375 # operation. 376 377 self.dispatch(arg.expr) 378 self.new_op(StoreFrameIndex(paramindex)) 379 380 # use (callable+0)+paramindex+table 381 # checks embedded offset against (callable+0) 382 # moves the top of stack to frame+position 383 384 else: 385 self.dispatch(arg) 386 employed_positions.add(frame_pos) 387 388 frame_pos = len(args) 389 390 # NOTE: If any extra keywords were identified, generate them now. 391 # NOTE: This needs to populate a ** argument dictionary. 392 # 393 # for arg in extra_keywords: 394 # const = self.module.constant_values[arg.name] 395 # self.new_op(LoadConst(const)) 396 # self.dispatch(arg.expr) 397 # frame_pos += 1 398 399 # NOTE: Somehow, the above needs to be combined with * and ** arguments. 400 401 # Either test for a complete set of arguments. 402 403 if target is not None: 404 405 # Make sure that enough arguments have been given. 406 407 nargs_max = len(target.positional_names) 408 ndefaults = len(target.defaults) 409 nargs_min = nargs_max - ndefaults 410 411 for i in range(0, nargs_min): 412 if i not in employed_positions: 413 raise TranslateError(self.module.full_name(), node, 414 "Argument %r not supplied for %r: need at least %d arguments." % (i+1, target.name, nargs_min)) 415 416 nargs = len(args) 417 418 if nargs > nargs_max and not target.has_star and not target.has_dstar: 419 raise TranslateError(self.module.full_name(), node, 420 "Too many arguments for %r: need at most %d arguments." % (target.name, nargs_max)) 421 422 # Where defaults are involved, put them into the frame. 423 # Here, we use negative index values to visit the right hand end of 424 # the defaults list. 425 426 for pos in range(nargs_min, nargs_max): 427 if pos not in employed_positions: 428 self.new_op(LoadConst(target)) 429 self.new_op(LoadAttr(target.default_attrs[pos - nargs_min])) 430 431 # If the position corresponds to the current frame element, 432 # skip generating the instruction. 433 434 if frame_pos != pos: 435 self.new_op(StoreFrame(pos)) 436 437 frame_pos += 1 438 439 # Or generate instructions to do this at run-time. 440 # NOTE: CheckFrame has to check the number of arguments and to fill in 441 # NOTE: defaults. 442 443 else: 444 self.new_op(CheckFrame()) 445 446 def _endCallFunc(self): 447 448 "Make the invocation and tidy up afterwards." 449 450 self.new_op(LoadCallable()) # uses the start of the frame to get the callable 451 self.new_op(JumpWithFrame()) 452 453 # NOTE: Exception handling required. 454 455 self.new_op(DropFrame()) 456 457 def _visitName(self, node, classes): 458 459 """ 460 Visit the name-related 'node', generating instructions based on the 461 given 'classes'. 462 """ 463 464 name = node.name 465 scope = self.get_scope(name) 466 #print self.module.name, node.lineno, name, scope 467 self._generateName(name, scope, classes, node) 468 469 def _generateName(self, name, scope, classes, node): 470 471 """ 472 Generate code for the access to 'name' in 'scope' using the given 473 'classes', and using the given 'node' as the source of the access. 474 """ 475 476 NameInstruction, AttrInstruction = classes 477 478 if self._optimise_constant_storage(NameInstruction, 0): 479 return 480 481 if scope == "local": 482 unit = self.unit 483 if isinstance(unit, micropython.inspect.Function): 484 self.new_op(NameInstruction(unit.all_locals()[name])) 485 elif isinstance(unit, micropython.inspect.Class): 486 self.new_op(AttrInstruction(unit.all_class_attributes()[name])) 487 elif isinstance(unit, micropython.inspect.Module): 488 self.new_op(AttrInstruction(unit.module_attributes()[name])) 489 else: 490 raise TranslateError(self.module.full_name(), node, "Program unit %r has no local %r." % (unit, name)) 491 492 elif scope == "global": 493 globals = self.module.module_attributes() 494 if globals.has_key(name): 495 self.new_op(AttrInstruction(globals[name])) 496 else: 497 raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r." % (self.module, name)) 498 499 else: 500 self.new_op(AttrInstruction(self._get_builtin(name, node))) 501 502 def _get_builtin(self, name, node): 503 if self.builtins is not None: 504 try: 505 return self.builtins[name] 506 except KeyError: 507 raise TranslateError(self.module.full_name(), node, "No __builtins__ definition is available for name %r." % name) 508 else: 509 raise TranslateError(self.module.full_name(), node, "No __builtins__ module is available for name %r." % name) 510 511 # Optimisation tests. 512 513 def _should_optimise_constant_storage(self): 514 return "constant_storage" in self.optimisations 515 516 def _should_optimise_known_target(self): 517 return "known_target" in self.optimisations 518 519 def _should_optimise_self_access(self): 520 return "self_access" in self.optimisations 521 522 def _have_constant_input(self, n): 523 last = self.last_ops(n+1) 524 return len(last) > n and (isinstance(last[n], LoadAttr) and last[n].attr.assignments == 1 or 525 isinstance(last[n], LoadConst)) 526 527 def _have_known_target(self): 528 return self._have_constant_input(0) 529 530 def _have_self_input(self): 531 last = self.last_op() 532 return isinstance(self.unit, micropython.inspect.Function) and \ 533 self.unit.is_method() and isinstance(last, LoadName) and \ 534 last.attr.name == "self" 535 536 # Optimisation methods. See the supported_optimisations class attribute. 537 538 def _optimise_constant_storage(self, instruction, n): 539 540 """ 541 Where this operation should store a constant into a target which is 542 also constant, optimise away both operations. 543 """ 544 545 if self._should_optimise_constant_storage() and \ 546 instruction in (StoreAttr, StoreName) and \ 547 self._have_constant_input(n) and \ 548 (n == 0 or self._have_constant_input(n-1)): 549 550 self.remove_ops(n+1) 551 return 1 552 else: 553 return 0 554 555 def _optimise_known_target(self): 556 557 """ 558 Where the target of an invocation is known, provide information about it 559 and its context. If a class is being invoked and the conditions are 560 appropriate, get information about the specific initialiser. 561 """ 562 563 if self._should_optimise_known_target() and self._have_known_target(): 564 last = self.last_op() 565 target = last.attr.value 566 context = last.attr.parent 567 568 # Handle calls to classes. 569 570 if isinstance(target, micropython.inspect.Class): 571 target = target.get_instantiator() 572 context = micropython.inspect.Instance() 573 574 # A special context is chosen to avoid generating unnecessary 575 # context loading and checking instructions. 576 577 else: 578 target = None 579 context = None 580 581 return target, context 582 583 def _optimise_self_access(self, attrname, instruction): 584 585 """ 586 Where the provided 'attrname' accesses an attribute which occupies the 587 same position in all possible objects which can be accessed, generate an 588 'instruction' accessing the attribute directly. 589 """ 590 591 if self._should_optimise_self_access() and self._have_self_input() and \ 592 not self.unit.is_relocated(attrname): 593 594 attr = self.unit.parent.all_attributes()[attrname] 595 self.new_op(instruction(attr)) 596 return 1 597 else: 598 return 0 599 600 # Visitor methods. 601 602 def default(self, node, *args): 603 raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__) 604 605 def dispatch(self, node, *args): 606 return ASTVisitor.dispatch(self, node, *args) 607 608 def _visitBinary(self, node, left_method, right_method): 609 610 """ 611 _t1 = node.left 612 _t2 = node.right 613 try: 614 _t1.__add__(_t2) 615 except AttributeError: 616 _t2.__radd__(_t1) 617 """ 618 619 right_label = self.new_label() 620 end_label = self.new_label() 621 622 # NOTE: Decide on temporary storage access. 623 624 self.dispatch(node.left) 625 self.new_op(StoreTemp(1)) 626 self.dispatch(node.right) 627 self.new_op(StoreTemp(2)) 628 629 # Left method. 630 631 self._startCallFunc() 632 self.new_op(LoadTemp(1)) 633 self._generateAttr(node, left_method, (LoadAttr, LoadAttrIndex)) 634 self.new_op(LoadTemp(1)) # Explicit context as first argument. 635 self.new_op(LoadTemp(2)) 636 self._endCallFunc() 637 638 self.dispatch(compiler.ast.Name("AttributeError")) 639 self.new_op(CheckException()) 640 self.new_op(JumpIfFalse(end_label)) 641 642 # Right method. 643 644 self.set_label(right_label) 645 self._startCallFunc() 646 self.new_op(LoadTemp(2)) 647 self._generateAttr(node, right_method, (LoadAttr, LoadAttrIndex)) 648 self.new_op(LoadTemp(2)) # Explicit context as first argument. 649 self.new_op(LoadTemp(1)) 650 self._endCallFunc() 651 652 self.set_label(end_label) 653 654 def visitAdd(self, node): 655 self._visitBinary(node, "__add__", "__radd__") 656 657 def visitAnd(self, node): pass 658 659 def visitAssert(self, node): pass 660 661 def visitAssign(self, node): 662 self.dispatch(node.expr) 663 for n in node.nodes: 664 self.dispatch(n) 665 666 def visitAssAttr(self, node): 667 self._visitAttr(node, (StoreAttr, StoreAttrIndex)) 668 669 def visitAssList(self, node): pass 670 671 def visitAssName(self, node): 672 self._visitName(node, (StoreName, StoreAttr)) 673 674 visitAssTuple = visitAssList 675 676 def visitAugAssign(self, node): pass 677 678 def visitBackquote(self, node): pass 679 680 def visitBitand(self, node): pass 681 682 def visitBitor(self, node): pass 683 684 def visitBitxor(self, node): pass 685 686 def visitBreak(self, node): 687 next_label, exit_label = self.get_loop_labels() 688 self.new_op(Jump(exit_label)) 689 690 def visitCallFunc(self, node): 691 692 """ 693 Evaluate positional arguments, evaluate and store keyword arguments in 694 the correct location, then invoke the function. 695 """ 696 697 # Mark the frame, evaluate the target, generate the call. 698 699 self._startCallFunc() 700 self.dispatch(node.node) 701 self._generateCallFunc(node.args, node) 702 self._endCallFunc() 703 704 def visitClass(self, node): 705 unit = self.unit 706 self.unit = node.unit 707 self.unit.code_location = self.module.code_location # class body code is not independently addressable 708 self.dispatch(node.code) 709 self.unit = unit 710 711 def visitCompare(self, node): 712 713 """ 714 self.dispatch(node.expr) 715 for op_name, next_node in compare.ops: 716 methods = self.comparison_methods[op_name] 717 if methods is not None: 718 # Generate method call using evaluated argument and next node. 719 else: 720 # Deal with the special operators. 721 # Provide short-circuiting. 722 """ 723 724 def visitConst(self, node): 725 const = self.module.constant_values[node.value] 726 self.new_op(LoadConst(const)) 727 728 def visitContinue(self, node): 729 next_label, exit_label = self.get_loop_labels() 730 self.new_op(Jump(next_label)) 731 732 def visitDecorators(self, node): pass 733 734 def visitDict(self, node): pass 735 736 def visitDiscard(self, node): 737 self.dispatch(node.expr) 738 739 def visitDiv(self, node): 740 self._visitBinary(node, "__div__", "__rdiv__") 741 742 def visitEllipsis(self, node): pass 743 744 def visitExec(self, node): pass 745 746 def visitExpression(self, node): pass 747 748 def visitFloorDiv(self, node): 749 self._visitBinary(node, "__floordiv__", "__rfloordiv__") 750 751 def visitFor(self, node): 752 exit_label = self.new_label() 753 next_label = self.new_label() 754 else_label = self.new_label() 755 756 # Get the "list" to be iterated over, obtain its iterator. 757 758 self._startCallFunc() 759 self.dispatch(node.list) 760 self._generateAttr(node, "__iter__", (LoadAttr, LoadAttrIndex)) 761 self._generateCallFunc([], node) 762 self._endCallFunc() 763 764 # Iterator on stack. 765 766 # In the loop... 767 768 self.set_label(next_label) 769 770 # Use the iterator to get the next value. 771 772 self._startCallFunc() 773 self.new_op(Duplicate()) 774 self._generateAttr(node, "next", (LoadAttr, LoadAttrIndex)) 775 self._generateCallFunc([], node) 776 self._endCallFunc() 777 778 # Test for StopIteration. 779 780 self.dispatch(compiler.ast.Name("StopIteration")) 781 self.new_op(CheckException()) 782 if node.else_ is not None: 783 self.new_op(JumpIfTrue(else_label)) 784 else: 785 self.new_op(JumpIfTrue(exit_label)) 786 787 # Assign to the target. 788 789 self.dispatch(node.assign) 790 791 # Process the body with the current next and exit points. 792 793 self.add_loop_labels(next_label, exit_label) 794 self.dispatch(node.body) 795 self.drop_loop_labels() 796 797 # Repeat the loop. 798 799 self.new_op(Jump(next_label)) 800 801 # Produce the "else" section. 802 803 if node.else_ is not None: 804 self.set_label(exit_label) 805 self.dispatch(node.else_) 806 807 # Pop the iterator. 808 809 self.set_label(exit_label) 810 self.new_op(Pop()) 811 812 def visitFrom(self, node): pass 813 814 def visitFunction(self, node): 815 816 # Only store the name when visiting this node from outside. 817 818 if self.unit is not node.unit: 819 self.new_op(LoadConst(node.unit)) 820 self._visitName(node, (StoreName, StoreAttr)) 821 822 # Visiting of the code occurs when get_code is invoked on this node. 823 824 else: 825 self.dispatch(node.code) 826 if not isinstance(self.last_op(), Return): 827 self.dispatch(compiler.ast.Name("None")) 828 self.new_op(Return()) 829 830 def visitGenExpr(self, node): pass 831 832 def visitGenExprFor(self, node): pass 833 834 def visitGenExprIf(self, node): pass 835 836 def visitGenExprInner(self, node): pass 837 838 def visitGetattr(self, node): 839 self._visitAttr(node, (LoadAttr, LoadAttrIndex)) 840 841 def visitGlobal(self, node): pass 842 843 def visitIf(self, node): 844 first = 1 845 exit_label = self.new_label() 846 847 for test, body in node.tests + [(None, node.else_)]: 848 if body is None: 849 break 850 if not first: 851 self.set_label(next_label) 852 if test is not None: 853 self.dispatch(test) 854 next_label = self.new_label() 855 self.new_op(JumpIfFalse(next_label)) 856 self.dispatch(body) 857 self.new_op(Jump(exit_label)) 858 first = 0 859 860 self.set_label(exit_label) 861 862 def visitImport(self, node): pass 863 864 def visitInvert(self, node): pass 865 866 def visitKeyword(self, node): pass 867 868 def visitLambda(self, node): pass 869 870 def visitLeftShift(self, node): pass 871 872 def visitList(self, node): pass 873 874 def visitListComp(self, node): pass 875 876 def visitListCompFor(self, node): pass 877 878 def visitListCompIf(self, node): pass 879 880 def visitMod(self, node): 881 self._visitBinary(node, "__mod__", "__rmod__") 882 883 def visitModule(self, node): 884 self.dispatch(node.node) 885 886 def visitMul(self, node): 887 self._visitBinary(node, "__mul__", "__rmul__") 888 889 def visitName(self, node): 890 self._visitName(node, (LoadName, LoadAttr)) 891 892 def visitNot(self, node): pass 893 894 def visitOr(self, node): pass 895 896 def visitPass(self, node): pass 897 898 def visitPower(self, node): pass 899 900 def visitPrint(self, node): pass 901 902 def visitPrintnl(self, node): pass 903 904 def visitRaise(self, node): pass 905 906 def visitReturn(self, node): 907 if node.value is not None: 908 self.dispatch(node.value) 909 else: 910 self.dispatch(compiler.ast.Name("None")) 911 self.new_op(Return()) 912 913 def visitRightShift(self, node): pass 914 915 def visitSlice(self, node): pass 916 917 def visitStmt(self, node): 918 for n in node.nodes: 919 self.dispatch(n) 920 921 def visitSub(self, node): 922 self._visitBinary(node, "__sub__", "__rsub__") 923 924 def visitSubscript(self, node): pass 925 926 def visitTryExcept(self, node): 927 928 """ 929 Enter try block. 930 Dispatch to code. 931 932 """ 933 934 exit_label = self.new_label() 935 handler_label = self.new_label() 936 937 self.add_exception_labels(handler_label, exit_label) 938 939 # Try... 940 # Produce the code, then jump to the exit. 941 942 self.dispatch(node.body) 943 self.new_op(Jump(exit_label)) 944 945 # Start of handlers. 946 947 self.set_label(handler_label) 948 for name, assignment, handler in node.handlers: 949 next_label = self.new_label() 950 951 # Test the given exception against the current exception. 952 953 if name is not None: 954 self.dispatch(name) 955 self.new_op(CheckException()) 956 self.new_op(JumpIfFalse(next_label)) 957 958 # Handle assignment to exception variable. 959 960 if assignment is not None: 961 self.dispatch(assignment) 962 963 # Produce the handler code, then jump to the exit. 964 965 self.dispatch(handler) 966 self.new_op(Jump(exit_label)) 967 968 self.set_label(next_label) 969 970 # Unhandled exceptions. 971 972 self.new_op(RaiseException()) 973 974 # After exception 975 976 self.set_label(exit_label) 977 978 # Optional else clause. 979 980 if node.else_ is not None: 981 self.dispatch(node.else_) 982 983 self.drop_exception_labels() 984 985 def visitTryFinally(self, node): pass 986 987 def visitTuple(self, node): pass 988 989 def visitUnaryAdd(self, node): pass 990 991 def visitUnarySub(self, node): pass 992 993 def visitWhile(self, node): 994 exit_label = self.new_label() 995 next_label = self.new_label() 996 else_label = self.new_label() 997 998 self.set_label(next_label) 999 self.dispatch(node.test) 1000 if node.else_ is not None: 1001 self.new_op(JumpIfFalse(else_label)) 1002 else: 1003 self.new_op(JumpIfFalse(exit_label)) 1004 1005 self.add_loop_labels(next_label, exit_label) 1006 1007 self.dispatch(node.body) 1008 self.new_op(Jump(next_label)) 1009 1010 if node.else_ is not None: 1011 self.set_label(else_label) 1012 self.dispatch(node.else_) 1013 1014 self.set_label(exit_label) 1015 self.drop_loop_labels() 1016 1017 def visitWith(self, node): pass 1018 1019 def visitYield(self, node): pass 1020 1021 # Useful data. 1022 1023 comparison_methods = { 1024 "==" : ("__eq__", "__ne__"), 1025 "!=" : ("__ne__", "__eq__"), 1026 "<" : ("__lt__", "__gt__"), 1027 "<=" : ("__le__", "__ge__"), 1028 ">=" : ("__ge__", "__le__"), 1029 ">" : ("__gt__", "__lt__"), 1030 "is" : None, 1031 "is not" : None, 1032 "in" : None, 1033 "not in" : None 1034 } 1035 1036 # vim: tabstop=4 expandtab shiftwidth=4