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