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