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