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