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, 2012 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 visitBitand = \ 177 visitBitor = \ 178 visitBitxor = Helper._visitBinaryBit 179 180 visitAdd = \ 181 visitDiv = \ 182 visitFloorDiv = \ 183 visitLeftShift = \ 184 visitMod = \ 185 visitMul = \ 186 visitPower = \ 187 visitRightShift = \ 188 visitSub = Helper._visitBinary 189 190 # Unary operators. 191 192 visitInvert = \ 193 visitUnaryAdd = \ 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, node.nodes) 387 388 def visitListComp(self, node): 389 self._generateList(node) 390 temp_list = self.optimiser.optimise_temp_storage() 391 392 # Get the list's append method. 393 394 self._generateAttr(node, "append", self.attribute_load_instructions) 395 temp_method = self.optimiser.optimise_temp_storage() 396 397 self.visitListCompFor(node.quals[0], node.quals[1:], node.expr, temp_list, temp_method) 398 399 # Generate a reference to the list. 400 401 self.new_op(temp_list) 402 403 self.discard_temp(temp_method) 404 self.discard_temp(temp_list) 405 406 def visitListCompFor(self, node, following_quals, expr, temp_list, temp_method): 407 temp_iterator, next_block, exit_block, else_block = self._startFor(node) 408 409 # Explicit dispatch to tests, following loops, expression. 410 411 if node.ifs: 412 self.visitListCompIf(node.ifs[0], node.ifs[1:], following_quals, expr, temp_list, temp_method) 413 414 # Explicit dispatch to following loops, expression. 415 416 elif following_quals: 417 self.visitListCompFor(following_quals[0], following_quals[1:], expr, temp_list, temp_method) 418 419 # Explicit dispatch to the expression. 420 421 else: 422 self.dispatch(expr) 423 424 # Append the value to the list. 425 426 temp_value = self.optimiser.optimise_temp_storage() 427 self._generateInvocation(temp_method, (temp_list, temp_value,)) 428 429 self._endFor(node, temp_iterator, next_block, exit_block, else_block) 430 431 def visitListCompIf(self, node, following_tests, following_quals, expr, temp_list, temp_method): 432 exit_block = self.new_block() 433 434 # Evaluate the test and jump beyond the body if it is not satisfied. 435 436 self.dispatch(node.test) 437 438 temp = self.optimiser.optimise_temp_storage() 439 self.new_op(temp) 440 self._generateTestBoolean(node, temp) 441 self.new_op(JumpIfFalse(exit_block, working="status")) 442 443 # Explicit dispatch to tests, following loops, expression. 444 445 if following_tests: 446 self.visitListCompIf(following_tests[0], following_tests[1:], following_quals, expr, temp_list, temp_method) 447 448 # Explicit dispatch to following loops, expression. 449 450 elif following_quals: 451 self.visitListCompFor(following_quals[0], following_quals[1:], expr, temp_list, temp_method) 452 453 # Explicit dispatch to the expression. 454 455 else: 456 self.dispatch(expr) 457 458 # Append the value to the list. 459 460 temp_value = self.optimiser.optimise_temp_storage() 461 self._generateInvocation(temp_method, (temp_list, temp_value,)) 462 463 self.set_block(exit_block) 464 465 def visitName(self, node): 466 self._visitName(node, self.name_load_instructions) 467 468 def visitSlice(self, node): 469 args = [node.expr] 470 471 if node.lower is None: 472 args.append(compiler.ast.Name("None")) 473 if node.upper is None: 474 args.append(compiler.ast.Name("None")) 475 else: 476 args.append(node.upper) 477 else: 478 args.append(node.lower) 479 if node.upper is None: 480 args.append(compiler.ast.Name("None")) 481 else: 482 args.append(node.upper) 483 484 temp_fn = self._getOperatorFunction(node, self.in_assignment and "AssSlice" or "Slice") 485 self._visitCall(node, temp_fn, args) 486 self.discard_temp(temp_fn) 487 488 def visitSubscript(self, node): 489 temp_fn = self._getOperatorFunction(node, self.in_assignment and "AssSubscript" or "Subscript") 490 self._visitCall(node, temp_fn, [node.expr] + node.subs) 491 self.discard_temp(temp_fn) 492 493 def visitTuple(self, node): 494 self._generateTuple(node) 495 496 # Definitions. 497 498 def visitAssign(self, node): 499 500 """ 501 Evaluate the expression from the given 'node' and assign it to the 502 associated recipients. 503 """ 504 505 self.dispatch(node.expr) 506 507 # Record the value and then dispatch to the assignment targets. 508 509 self.record_value(self.has_immediate_usage(node.nodes)) 510 511 self.in_assignment = 1 512 513 for n in node.nodes: 514 self.dispatch(n) 515 516 self.in_assignment = 0 517 self.discard_value() 518 519 def visitAssAttr(self, node): 520 521 "Assign the assignment expression to the recipient 'node'." 522 523 self.start_target() 524 self._visitAttr(node, self.optimiser.get_attribute_store_instructions()) 525 self.assign_value() 526 527 def visitAssList(self, node): 528 529 """ 530 Assign items from the assignment expression to each of the recipients 531 found within the given 'node'. 532 """ 533 534 self.new_op(self.expr_temp[-1]) 535 self._generateAttr(node, "__getitem__", self.attribute_load_instructions) 536 temp_getitem = self.optimiser.optimise_temp_storage() 537 538 for i, n in enumerate(node.nodes): 539 self._startCallFunc() 540 self.new_op(temp_getitem) 541 temp_target, target, temp_context = self._generateCallFunc([compiler.ast.Const(i)], node) 542 self._doCallFunc(temp_target, target) 543 self._endCallFunc(temp_context=temp_context) 544 545 # Provide a different source value. 546 # NOTE: Permitting immediate usage given that neither name nor 547 # NOTE: attribute accesses should involve a function call 548 # NOTE: overwriting the above result. 549 550 self.record_value(self.is_immediate_user(n)) 551 self.dispatch(n) 552 self.discard_value() 553 554 self.discard_temp(temp_getitem) 555 556 def visitAssName(self, node): 557 558 "Assign the assignment expression to the recipient 'node'." 559 560 if hasattr(node, "flags") and node.flags == "OP_DELETE": 561 raise TranslationNotImplementedError("AssName(OP_DELETE)") 562 563 self.start_target() 564 self._visitName(node, self.name_store_instructions) 565 self.assign_value() 566 567 # Add any attribute usage guards. 568 569 self._generateGuards(node) 570 571 visitAssTuple = visitAssList 572 573 def visitAugAssign(self, node): 574 575 # Find the augmented assignment function and attempt to use it. 576 577 temp_fn = self._getOperatorAugAssignFunction(node) 578 self._visitCall(node, temp_fn, (node.node, node.expr)) 579 self.discard_temp(temp_fn) 580 581 # Assign the result to the name. 582 583 self.record_value(1) 584 585 if isinstance(node.node, compiler.ast.Name): 586 self.visitAssName(node.node) 587 elif isinstance(node.node, compiler.ast.Getattr): 588 self.visitAssAttr(node.node) 589 else: 590 raise TranslationNotImplementedError("AugAssign(Slice or Subscript)") 591 592 self.discard_value() 593 594 def visitClass(self, node): 595 if not used_by_unit(node): 596 return 597 598 # Store the name. 599 600 self.new_op(LoadClass(node.unit)) 601 self.record_value() 602 self.start_target() 603 self._visitName(node, self.name_store_instructions) 604 self.assign_value() 605 self.discard_value() 606 607 # Visit the code. 608 609 unit = self.unit 610 self.unit = node.unit 611 self.dispatch(node.code) 612 self.unit = unit 613 614 def visitDecorators(self, node): raise TranslationNotImplementedError("Decorators") 615 616 def visitFrom(self, node): pass 617 618 def visitFunction(self, node): 619 if not used_by_unit(node): 620 return 621 622 # Only store the name when visiting this node from outside. 623 624 if self.unit is not node.unit: 625 self._visitFunctionDeclaration(node) 626 627 # Record the declared function. 628 629 self.record_value() 630 631 self.start_target() 632 self._visitName(node, self.name_store_instructions) # AssName equivalent 633 self.assign_value() 634 self.discard_value() 635 636 # Visiting of the code occurs when get_code is invoked on this node. 637 638 else: 639 self._visitFunctionDefinition(node) 640 641 def visitGlobal(self, node): pass 642 643 def visitImport(self, node): pass 644 645 def visitKeyword(self, node): pass 646 647 def visitLambda(self, node): 648 649 """ 650 Lambda functions can be represented as globally defined functions 651 provided they do not define any default parameter values, since these 652 may defined in a non-global scope. 653 654 Where defaults are defined, an object must be created and its content 655 defined: the callable member of the object's structure must be set to 656 the lambda function definition; each default must be attached to the 657 object as an attribute, as is the case with normal functions and 658 methods. 659 """ 660 661 # Produce the reference to this function when visiting this node from 662 # outside. 663 664 if self.unit is not node.unit: 665 666 # Provide the declared function. 667 668 self._visitFunctionDeclaration(node) 669 670 # Visiting of the code occurs when get_code is invoked on this node. 671 672 else: 673 self._visitFunctionDefinition(node) 674 675 def visitModule(self, node): 676 extend = ExtendFrame() 677 self.new_op(extend) 678 self.dispatch(node.node) 679 self.set_frame_usage(node, extend) 680 681 # Statements. 682 683 def visitStmt(self, node): 684 685 "Process the collection of statements provided by 'node'." 686 687 for n in node.nodes: 688 689 # Process the statement. 690 691 self.dispatch(n) 692 693 # Prevent incorrect optimisation by resetting the optimiser after 694 # each statement. 695 696 self.optimiser.reset() 697 698 def visitAssert(self, node): raise TranslationNotImplementedError("Assert") 699 700 def visitBreak(self, node): 701 next_block, exit_block = self.get_loop_blocks() 702 self.new_op(Jump(exit_block)) 703 704 def visitContinue(self, node): 705 next_block, exit_block = self.get_loop_blocks() 706 self.new_op(Jump(next_block)) 707 708 def visitDiscard(self, node): 709 self.dispatch(node.expr) 710 self.optimiser.optimise_unused_results() 711 712 def visitFor(self, node): 713 temp_iterator, next_block, exit_block, else_block = self._startFor(node, node.else_) 714 self.dispatch(node.body) 715 self._endFor(node, temp_iterator, next_block, exit_block, else_block, node.else_) 716 717 def visitIf(self, node): 718 first = 1 719 next_block = None 720 exit_block = self.new_block() 721 722 clauses = node.tests + [(None, node.else_)] 723 724 for clause in clauses: 725 test, body = clause 726 if body is None: 727 break 728 729 if not first: 730 self.new_op(Jump(exit_block)) # finish last body 731 self.set_block(next_block) # start next test 732 next_block = None 733 734 if test is not None: 735 self.dispatch(test) 736 737 temp = self.optimiser.optimise_temp_storage() 738 self.new_op(temp) 739 self._generateTestBoolean(node, temp) 740 741 next_block = self.new_block() 742 self.new_op(JumpIfFalse(next_block, working="status")) 743 744 self.dispatch(body) 745 first = 0 746 747 if next_block is not None: 748 self.set_block(next_block) 749 750 self.set_block(exit_block) 751 752 def visitIfExp(self, node): raise TranslationNotImplementedError("IfExp") 753 754 def visitPass(self, node): pass 755 756 def visitPrint(self, node): 757 self._visitPrint(node, "_print") 758 759 def visitPrintnl(self, node): 760 self._visitPrint(node, "_printnl") 761 762 def visitRaise(self, node): 763 764 if node.expr1 is not None: 765 766 # NOTE: expr1 only => instance provided 767 768 self.dispatch(node.expr1) 769 770 if node.expr2 is not None: 771 temp = self.optimiser.optimise_temp_storage() 772 773 self.dispatch(node.expr2) 774 temp_arg = self.optimiser.optimise_temp_storage() 775 776 self._generateInvocation(temp, (temp_arg,)) 777 778 self.discard_temp(temp_arg) 779 780 self.new_op(Transfer(source="working", target="exception")) 781 782 self.new_op(RaiseException()) 783 784 def visitReturn(self, node): 785 if node.value is not None: 786 self.dispatch(node.value) 787 else: 788 self.dispatch(compiler.ast.Name("None")) 789 790 if self.in_exception_handler: 791 self.new_op(ClearException(target="exception")) 792 793 # NOTE: Support finally blocks here. 794 795 if self.exception_blocks[-1]: 796 self.new_op(PopHandler(len(self.exception_blocks[-1]))) 797 798 self.new_op(Return()) 799 800 def visitTryExcept(self, node): 801 exit_block = self.new_block() 802 else_block = self.new_block() 803 handler_block = self.new_block() 804 805 self.add_exception_blocks(handler_block, exit_block) 806 807 # Try... 808 # Produce the code, then jump to the exit. 809 810 self.new_op(PushHandler(handler_block)) 811 self.dispatch(node.body) 812 self.new_op(PopHandler(1)) 813 814 if node.else_ is not None: 815 self.new_op(Jump(else_block)) 816 else: 817 self.new_op(Jump(exit_block)) 818 819 # Start of handlers. 820 821 self.set_block(handler_block) 822 self.new_op(PopHandler(1)) 823 824 # Disable the handlers. 825 826 self.drop_exception_blocks() 827 828 for name, assignment, handler in node.handlers: 829 next_block = self.new_block() 830 831 # Test the given exception against the current exception. 832 833 if name is not None: 834 self.dispatch(name) 835 836 self.new_op(CheckException(target="status")) 837 self.new_op(JumpIfFalse(next_block, working="status")) 838 839 # Handle assignment to exception variable. 840 841 if assignment is not None: 842 self.new_op(Transfer(source="working", target="exception")) 843 844 # Record the value to be assigned. 845 846 self.record_value() 847 self.dispatch(assignment) 848 self.discard_value() 849 850 # Produce the handler code, then jump to the exit. 851 852 self.in_exception_handler = 1 853 self.dispatch(handler) 854 self.in_exception_handler = 0 855 856 self.new_op(Jump(exit_block)) 857 858 self.set_block(next_block) 859 860 # Unhandled exceptions. 861 862 self.new_op(RaiseException()) 863 864 # Optional else clause. 865 866 if node.else_ is not None: 867 self.set_block(else_block) 868 self.dispatch(node.else_) 869 870 # Clear the exception. 871 872 self.set_block(exit_block) 873 self.new_op(ClearException(target="exception")) 874 875 def visitTryFinally(self, node): 876 877 """ 878 Add finally handler, potentially as an exception handler. 879 Generate body, potentially changing return statements so that they do 880 not return immediately. 881 Generate handler, removing the handler from the active handler list, 882 adding instructions which raise active exceptions. 883 """ 884 885 raise TranslationNotImplementedError("TryFinally") 886 887 def visitWhile(self, node): 888 exit_block = self.new_block() 889 next_block = self.new_block() 890 else_block = self.new_block() 891 892 self.set_block(next_block) 893 self.dispatch(node.test) 894 895 temp = self.optimiser.optimise_temp_storage() 896 self.new_op(temp) 897 self._generateTestBoolean(node, temp) 898 899 if node.else_ is not None: 900 self.new_op(JumpIfFalse(else_block, working="status")) 901 else: 902 self.new_op(JumpIfFalse(exit_block, working="status")) 903 904 self.add_loop_blocks(next_block, exit_block) 905 906 self.dispatch(node.body) 907 self.new_op(Jump(next_block)) 908 909 if node.else_ is not None: 910 self.set_block(else_block) 911 912 self.dispatch(node.else_) 913 914 self.set_block(exit_block) 915 916 self.drop_loop_blocks() 917 918 def visitWith(self, node): raise TranslationNotImplementedError("With") 919 920 def visitYield(self, node): raise TranslationNotImplementedError("Yield") 921 922 # vim: tabstop=4 expandtab shiftwidth=4