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