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