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