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