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