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