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", "constant_test"] 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 259 target = last.attr.value 260 261 if isinstance(target, micropython.inspect.Const): 262 target_name = target.value_type_name() 263 else: 264 target_name = target.full_name() 265 266 # Access the object table to get the attribute position. 267 268 try: 269 table_entry = self.objtable.table[target_name] 270 except KeyError: 271 raise TranslateError(self.module.full_name(), node, 272 "No object entry exists for target %r." % target_name) 273 274 try: 275 pos = table_entry[attrname] 276 except KeyError: 277 raise TranslateError(self.module.full_name(), node, 278 "No attribute entry exists for name %r in target %r." % (attrname, target_name)) 279 280 # Produce a suitable instruction. 281 282 if isinstance(target, micropython.inspect.Const): 283 self.replace_op(AttrInstruction(pos)) 284 else: 285 self.replace_op(AddressInstruction(pos)) 286 287 # Where the last operation involves the special 'self' name, check to 288 # see if the attribute is acceptably positioned and produce a direct 289 # access to the attribute. 290 291 elif self._optimise_self_access(attrname, AttrInstruction): 292 pass 293 294 # Otherwise, perform a normal operation. 295 296 else: 297 try: 298 index = self.objtable.get_index(attrname) 299 except self.objtable.TableError: 300 raise TranslateError(self.module.full_name(), node, 301 "No attribute entry exists for name %r." % attrname) 302 303 self.new_op(AttrIndexInstruction(index)) 304 305 def _startCallFunc(self): 306 307 "Record the location of the invocation." 308 309 self.new_op(MakeFrame()) # records the start of the frame 310 311 def _generateCallFunc(self, args, node): 312 313 # NOTE: Only simple cases are used for optimisations. 314 315 target, context = self._optimise_known_target() 316 317 # Where a target is known and has a known context, avoid generating any 318 # first argument. Instance methods do not have a known target since they 319 # are accessed via an instance whose identity cannot generally be known 320 # at compile-time. 321 322 if context is None: 323 continue_label = self.new_label() 324 self.new_op(LoadContext()) 325 self.new_op(CheckContext()) 326 self.new_op(JumpIfTrue(continue_label)) 327 self.dispatch(compiler.ast.Name("TypeError")) 328 self.new_op(RaiseException()) 329 self.set_label(continue_label) 330 else: 331 pass # NOTE: Class methods should be supported. 332 333 # Evaluate the arguments. 334 335 employed_positions = set() 336 extra_keywords = [] 337 338 for frame_pos, arg in enumerate(args): 339 340 # Handle positional and keyword arguments separately. 341 342 if isinstance(arg, compiler.ast.Keyword): 343 344 # Optimise where the target is known now. 345 346 if target is not None: 347 348 # Find the parameter table entry for the target. 349 350 target_name = target.full_name() 351 352 # Look for a callable with the precise target name. 353 354 table_entry = self.paramtable.table[target_name] 355 356 # Look the name up in the parameter table entry. 357 358 try: 359 pos = table_entry[arg.name] 360 361 # Where no position is found, this could be an extra keyword 362 # argument. 363 364 except KeyError: 365 extra_keywords.append(arg) 366 continue 367 368 # Test for illegal conditions. 369 370 if pos in employed_positions: 371 raise TranslateError(self.module.full_name(), node, 372 "Keyword argument %r overwrites parameter %r." % (arg.name, pos)) 373 374 employed_positions.add(pos) 375 376 # Add space for arguments appearing before this one. 377 378 if frame_pos < pos: 379 self.new_op(ReserveFrame(pos - frame_pos)) 380 381 # Generate code for the keyword and the positioning 382 # operation. 383 384 self.dispatch(arg.expr) 385 386 # If the position corresponds to the current frame element, 387 # skip generating the store instruction. 388 389 if frame_pos > pos: 390 self.new_op(StoreFrame(pos)) 391 392 # Otherwise, generate the code needed to obtain the details of 393 # the parameter location. 394 395 else: 396 397 # Combine the target details with the name to get the location. 398 # See the access method on the List class. 399 400 try: 401 paramindex = self.paramtable.get_index(arg.name) 402 403 # Where no position is found, this could be an extra keyword 404 # argument. 405 406 except self.paramtable.TableError: 407 extra_keywords.append(arg) 408 continue 409 410 # Generate code for the keyword and the positioning 411 # operation. 412 413 self.dispatch(arg.expr) 414 self.new_op(StoreFrameIndex(paramindex)) 415 416 # use (callable+0)+paramindex+table 417 # checks embedded offset against (callable+0) 418 # moves the top of stack to frame+position 419 420 else: 421 self.dispatch(arg) 422 employed_positions.add(frame_pos) 423 424 frame_pos = len(args) 425 426 # NOTE: Extra keywords are not supported. 427 # NOTE: Somehow, the above needs to be combined with * arguments. 428 429 # Either test for a complete set of arguments. 430 431 if target is not None: 432 433 # Make sure that enough arguments have been given. 434 435 nargs_max = len(target.positional_names) 436 ndefaults = len(target.defaults) 437 nargs_min = nargs_max - ndefaults 438 439 for i in range(0, nargs_min): 440 if i not in employed_positions: 441 raise TranslateError(self.module.full_name(), node, 442 "Argument %r not supplied for %r: need at least %d arguments." % (i+1, target.name, nargs_min)) 443 444 nargs = len(args) 445 446 if nargs > nargs_max and not target.has_star and not target.has_dstar: 447 raise TranslateError(self.module.full_name(), node, 448 "Too many arguments for %r: need at most %d arguments." % (target.name, nargs_max)) 449 450 # Where defaults are involved, put them into the frame. 451 # Here, we use negative index values to visit the right hand end of 452 # the defaults list. 453 454 for pos in range(nargs_min, nargs_max): 455 if pos not in employed_positions: 456 self.new_op(LoadConst(target)) 457 self.new_op(LoadAttr(target.default_attrs[pos - nargs_min])) 458 459 # If the position corresponds to the current frame element, 460 # skip generating the instruction. 461 462 if frame_pos != pos: 463 self.new_op(StoreFrame(pos)) 464 465 frame_pos += 1 466 467 # Or generate instructions to do this at run-time. 468 # NOTE: CheckFrame has to check the number of arguments and to fill in 469 # NOTE: defaults. 470 471 else: 472 self.new_op(CheckFrame()) 473 474 def _endCallFunc(self): 475 476 "Make the invocation and tidy up afterwards." 477 478 self.new_op(LoadCallable()) # uses the start of the frame to get the callable 479 self.new_op(JumpWithFrame()) 480 481 # NOTE: Exception handling required. 482 483 self.new_op(DropFrame()) 484 485 def _visitName(self, node, classes): 486 487 """ 488 Visit the name-related 'node', generating instructions based on the 489 given 'classes'. 490 """ 491 492 name = node.name 493 scope = self.get_scope(name) 494 #print self.module.name, node.lineno, name, scope 495 self._generateName(name, scope, classes, node) 496 497 def _generateName(self, name, scope, classes, node): 498 499 """ 500 Generate code for the access to 'name' in 'scope' using the given 501 'classes', and using the given 'node' as the source of the access. 502 """ 503 504 NameInstruction, AddressInstruction = classes 505 506 if self._optimise_constant_storage(NameInstruction, 0): 507 return 508 509 if scope == "local": 510 unit = self.unit 511 if isinstance(unit, micropython.inspect.Function): 512 self.new_op(NameInstruction(unit.all_locals()[name])) 513 elif isinstance(unit, micropython.inspect.Class): 514 self.new_op(AddressInstruction(unit.all_class_attributes()[name])) 515 elif isinstance(unit, micropython.inspect.Module): 516 self.new_op(AddressInstruction(unit.module_attributes()[name])) 517 else: 518 raise TranslateError(self.module.full_name(), node, "Program unit %r has no local %r." % (unit, name)) 519 520 elif scope == "global": 521 globals = self.module.module_attributes() 522 if globals.has_key(name): 523 self.new_op(AddressInstruction(globals[name])) 524 else: 525 raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r." % (self.module, name)) 526 527 else: 528 self.new_op(AddressInstruction(self._get_builtin(name, node))) 529 530 def _get_builtin(self, name, node): 531 if self.builtins is not None: 532 try: 533 return self.builtins[name] 534 except KeyError: 535 raise TranslateError(self.module.full_name(), node, "No __builtins__ definition is available for name %r." % name) 536 else: 537 raise TranslateError(self.module.full_name(), node, "No __builtins__ module is available for name %r." % name) 538 539 # Optimisation tests. 540 541 def _should_optimise_constant_storage(self): 542 return "constant_storage" in self.optimisations 543 544 def _should_optimise_constant_test(self): 545 return "constant_test" 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)) # and not isinstance(last[n].attr, micropython.inspect.Instance) 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, LoadConst)) 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_constant_test(self, instruction): 614 615 """ 616 Where this operation tests the topmost stack value which happens to be 617 a constant against another stack value, merge the last instruction which 618 loaded the constant into the current 'instruction'. 619 """ 620 621 if self._should_optimise_constant_test() and \ 622 instruction is TestIdentity and \ 623 self._have_constant_input(0): 624 625 last = self.last_op() 626 self.replace_op(TestIdentityAddress(last.attr)) 627 return 1 628 else: 629 return 0 630 631 def _optimise_known_target(self): 632 633 """ 634 Where the target of an invocation is known, provide information about it 635 and its context. If a class is being invoked and the conditions are 636 appropriate, get information about the specific initialiser. 637 """ 638 639 if self._should_optimise_known_target() and self._have_known_target(): 640 last = self.last_op() 641 target = last.attr.value 642 context = last.attr.parent 643 644 # Handle calls to classes. 645 646 if isinstance(target, micropython.inspect.Class): 647 target = target.get_instantiator() 648 context = micropython.inspect.Instance() 649 650 # A special context is chosen to avoid generating unnecessary 651 # context loading and checking instructions. 652 653 else: 654 target = None 655 context = None 656 657 return target, context 658 659 def _optimise_self_access(self, attrname, instruction): 660 661 """ 662 Where the provided 'attrname' accesses an attribute which occupies the 663 same position in all possible objects which can be accessed, generate an 664 'instruction' accessing the attribute directly. 665 """ 666 667 if self._should_optimise_self_access() and self._have_self_input() and \ 668 not self.unit.is_relocated(attrname): 669 670 attr = self.unit.parent.all_attributes()[attrname] 671 self.new_op(instruction(attr)) 672 return 1 673 else: 674 return 0 675 676 # Visitor methods. 677 678 def default(self, node, *args): 679 raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__) 680 681 def dispatch(self, node, *args): 682 return ASTVisitor.dispatch(self, node, *args) 683 684 def _visitBinary(self, node, left_method, right_method): 685 686 """ 687 _t1 = node.left 688 _t2 = node.right 689 try: 690 _result = _t1.__add__(_t2) 691 if _result is NotImplemented: 692 raise AttributeError 693 except AttributeError: 694 try: 695 _result = _t2.__radd__(_t1) 696 if _result is NotImplemented: 697 raise AttributeError 698 except AttributeError: 699 raise TypeError 700 """ 701 702 end_left_label = self.new_label() 703 right_label = self.new_label() 704 type_error_label = self.new_label() 705 end_label = self.new_label() 706 707 # NOTE: Potentially remove the reservation if optimised storage is used. 708 709 temp_position = self.reserve_temp(2) 710 711 self.dispatch(node.left) 712 713 temp1 = self._optimise_temp_storage() 714 if not temp1: 715 self.new_op(StoreTemp(temp_position)) 716 temp1 = LoadTemp(temp_position) 717 718 self.dispatch(node.right) 719 720 temp2 = self._optimise_temp_storage() 721 if not temp2: 722 self.new_op(StoreTemp(temp_position + 1)) 723 temp2 = LoadTemp(temp_position + 1) 724 725 # Left method. 726 727 self._startCallFunc() 728 self.new_op(temp1) 729 730 # Get left method on temp1. 731 732 self._generateAttr(node, left_method, (LoadAddress, LoadAttr, LoadAttrIndex)) 733 self.dispatch(compiler.ast.Name("AttributeError")) 734 self.new_op(CheckException()) 735 self.new_op(JumpIfTrue(end_left_label)) 736 737 # Add arguments. 738 739 self.new_op(temp1) # Explicit context as first argument. 740 self.new_op(temp2) 741 self._endCallFunc() 742 743 # Test for NotImplemented. 744 # Don't actually raise an exception. 745 746 self.dispatch(compiler.ast.Name("NotImplemented")) 747 if not self._optimise_constant_test(TestIdentity): 748 self.new_op(TestIdentity()) 749 self.new_op(JumpIfTrue(right_label)) 750 self.new_op(Jump(end_label)) 751 752 # End left method attempt. 753 754 self.set_label(end_left_label) 755 self.new_op(DropFrame()) # From the left method call. 756 757 # Right method. 758 759 self.set_label(right_label) 760 self._startCallFunc() 761 self.new_op(temp2) 762 763 # Get right method on temp2. 764 765 self._generateAttr(node, right_method, (LoadAddress, LoadAttr, LoadAttrIndex)) 766 self.dispatch(compiler.ast.Name("AttributeError")) 767 self.new_op(CheckException()) 768 self.new_op(JumpIfTrue(type_error_label)) 769 770 # Add arguments. 771 772 self.new_op(temp2) # Explicit context as first argument. 773 self.new_op(temp1) 774 self._endCallFunc() 775 776 # Test for NotImplemented. 777 # Don't actually raise an exception. 778 779 self.dispatch(compiler.ast.Name("NotImplemented")) 780 if not self._optimise_constant_test(TestIdentity): 781 self.new_op(TestIdentity()) 782 self.new_op(JumpIfTrue(type_error_label)) 783 self.new_op(Jump(end_label)) 784 785 # Raise a TypeError. 786 787 self.set_label(type_error_label) 788 self.dispatch(compiler.ast.Name("TypeError")) 789 self.new_op(RaiseException()) 790 791 self.set_label(end_label) 792 793 # Compilation duties... 794 # NOTE: Potentially remove this when optimised away. 795 796 self.discard_temp(2) 797 798 def visitAdd(self, node): 799 self._visitBinary(node, "__add__", "__radd__") 800 801 def visitAnd(self, node): pass 802 803 def visitAssert(self, node): pass 804 805 def visitAssign(self, node): 806 self.dispatch(node.expr) 807 for n in node.nodes: 808 self.dispatch(n) 809 810 def visitAssAttr(self, node): 811 self._visitAttr(node, (StoreAddress, StoreAttr, StoreAttrIndex)) 812 813 def visitAssList(self, node): pass 814 815 def visitAssName(self, node): 816 self._visitName(node, (StoreName, StoreAddress)) 817 818 visitAssTuple = visitAssList 819 820 def visitAugAssign(self, node): pass 821 822 def visitBackquote(self, node): pass 823 824 def visitBitand(self, node): pass 825 826 def visitBitor(self, node): pass 827 828 def visitBitxor(self, node): pass 829 830 def visitBreak(self, node): 831 next_label, exit_label = self.get_loop_labels() 832 self.new_op(Jump(exit_label)) 833 834 def visitCallFunc(self, node): 835 836 """ 837 Evaluate positional arguments, evaluate and store keyword arguments in 838 the correct location, then invoke the function. 839 """ 840 841 # Mark the frame, evaluate the target, generate the call. 842 843 self._startCallFunc() 844 self.dispatch(node.node) 845 self._generateCallFunc(node.args, node) 846 self._endCallFunc() 847 848 def visitClass(self, node): 849 unit = self.unit 850 self.unit = node.unit 851 self.unit.code_location = self.module.code_location # class body code is not independently addressable 852 self.dispatch(node.code) 853 self.unit = unit 854 855 def visitCompare(self, node): 856 857 """ 858 self.dispatch(node.expr) 859 for op_name, next_node in compare.ops: 860 methods = self.comparison_methods[op_name] 861 if methods is not None: 862 # Generate method call using evaluated argument and next node. 863 else: 864 # Deal with the special operators. 865 # Provide short-circuiting. 866 """ 867 868 def visitConst(self, node): 869 const = self.module.constant_values[node.value] 870 self.new_op(LoadConst(const)) 871 872 def visitContinue(self, node): 873 next_label, exit_label = self.get_loop_labels() 874 self.new_op(Jump(next_label)) 875 876 def visitDecorators(self, node): pass 877 878 def visitDict(self, node): pass 879 880 def visitDiscard(self, node): 881 self.dispatch(node.expr) 882 883 def visitDiv(self, node): 884 self._visitBinary(node, "__div__", "__rdiv__") 885 886 def visitEllipsis(self, node): pass 887 888 def visitExec(self, node): pass 889 890 def visitExpression(self, node): pass 891 892 def visitFloorDiv(self, node): 893 self._visitBinary(node, "__floordiv__", "__rfloordiv__") 894 895 def visitFor(self, node): 896 exit_label = self.new_label() 897 next_label = self.new_label() 898 else_label = self.new_label() 899 900 # Get the "list" to be iterated over, obtain its iterator. 901 902 self._startCallFunc() 903 self.dispatch(node.list) 904 self._generateAttr(node, "__iter__", (LoadAddress, LoadAttr, LoadAttrIndex)) 905 self._generateCallFunc([], node) 906 self._endCallFunc() 907 908 # Iterator on stack. 909 910 # In the loop... 911 912 self.set_label(next_label) 913 914 # Use the iterator to get the next value. 915 916 self._startCallFunc() 917 self.new_op(Duplicate()) 918 self._generateAttr(node, "next", (LoadAddress, LoadAttr, LoadAttrIndex)) 919 self._generateCallFunc([], node) 920 self._endCallFunc() 921 922 # Test for StopIteration. 923 924 self.dispatch(compiler.ast.Name("StopIteration")) 925 self.new_op(CheckException()) 926 if node.else_ is not None: 927 self.new_op(JumpIfTrue(else_label)) 928 else: 929 self.new_op(JumpIfTrue(exit_label)) 930 931 # Assign to the target. 932 933 self.dispatch(node.assign) 934 935 # Process the body with the current next and exit points. 936 937 self.add_loop_labels(next_label, exit_label) 938 self.dispatch(node.body) 939 self.drop_loop_labels() 940 941 # Repeat the loop. 942 943 self.new_op(Jump(next_label)) 944 945 # Produce the "else" section. 946 947 if node.else_ is not None: 948 self.set_label(exit_label) 949 self.dispatch(node.else_) 950 951 # Pop the iterator. 952 953 self.set_label(exit_label) 954 self.new_op(Pop()) 955 956 def visitFrom(self, node): pass 957 958 def visitFunction(self, node): 959 960 # Only store the name when visiting this node from outside. 961 962 if self.unit is not node.unit: 963 self.new_op(LoadConst(node.unit)) 964 self._visitName(node, (StoreName, StoreAddress)) 965 966 # Generate the default initialisation code. 967 968 for attr, default in zip(node.unit.default_attrs, node.unit.defaults): 969 self.dispatch(default) 970 self.new_op(StoreAddress(attr)) 971 972 # Visiting of the code occurs when get_code is invoked on this node. 973 974 else: 975 self.dispatch(node.code) 976 if not isinstance(self.last_op(), Return): 977 self.dispatch(compiler.ast.Name("None")) 978 self.new_op(Return()) 979 980 def visitGenExpr(self, node): pass 981 982 def visitGenExprFor(self, node): pass 983 984 def visitGenExprIf(self, node): pass 985 986 def visitGenExprInner(self, node): pass 987 988 def visitGetattr(self, node): 989 self._visitAttr(node, (LoadAddress, LoadAttr, LoadAttrIndex)) 990 991 def visitGlobal(self, node): pass 992 993 def visitIf(self, node): 994 first = 1 995 exit_label = self.new_label() 996 997 for test, body in node.tests + [(None, node.else_)]: 998 if body is None: 999 break 1000 if not first: 1001 self.set_label(next_label) 1002 if test is not None: 1003 self.dispatch(test) 1004 next_label = self.new_label() 1005 self.new_op(JumpIfFalse(next_label)) 1006 self.dispatch(body) 1007 self.new_op(Jump(exit_label)) 1008 first = 0 1009 1010 self.set_label(exit_label) 1011 1012 def visitImport(self, node): pass 1013 1014 def visitInvert(self, node): pass 1015 1016 def visitKeyword(self, node): pass 1017 1018 def visitLambda(self, node): pass 1019 1020 def visitLeftShift(self, node): pass 1021 1022 def visitList(self, node): pass 1023 1024 def visitListComp(self, node): pass 1025 1026 def visitListCompFor(self, node): pass 1027 1028 def visitListCompIf(self, node): pass 1029 1030 def visitMod(self, node): 1031 self._visitBinary(node, "__mod__", "__rmod__") 1032 1033 def visitModule(self, node): 1034 self.dispatch(node.node) 1035 1036 def visitMul(self, node): 1037 self._visitBinary(node, "__mul__", "__rmul__") 1038 1039 def visitName(self, node): 1040 self._visitName(node, (LoadName, LoadAddress)) 1041 1042 def visitNot(self, node): pass 1043 1044 def visitOr(self, node): pass 1045 1046 def visitPass(self, node): pass 1047 1048 def visitPower(self, node): pass 1049 1050 def visitPrint(self, node): pass 1051 1052 def visitPrintnl(self, node): pass 1053 1054 def visitRaise(self, node): pass 1055 1056 def visitReturn(self, node): 1057 if node.value is not None: 1058 self.dispatch(node.value) 1059 else: 1060 self.dispatch(compiler.ast.Name("None")) 1061 self.new_op(Return()) 1062 1063 def visitRightShift(self, node): pass 1064 1065 def visitSlice(self, node): pass 1066 1067 def visitStmt(self, node): 1068 for n in node.nodes: 1069 self.dispatch(n) 1070 1071 def visitSub(self, node): 1072 self._visitBinary(node, "__sub__", "__rsub__") 1073 1074 def visitSubscript(self, node): pass 1075 1076 def visitTryExcept(self, node): 1077 1078 """ 1079 Enter try block. 1080 Dispatch to code. 1081 1082 """ 1083 1084 exit_label = self.new_label() 1085 handler_label = self.new_label() 1086 1087 self.add_exception_labels(handler_label, exit_label) 1088 1089 # Try... 1090 # Produce the code, then jump to the exit. 1091 1092 self.dispatch(node.body) 1093 self.new_op(Jump(exit_label)) 1094 1095 # Start of handlers. 1096 1097 self.set_label(handler_label) 1098 for name, assignment, handler in node.handlers: 1099 next_label = self.new_label() 1100 1101 # Test the given exception against the current exception. 1102 1103 if name is not None: 1104 self.dispatch(name) 1105 self.new_op(CheckException()) 1106 self.new_op(JumpIfFalse(next_label)) 1107 1108 # Handle assignment to exception variable. 1109 1110 if assignment is not None: 1111 self.dispatch(assignment) 1112 1113 # Produce the handler code, then jump to the exit. 1114 1115 self.dispatch(handler) 1116 self.new_op(Jump(exit_label)) 1117 1118 self.set_label(next_label) 1119 1120 # Unhandled exceptions. 1121 1122 self.new_op(RaiseException()) 1123 1124 # After exception 1125 1126 self.set_label(exit_label) 1127 1128 # Optional else clause. 1129 1130 if node.else_ is not None: 1131 self.dispatch(node.else_) 1132 1133 self.drop_exception_labels() 1134 1135 def visitTryFinally(self, node): pass 1136 1137 def visitTuple(self, node): pass 1138 1139 def visitUnaryAdd(self, node): pass 1140 1141 def visitUnarySub(self, node): pass 1142 1143 def visitWhile(self, node): 1144 exit_label = self.new_label() 1145 next_label = self.new_label() 1146 else_label = self.new_label() 1147 1148 self.set_label(next_label) 1149 self.dispatch(node.test) 1150 if node.else_ is not None: 1151 self.new_op(JumpIfFalse(else_label)) 1152 else: 1153 self.new_op(JumpIfFalse(exit_label)) 1154 1155 self.add_loop_labels(next_label, exit_label) 1156 1157 self.dispatch(node.body) 1158 self.new_op(Jump(next_label)) 1159 1160 if node.else_ is not None: 1161 self.set_label(else_label) 1162 self.dispatch(node.else_) 1163 1164 self.set_label(exit_label) 1165 self.drop_loop_labels() 1166 1167 def visitWith(self, node): pass 1168 1169 def visitYield(self, node): pass 1170 1171 # Useful data. 1172 1173 comparison_methods = { 1174 "==" : ("__eq__", "__ne__"), 1175 "!=" : ("__ne__", "__eq__"), 1176 "<" : ("__lt__", "__gt__"), 1177 "<=" : ("__le__", "__ge__"), 1178 ">=" : ("__ge__", "__le__"), 1179 ">" : ("__gt__", "__lt__"), 1180 "is" : None, 1181 "is not" : None, 1182 "in" : None, 1183 "not in" : None 1184 } 1185 1186 # vim: tabstop=4 expandtab shiftwidth=4