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