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