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