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 if self.optimiser.should_optimise_accesses_by_attribute_usage() and hasattr(node, "_attrnames"): 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.new_op(PushHandler(next_handler_block)) 703 704 # Use the iterator to get the next value. 705 706 self._startCallFunc() 707 self.new_op(temp_iterator) 708 self._generateAttr(node, "next", self.attribute_load_instructions) 709 temp_target, target, temp_context = self._generateCallFunc([], node) 710 self._doCallFunc(temp_target, target) 711 self._endCallFunc(temp_target, temp_context) 712 713 # Record the value to be assigned. 714 715 self.record_value() 716 717 # Skip the handler where the call was successful. 718 719 self.new_op(PopHandler()) 720 self.new_op(Jump(end_handler_block)) 721 722 # Enter the exception handler. 723 724 self.set_block(next_handler_block) 725 self.new_op(PopHandler()) 726 727 # Test for StopIteration. 728 729 self.load_builtin("StopIteration", node) 730 self.new_op(CheckException()) 731 if node.else_ is not None: 732 self.new_op(JumpIfTrue(else_block)) 733 else: 734 self.new_op(JumpIfTrue(exit_block)) 735 736 # Re-raise the exception otherwise. 737 738 self.new_op(RaiseException()) 739 740 # After the handler, clear the exception. 741 742 self.set_block(end_handler_block) 743 744 # Assign to the target. 745 746 self.dispatch(node.assign) 747 self.discard_value() 748 749 # Process the body with the current next and exit points. 750 751 self.add_loop_blocks(next_block, exit_block) 752 self.dispatch(node.body) 753 self.drop_loop_blocks() 754 755 # Repeat the loop. 756 757 self.new_op(Jump(next_block)) 758 759 # Produce the "else" section. 760 761 if node.else_ is not None: 762 self.set_block(else_block) 763 self.new_op(ClearException()) 764 self.dispatch(node.else_) 765 766 # After the loop... 767 768 self.set_block(exit_block) 769 770 else: 771 # After the loop... 772 773 self.set_block(exit_block) 774 self.new_op(ClearException()) 775 776 # Compilation duties... 777 778 self.discard_temp(temp_iterator) 779 780 def visitIf(self, node): 781 first = 1 782 next_block = None 783 exit_block = self.new_block() 784 785 clauses = node.tests + [(None, node.else_)] 786 787 for clause in clauses: 788 test, body = clause 789 if body is None: 790 break 791 792 if not first: 793 self.new_op(Jump(exit_block)) # finish last body 794 self.set_block(next_block) # start next test 795 next_block = None 796 797 if test is not None: 798 self.dispatch(test) 799 800 temp = self.optimiser.optimise_temp_storage() 801 self._generateTestBoolean(node, temp) 802 803 next_block = self.new_block() 804 self.new_op(JumpIfFalse(next_block)) 805 806 self.dispatch(body) 807 first = 0 808 809 if next_block is not None: 810 self.set_block(next_block) 811 812 self.set_block(exit_block) 813 814 def visitPass(self, node): pass 815 816 def visitPrint(self, node): raise TranslationNotImplementedError("Print") 817 818 def visitPrintnl(self, node): raise TranslationNotImplementedError("Printnl") 819 820 def visitRaise(self, node): 821 # NOTE: expr1 only => instance provided 822 self.dispatch(node.expr1) 823 824 if node.expr2 is not None: 825 temp = self.optimiser.optimise_temp_storage() 826 827 self.dispatch(node.expr2) 828 temp_arg = self.optimiser.optimise_temp_storage() 829 830 self._generateInvocation(temp, (temp_arg,)) 831 832 self.discard_temp(temp_arg) 833 834 self.new_op(StoreException()) 835 self.new_op(RaiseException()) 836 837 def visitReturn(self, node): 838 if node.value is not None: 839 self.dispatch(node.value) 840 else: 841 self.dispatch(compiler.ast.Name("None")) 842 843 self.new_op(StoreResult()) 844 845 if self.in_exception_handler: 846 self.new_op(ClearException()) 847 848 self.new_op(Return()) 849 850 def visitTryExcept(self, node): 851 exit_block = self.new_block() 852 else_block = self.new_block() 853 handler_block = self.new_block() 854 855 self.add_exception_blocks(handler_block, exit_block) 856 857 # Try... 858 # Produce the code, then jump to the exit. 859 860 self.new_op(PushHandler(handler_block)) 861 self.dispatch(node.body) 862 self.new_op(PopHandler()) 863 864 if node.else_ is not None: 865 self.new_op(Jump(else_block)) 866 else: 867 self.new_op(Jump(exit_block)) 868 869 # Start of handlers. 870 871 self.set_block(handler_block) 872 self.new_op(PopHandler()) 873 874 for name, assignment, handler in node.handlers: 875 next_block = self.new_block() 876 877 # Test the given exception against the current exception. 878 879 if name is not None: 880 self.dispatch(name) 881 882 self.new_op(CheckException()) 883 self.new_op(JumpIfFalse(next_block)) 884 885 # Handle assignment to exception variable. 886 887 if assignment is not None: 888 self.new_op(LoadException()) 889 890 # Record the value to be assigned. 891 892 self.record_value() 893 self.dispatch(assignment) 894 self.discard_value() 895 896 # Produce the handler code, then jump to the exit. 897 898 self.in_exception_handler = 1 899 self.dispatch(handler) 900 self.in_exception_handler = 0 901 902 self.new_op(Jump(exit_block)) 903 904 self.set_block(next_block) 905 906 # Unhandled exceptions. 907 908 self.new_op(RaiseException()) 909 910 # Optional else clause. 911 912 if node.else_ is not None: 913 self.set_block(else_block) 914 self.dispatch(node.else_) 915 916 # Clear the exception. 917 918 self.set_block(exit_block) 919 self.new_op(ClearException()) 920 self.drop_exception_blocks() 921 922 def visitTryFinally(self, node): 923 924 """ 925 Add finally handler, potentially as an exception handler. 926 Generate body, potentially changing return statements so that they do 927 not return immediately. 928 Generate handler, removing the handler from the active handler list, 929 adding instructions which raise active exceptions. 930 """ 931 932 raise TranslationNotImplementedError("TryFinally") 933 934 def visitWhile(self, node): 935 exit_block = self.new_block() 936 next_block = self.new_block() 937 else_block = self.new_block() 938 939 self.set_block(next_block) 940 self.dispatch(node.test) 941 942 temp = self.optimiser.optimise_temp_storage() 943 self._generateTestBoolean(node, temp) 944 945 if node.else_ is not None: 946 self.new_op(JumpIfFalse(else_block)) 947 else: 948 self.new_op(JumpIfFalse(exit_block)) 949 950 self.add_loop_blocks(next_block, exit_block) 951 952 self.dispatch(node.body) 953 self.new_op(Jump(next_block)) 954 955 if node.else_ is not None: 956 self.set_block(else_block) 957 958 self.dispatch(node.else_) 959 960 self.set_block(exit_block) 961 962 self.drop_loop_blocks() 963 964 def visitWith(self, node): raise TranslationNotImplementedError("With") 965 966 def visitYield(self, node): raise TranslationNotImplementedError("Yield") 967 968 # vim: tabstop=4 expandtab shiftwidth=4