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, 2009, 2010, 2011 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 from micropython.opt import Optimiser 23 from micropython.common import * 24 from micropython.data import * 25 from micropython.rsvp import * 26 from micropython.trans import Helper 27 import compiler.ast 28 29 # Program visitors. 30 31 class Translation(ASTVisitor, Helper): 32 33 "A translated module." 34 35 # Attribute access instructions, for use with the appropriate handlers. 36 37 attribute_load_instructions = ( 38 LoadAddress, LoadAddressContext, LoadAddressContextCond, 39 LoadAttr, LoadAttrIndex, LoadAttrIndexContextCond 40 ) 41 attribute_store_instructions = ( 42 None, None, None, 43 StoreAttr, StoreAttrIndex, None 44 ) 45 46 # Name access instructions, for use with the appropriate handlers. 47 48 name_load_instructions = (LoadName, LoadAddress, None) 49 name_store_instructions = (StoreName, StoreAddress, StoreAddressContext) 50 51 def __init__(self, module, program): 52 53 """ 54 Initialise the translation with an inspected 'module' and the 'program' 55 container. 56 """ 57 58 ASTVisitor.__init__(self) 59 self.visitor = self 60 self.module = module 61 62 # Global program dependencies. 63 64 self.program = program 65 self.objtable = self.program.get_object_table() 66 self.paramtable = self.program.get_parameter_table() 67 self.importer = self.program.get_importer() 68 self.builtins = self.importer.modules.get("__builtins__") 69 70 # Optimisation. 71 72 self.optimiser = Optimiser(self, program.optimisations) 73 74 # The current unit being translated. 75 76 self.unit = None 77 78 # The temporary storage used by the current assignment expression. 79 80 self.expr_temp = [] 81 82 # Wiring within the code. 83 84 self.labels = {} 85 self.label_number = 0 86 self.loop_blocks = [] 87 self.exception_blocks = [] 88 self.in_exception_handler = 0 89 self.in_assignment = 0 # for slicing and subscript 90 91 self.reset() 92 93 def __repr__(self): 94 return "Translation(%r)" % self.module 95 96 def reset(self): 97 98 "Reset the state of the translator." 99 100 # The code itself. This is limited to the code for a particular block 101 # being processed. 102 103 self.blocks = [] 104 105 # Information about temporary values. 106 107 self.temp_positions = set() 108 self.max_temp_position = -1 109 110 # Information about instructions which construct frames. 111 112 self.frame_makers = [] 113 114 # Optimiser state must be reset for each unit. 115 116 self.optimiser.reset() 117 118 def get_module_code(self): 119 120 """ 121 Return the top-level module code. 122 """ 123 124 self.unit = self.module 125 self.reset() 126 self.add_exception_unit() 127 128 block = self.new_block() 129 self.set_block(block) 130 131 # Handle exceptions for the program. 132 133 if self.module.name == "__main__": 134 handler_block = self.new_block() 135 self.new_op(PushHandler(handler_block)) 136 137 # Generate code for the module. 138 139 if self.module.astnode is not None: 140 self.dispatch(self.module.astnode) 141 142 # Finish off the translated program if appropriate. 143 144 if self.module.name == "__main__": 145 self.set_block(handler_block) 146 self.new_op(PopHandler(1)) 147 self.new_op(Return()) 148 149 self.drop_exception_unit() 150 self.unit.temp_usage = self.max_temp_position + 1 151 self.unit.blocks = self.blocks 152 return self.blocks 153 154 def get_code(self, unit): 155 156 "Return the code for the given 'unit'." 157 158 self.unit = unit 159 self.reset() 160 self.add_exception_unit() 161 162 block = self.new_block() 163 self.set_block(block) 164 165 if unit.astnode is not None: 166 self.dispatch(unit.astnode) 167 168 self.drop_exception_unit() 169 self.unit.temp_usage = self.max_temp_position + 2 # include space for instantiators to expand backwards 170 self.unit.blocks = self.blocks 171 return self.blocks 172 173 def get_instantiator_code(self, cls): 174 175 "Return the code for the given class 'cls'." 176 177 self.unit = cls.get_instantiator() 178 self.reset() 179 180 block = self.new_block() 181 self.set_block(block) 182 183 init_method = cls.get_init_method() 184 185 # Make an object and store it in the unused first slot. 186 187 self.make_instance(cls, len(cls.instance_attributes())) 188 self.new_op(StoreTemp(0)) 189 190 # Invoke the appropriate initialiser. 191 192 self.new_op(LoadFunction(init_method)) 193 self.new_op(LoadCallable()) 194 self.new_op(JumpInFrame()) 195 196 # Store the object as the result. 197 198 self.new_op(LoadTemp(0)) # load the context from the locals 199 self.new_op(StoreResult()) 200 self.new_op(Return()) 201 202 self.unit.blocks = self.blocks 203 return self.blocks 204 205 # Visitor methods. 206 207 def default(self, node, *args): 208 raise TranslateError("Node class %r is not supported." % node.__class__) 209 210 # Concrete visitor methods. 211 212 # Binary operators. 213 214 visitAdd = Helper._visitBinary 215 visitBitand = Helper._visitBinaryBit 216 visitBitor = Helper._visitBinaryBit 217 visitBitxor = Helper._visitBinaryBit 218 visitDiv = Helper._visitBinary 219 visitFloorDiv = Helper._visitBinary 220 visitLeftShift = Helper._visitBinary 221 visitMod = Helper._visitBinary 222 visitMul = Helper._visitBinary 223 visitPower = Helper._visitBinary 224 visitRightShift = Helper._visitBinary 225 visitSub = Helper._visitBinary 226 227 # Unary operators. 228 229 visitInvert = Helper._visitUnary 230 visitUnaryAdd = Helper._visitUnary 231 visitUnarySub = Helper._visitUnary 232 233 # Logical operators. 234 235 def visitAnd(self, node): 236 end_block = self.new_block() 237 temp_pos = self.reserve_temp() 238 temp = LoadTemp(temp_pos) 239 240 for n in node.nodes[:-1]: 241 self.dispatch(n) 242 self.new_op(StoreTemp(temp_pos)) 243 244 self._generateTestBoolean(n, temp) 245 self.new_op(JumpIfFalse(end_block)) 246 247 self.dispatch(node.nodes[-1]) 248 self.new_op(StoreTemp(temp_pos)) 249 250 self.set_block(end_block) 251 252 self.new_op(temp) 253 self.discard_temp(temp) 254 255 def visitNot(self, node): 256 self.dispatch(node.expr) 257 258 temp = self.optimiser.optimise_temp_storage() 259 self._generateTestBoolean(node.expr, temp) 260 self.discard_temp(temp) 261 262 self.new_op(InvertBoolean()) 263 self._generateLoadBoolean(node) 264 265 def visitOr(self, node): 266 end_block = self.new_block() 267 temp_pos = self.reserve_temp() 268 temp = LoadTemp(temp_pos) 269 270 for n in node.nodes[:-1]: 271 self.dispatch(n) 272 self.new_op(StoreTemp(temp_pos)) 273 274 self._generateTestBoolean(n, temp) 275 self.new_op(JumpIfTrue(end_block)) 276 277 self.dispatch(node.nodes[-1]) 278 self.new_op(StoreTemp(temp_pos)) 279 280 self.set_block(end_block) 281 282 self.new_op(temp) 283 self.discard_temp(temp) 284 285 # Comparisons. 286 287 def visitCompare(self, node): 288 289 """ 290 _t1 = node.expr 291 _t1 op1 _t2 and _t2 op2 _t3 and ... 292 """ 293 294 end_block = self.new_block() 295 296 self.dispatch(node.expr) 297 temp2 = self.optimiser.optimise_temp_storage() 298 299 # NOTE: Replicated by some code in micropython.inspect.visitCompare. 300 301 last_op = node.ops[-1] 302 303 for op in node.ops: 304 op_name, next_node = op 305 operator_fn = operator_functions.get(op_name) 306 307 # Propagate the arguments as we traverse the construct. 308 309 temp1 = temp2 310 self.dispatch(next_node) 311 temp2 = self.optimiser.optimise_temp_storage() 312 313 # Use the appropriate mechanism, setting the boolean status for the 314 # comparison. 315 316 if operator_fn is not None: 317 318 # Generate function call using evaluated argument and next node. 319 320 temp_fn = self._generateOperatorFunction(op_name) 321 self._generateInvocation(temp_fn, (temp1, temp2)) 322 self.discard_temp(temp_fn) 323 324 temp_result = self.optimiser.optimise_temp_storage() 325 self._generateTestBoolean(node, temp_result) 326 self.discard_temp(temp_result) 327 328 else: 329 # Deal with the special operators. 330 331 if op_name.startswith("is"): 332 self.new_op(temp1) 333 self.record_value() 334 self.new_op(temp2) 335 self.new_op(TestIdentity()) 336 self.set_source() 337 self.discard_value() 338 339 elif op_name.endswith("in"): 340 self.new_op(temp2) 341 342 # Get method on temp2. 343 344 self._generateAttr(node, "__contains__", self.attribute_load_instructions) 345 temp_method = self.optimiser.optimise_temp_storage() 346 347 # Add arguments. 348 # NOTE: No support for defaults. 349 350 self._generateInvocation(temp_method, (temp2, temp1)) 351 352 temp_result = self.get_temp() 353 self._generateTestBoolean(node, temp_result) 354 self.discard_temp(temp_result) 355 356 if op_name.find("not") != -1: 357 self.new_op(InvertBoolean()) 358 359 # Test the result and jump to the end block if false. 360 361 if op is not last_op: 362 self.new_op(JumpIfFalse(end_block)) 363 364 # Compilation duties... 365 366 self.discard_temp(temp1) 367 368 self.discard_temp(temp2) 369 370 # With the status set above, produce a boolean result. 371 372 self.set_block(end_block) 373 374 # Yield the appropriate value. 375 376 self._generateLoadBoolean(node) 377 378 # Expressions. 379 380 def visitBackquote(self, node): raise TranslationNotImplementedError("Backquote") 381 382 def visitCallFunc(self, node): 383 384 """ 385 Evaluate positional arguments, evaluate and store keyword arguments in 386 the correct location, then invoke the function. 387 """ 388 389 # Mark the frame, evaluate the target, generate the call. 390 391 self._startCallFunc() 392 self.dispatch(node.node) 393 temp_target, target, temp_context = self._generateCallFunc(node.args, node) 394 self._doCallFunc(temp_target, target) 395 self._endCallFunc(temp_target, temp_context) 396 397 def visitConst(self, node): 398 const = self.importer.get_constant(node.value) 399 self.new_op(LoadConst(const)) 400 401 def visitDict(self, node): raise TranslationNotImplementedError("Dict") 402 403 def visitEllipsis(self, node): raise TranslationNotImplementedError("Ellipsis") 404 405 def visitExec(self, node): raise TranslationNotImplementedError("Exec") 406 407 def visitExpression(self, node): raise TranslationNotImplementedError("Expression") 408 409 def visitGenExpr(self, node): raise TranslationNotImplementedError("GenExpr") 410 411 def visitGenExprFor(self, node): raise TranslationNotImplementedError("GenExprFor") 412 413 def visitGenExprIf(self, node): raise TranslationNotImplementedError("GenExprIf") 414 415 def visitGenExprInner(self, node): raise TranslationNotImplementedError("GenExprInner") 416 417 def visitGetattr(self, node): 418 self._visitAttr(node, self.attribute_load_instructions) 419 420 def visitList(self, node): 421 self._generateList(node) 422 423 def visitListComp(self, node): raise TranslationNotImplementedError("ListComp") 424 425 def visitListCompFor(self, node): raise TranslationNotImplementedError("ListCompFor") 426 427 def visitListCompIf(self, node): raise TranslationNotImplementedError("ListCompIf") 428 429 def visitName(self, node): 430 self._visitName(node, self.name_load_instructions) 431 432 def visitSlice(self, node): 433 args = [node.expr] 434 435 if node.lower is None: 436 args.append(compiler.ast.Name("None")) 437 if node.upper is None: 438 args.append(compiler.ast.Name("None")) 439 else: 440 args.append(node.upper) 441 else: 442 args.append(node.lower) 443 if node.upper is None: 444 args.append(compiler.ast.Name("None")) 445 else: 446 args.append(node.upper) 447 448 temp_fn = self._getOperatorFunction(node, self.in_assignment and "AssSlice" or "Slice") 449 self._visitCall(node, temp_fn, args) 450 self.discard_temp(temp_fn) 451 452 def visitSubscript(self, node): 453 temp_fn = self._getOperatorFunction(node, self.in_assignment and "AssSubscript" or "Subscript") 454 self._visitCall(node, temp_fn, [node.expr] + node.subs) 455 self.discard_temp(temp_fn) 456 457 def visitTuple(self, node): 458 self._generateTuple(node) 459 460 # Definitions. 461 462 def visitAssign(self, node): 463 464 """ 465 Evaluate the expression from the given 'node' and assign it to the 466 associated recipients. 467 """ 468 469 self.dispatch(node.expr) 470 471 # Record the value and then dispatch to the assignment targets. 472 473 self.record_value(self.has_immediate_usage(node.nodes)) 474 475 self.in_assignment = 1 476 477 for n in node.nodes: 478 self.dispatch(n) 479 480 self.in_assignment = 0 481 self.discard_value() 482 483 def visitAssAttr(self, node): 484 485 "Assign the assignment expression to the recipient 'node'." 486 487 self._visitAttr(node, self.attribute_store_instructions) 488 self.set_source() 489 490 def visitAssList(self, node): 491 492 """ 493 Assign items from the assignment expression to each of the recipients 494 found within the given 'node'. 495 """ 496 497 self.new_op(self.expr_temp[-1]) 498 self._generateAttr(node, "__getitem__", self.attribute_load_instructions) 499 temp_getitem = self.optimiser.optimise_temp_storage() 500 501 for i, n in enumerate(node.nodes): 502 self._startCallFunc() 503 self.new_op(temp_getitem) 504 temp_target, target, temp_context = self._generateCallFunc([compiler.ast.Const(i)], node) 505 self._doCallFunc(temp_target, target) 506 self._endCallFunc() 507 508 # Provide a different source value. 509 # NOTE: Permitting immediate usage given that neither name nor 510 # NOTE: attribute accesses should involve a function call 511 # NOTE: overwriting the above result. 512 513 self.record_value(self.is_immediate_user(n)) 514 self.dispatch(n) 515 self.discard_value() 516 517 self.discard_temp(temp_getitem) 518 519 def visitAssName(self, node): 520 521 "Assign the assignment expression to the recipient 'node'." 522 523 if hasattr(node, "flags") and node.flags == "OP_DELETE": 524 raise TranslationNotImplementedError("AssName(OP_DELETE)") 525 526 self._visitName(node, self.name_store_instructions) 527 self.set_source() 528 529 # Add any attribute usage guards. 530 531 self._generateGuards(node) 532 533 visitAssTuple = visitAssList 534 535 def visitAugAssign(self, node): 536 537 # Find the augmented assignment function and attempt to use it. 538 539 temp_fn = self._getOperatorAugAssignFunction(node) 540 self._visitCall(node, temp_fn, (node.node, node.expr)) 541 self.discard_temp(temp_fn) 542 543 # Assign the result to the name. 544 545 self.record_value(1) 546 547 if isinstance(node.node, compiler.ast.Name): 548 self.visitAssName(node.node) 549 elif isinstance(node.node, compiler.ast.Getattr): 550 self.visitAssAttr(node.node) 551 else: 552 raise TranslationNotImplementedError("AugAssign(Slice or Subscript)") 553 554 self.discard_value() 555 556 def visitClass(self, node): 557 if not used_by_unit(node): 558 return 559 560 # Store the name. 561 562 self.new_op(LoadClass(node.unit)) 563 self.record_value() 564 self._visitName(node, self.name_store_instructions) 565 self.set_source() 566 self.discard_value() 567 568 # Visit the code. 569 570 unit = self.unit 571 self.unit = node.unit 572 self.dispatch(node.code) 573 self.unit = unit 574 575 def visitDecorators(self, node): raise TranslationNotImplementedError("Decorators") 576 577 def visitFrom(self, node): pass 578 579 def visitFunction(self, node): 580 if not used_by_unit(node): 581 return 582 583 # Only store the name when visiting this node from outside. 584 585 if self.unit is not node.unit: 586 self._visitFunctionDeclaration(node) 587 588 # Record the declared function. 589 590 self.record_value() 591 592 self._visitName(node, self.name_store_instructions) # AssName equivalent 593 self.set_source() 594 self.discard_value() 595 596 # Visiting of the code occurs when get_code is invoked on this node. 597 598 else: 599 self._visitFunctionDefinition(node) 600 601 def visitGlobal(self, node): pass 602 603 def visitImport(self, node): pass 604 605 def visitKeyword(self, node): pass 606 607 def visitLambda(self, node): 608 609 """ 610 Lambda functions can be represented as globally defined functions 611 provided they do not define any default parameter values, since these 612 may defined in a non-global scope. 613 614 Where defaults are defined, an object must be created and its content 615 defined: the callable member of the object's structure must be set to 616 the lambda function definition; each default must be attached to the 617 object as an attribute, as is the case with normal functions and 618 methods. 619 """ 620 621 # Produce the reference to this function when visiting this node from 622 # outside. 623 624 if self.unit is not node.unit: 625 626 # Provide the declared function. 627 628 self._visitFunctionDeclaration(node) 629 630 # Visiting of the code occurs when get_code is invoked on this node. 631 632 else: 633 self._visitFunctionDefinition(node) 634 635 def visitModule(self, node): 636 extend = ExtendFrame() 637 self.new_op(extend) 638 self.dispatch(node.node) 639 self.set_frame_usage(node, extend) 640 641 # Statements. 642 643 def visitStmt(self, node): 644 645 "Process the collection of statements provided by 'node'." 646 647 for n in node.nodes: 648 649 # Process the statement. 650 651 self.dispatch(n) 652 653 # Discard temporary storage. 654 655 if self.temp_positions: 656 #print "Had temp", self.temp_positions 657 self.temp_positions = set() 658 659 # Prevent incorrect optimisation by resetting the optimiser after 660 # each statement. 661 662 self.optimiser.reset() 663 664 def visitAssert(self, node): raise TranslationNotImplementedError("Assert") 665 666 def visitBreak(self, node): 667 next_block, exit_block = self.get_loop_blocks() 668 self.new_op(Jump(exit_block)) 669 670 def visitContinue(self, node): 671 next_block, exit_block = self.get_loop_blocks() 672 self.new_op(Jump(next_block)) 673 674 def visitDiscard(self, node): 675 self.dispatch(node.expr) 676 self.optimiser.optimise_unused_results() 677 678 def visitFor(self, node): 679 next_handler_block = self.new_block() 680 end_handler_block = self.new_block() 681 exit_block = self.new_block() 682 next_block = self.new_block() 683 else_block = self.new_block() 684 685 # Get the "list" to be iterated over, obtain its iterator. 686 687 self._startCallFunc() 688 self.dispatch(node.list) 689 self._generateAttr(node, "__iter__", self.attribute_load_instructions) 690 temp_target, target, temp_context = self._generateCallFunc([], node) 691 self._doCallFunc(temp_target, target) 692 self._endCallFunc(temp_target, temp_context) 693 694 # Use a long-lasting temporary storage slot, since any result from the 695 # __iter__ method will not remain around for long. 696 697 temp_iterator = self.get_temp() 698 699 # In the loop... 700 701 self.set_block(next_block) 702 703 # Handle exceptions when calling "next"... 704 705 self.add_exception_blocks(next_handler_block, end_handler_block) 706 self.new_op(PushHandler(next_handler_block)) 707 708 # Use the iterator to get the next value. 709 710 self._startCallFunc() 711 self.new_op(temp_iterator) 712 self._generateAttr(node, "next", self.attribute_load_instructions) 713 temp_target, target, temp_context = self._generateCallFunc([], node) 714 self._doCallFunc(temp_target, target) 715 self._endCallFunc(temp_target, temp_context) 716 717 # Record the value to be assigned. 718 719 self.record_value() 720 721 # Skip the handler where the call was successful. 722 723 self.new_op(PopHandler(1)) 724 self.new_op(Jump(end_handler_block)) 725 726 # Enter the exception handler. 727 728 self.set_block(next_handler_block) 729 self.new_op(PopHandler(1)) 730 731 # Disable the handlers. 732 733 self.drop_exception_blocks() 734 735 # Test for StopIteration. 736 737 self.load_builtin("StopIteration", node) 738 self.new_op(CheckException()) 739 if node.else_ is not None: 740 self.new_op(JumpIfTrue(else_block)) 741 else: 742 self.new_op(JumpIfTrue(exit_block)) 743 744 # Re-raise the exception otherwise. 745 746 self.new_op(RaiseException()) 747 748 # After the handler, clear the exception. 749 750 self.set_block(end_handler_block) 751 752 # Assign to the target. 753 754 self.dispatch(node.assign) 755 self.discard_value() 756 757 # Process the body with the current next and exit points. 758 759 self.add_loop_blocks(next_block, exit_block) 760 self.dispatch(node.body) 761 self.drop_loop_blocks() 762 763 # Repeat the loop. 764 765 self.new_op(Jump(next_block)) 766 767 # Produce the "else" section. 768 769 if node.else_ is not None: 770 self.set_block(else_block) 771 self.new_op(ClearException()) 772 self.dispatch(node.else_) 773 774 # After the loop... 775 776 self.set_block(exit_block) 777 778 else: 779 # After the loop... 780 781 self.set_block(exit_block) 782 self.new_op(ClearException()) 783 784 # Compilation duties... 785 786 self.discard_temp(temp_iterator) 787 788 def visitIf(self, node): 789 first = 1 790 next_block = None 791 exit_block = self.new_block() 792 793 clauses = node.tests + [(None, node.else_)] 794 795 for clause in clauses: 796 test, body = clause 797 if body is None: 798 break 799 800 if not first: 801 self.new_op(Jump(exit_block)) # finish last body 802 self.set_block(next_block) # start next test 803 next_block = None 804 805 if test is not None: 806 self.dispatch(test) 807 808 temp = self.optimiser.optimise_temp_storage() 809 self._generateTestBoolean(node, temp) 810 811 next_block = self.new_block() 812 self.new_op(JumpIfFalse(next_block)) 813 814 self.dispatch(body) 815 first = 0 816 817 if next_block is not None: 818 self.set_block(next_block) 819 820 self.set_block(exit_block) 821 822 def visitPass(self, node): pass 823 824 def visitPrint(self, node): 825 self._visitPrint(node, "_print") 826 827 def visitPrintnl(self, node): 828 self._visitPrint(node, "_printnl") 829 830 def visitRaise(self, node): 831 # NOTE: expr1 only => instance provided 832 self.dispatch(node.expr1) 833 834 if node.expr2 is not None: 835 temp = self.optimiser.optimise_temp_storage() 836 837 self.dispatch(node.expr2) 838 temp_arg = self.optimiser.optimise_temp_storage() 839 840 self._generateInvocation(temp, (temp_arg,)) 841 842 self.discard_temp(temp_arg) 843 844 self.new_op(StoreException()) 845 self.new_op(RaiseException()) 846 847 def visitReturn(self, node): 848 if node.value is not None: 849 self.dispatch(node.value) 850 else: 851 self.dispatch(compiler.ast.Name("None")) 852 853 self.new_op(StoreResult()) 854 855 if self.in_exception_handler: 856 self.new_op(ClearException()) 857 858 # NOTE: Support finally blocks here. 859 860 if self.exception_blocks[-1]: 861 self.new_op(PopHandler(len(self.exception_blocks[-1]))) 862 863 self.new_op(Return()) 864 865 def visitTryExcept(self, node): 866 exit_block = self.new_block() 867 else_block = self.new_block() 868 handler_block = self.new_block() 869 870 self.add_exception_blocks(handler_block, exit_block) 871 872 # Try... 873 # Produce the code, then jump to the exit. 874 875 self.new_op(PushHandler(handler_block)) 876 self.dispatch(node.body) 877 self.new_op(PopHandler(1)) 878 879 if node.else_ is not None: 880 self.new_op(Jump(else_block)) 881 else: 882 self.new_op(Jump(exit_block)) 883 884 # Start of handlers. 885 886 self.set_block(handler_block) 887 self.new_op(PopHandler(1)) 888 889 # Disable the handlers. 890 891 self.drop_exception_blocks() 892 893 for name, assignment, handler in node.handlers: 894 next_block = self.new_block() 895 896 # Test the given exception against the current exception. 897 898 if name is not None: 899 self.dispatch(name) 900 901 self.new_op(CheckException()) 902 self.new_op(JumpIfFalse(next_block)) 903 904 # Handle assignment to exception variable. 905 906 if assignment is not None: 907 self.new_op(LoadException()) 908 909 # Record the value to be assigned. 910 911 self.record_value() 912 self.dispatch(assignment) 913 self.discard_value() 914 915 # Produce the handler code, then jump to the exit. 916 917 self.in_exception_handler = 1 918 self.dispatch(handler) 919 self.in_exception_handler = 0 920 921 self.new_op(Jump(exit_block)) 922 923 self.set_block(next_block) 924 925 # Unhandled exceptions. 926 927 self.new_op(RaiseException()) 928 929 # Optional else clause. 930 931 if node.else_ is not None: 932 self.set_block(else_block) 933 self.dispatch(node.else_) 934 935 # Clear the exception. 936 937 self.set_block(exit_block) 938 self.new_op(ClearException()) 939 940 def visitTryFinally(self, node): 941 942 """ 943 Add finally handler, potentially as an exception handler. 944 Generate body, potentially changing return statements so that they do 945 not return immediately. 946 Generate handler, removing the handler from the active handler list, 947 adding instructions which raise active exceptions. 948 """ 949 950 raise TranslationNotImplementedError("TryFinally") 951 952 def visitWhile(self, node): 953 exit_block = self.new_block() 954 next_block = self.new_block() 955 else_block = self.new_block() 956 957 self.set_block(next_block) 958 self.dispatch(node.test) 959 960 temp = self.optimiser.optimise_temp_storage() 961 self._generateTestBoolean(node, temp) 962 963 if node.else_ is not None: 964 self.new_op(JumpIfFalse(else_block)) 965 else: 966 self.new_op(JumpIfFalse(exit_block)) 967 968 self.add_loop_blocks(next_block, exit_block) 969 970 self.dispatch(node.body) 971 self.new_op(Jump(next_block)) 972 973 if node.else_ is not None: 974 self.set_block(else_block) 975 976 self.dispatch(node.else_) 977 978 self.set_block(exit_block) 979 980 self.drop_loop_blocks() 981 982 def visitWith(self, node): raise TranslationNotImplementedError("With") 983 984 def visitYield(self, node): raise TranslationNotImplementedError("Yield") 985 986 # vim: tabstop=4 expandtab shiftwidth=4