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