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