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