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