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.module is not None: 130 self.dispatch(self.module.module) 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 methods = comparison_methods[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 methods is not None: 302 left_method, right_method = methods 303 304 # Generate method call using evaluated argument and next node. 305 306 temp_result = self._generateBinary(node, temp1, temp2, left_method, right_method) 307 self.new_op(temp_result) 308 self._generateTestBoolean(node, temp_result) 309 self.discard_temp(temp_result) 310 311 else: 312 # Deal with the special operators. 313 314 if op_name.startswith("is"): 315 self.new_op(temp1) 316 self.record_value() 317 self.new_op(temp2) 318 self.new_op(TestIdentity()) 319 self.set_source() 320 self.discard_value() 321 322 elif op_name.endswith("in"): 323 self.new_op(temp2) 324 325 # Get method on temp2. 326 327 self._generateAttr(node, "__contains__", self.attribute_load_instructions) 328 temp_method = self.optimiser.optimise_temp_storage() 329 330 # Add arguments. 331 # NOTE: No support for defaults. 332 333 self._startCallFunc() 334 self.new_op(temp2) 335 self.new_op(StoreFrame(0)) 336 self.new_op(temp1) 337 self.new_op(StoreFrame(1)) 338 self._endCallFuncArgs(2) 339 self._doCallFunc(temp_method) 340 self._endCallFunc(temp_method) 341 342 temp_result = self.get_temp() 343 self._generateTestBoolean(node, temp_result) 344 self.discard_temp(temp_result) 345 346 if op_name.find("not") != -1: 347 self.new_op(InvertBoolean()) 348 349 # Test the result and jump to the end block if false. 350 351 if op is not last_op: 352 self.new_op(JumpIfFalse(end_block)) 353 354 # Compilation duties... 355 356 self.discard_temp(temp1) 357 358 self.discard_temp(temp2) 359 360 # With the status set above, produce a boolean result. 361 362 self.set_block(end_block) 363 364 # Yield the appropriate value. 365 366 self._generateLoadBoolean(node) 367 368 # Expressions. 369 370 def visitBackquote(self, node): raise TranslationNotImplementedError("Backquote") 371 372 def visitCallFunc(self, node): 373 374 """ 375 Evaluate positional arguments, evaluate and store keyword arguments in 376 the correct location, then invoke the function. 377 """ 378 379 # Mark the frame, evaluate the target, generate the call. 380 381 self._startCallFunc() 382 self.dispatch(node.node) 383 temp_target, target, temp_context = self._generateCallFunc(node.args, node) 384 self._doCallFunc(temp_target, target) 385 self._endCallFunc(temp_target, target, temp_context) 386 387 def visitConst(self, node): 388 const = self.importer.get_constant(node.value) 389 self.new_op(LoadConst(const)) 390 391 def visitDict(self, node): raise TranslationNotImplementedError("Dict") 392 393 def visitEllipsis(self, node): raise TranslationNotImplementedError("Ellipsis") 394 395 def visitExec(self, node): raise TranslationNotImplementedError("Exec") 396 397 def visitExpression(self, node): raise TranslationNotImplementedError("Expression") 398 399 def visitGenExpr(self, node): raise TranslationNotImplementedError("GenExpr") 400 401 def visitGenExprFor(self, node): raise TranslationNotImplementedError("GenExprFor") 402 403 def visitGenExprIf(self, node): raise TranslationNotImplementedError("GenExprIf") 404 405 def visitGenExprInner(self, node): raise TranslationNotImplementedError("GenExprInner") 406 407 def visitGetattr(self, node): 408 self._visitAttr(node, self.attribute_load_instructions) 409 410 def visitList(self, node): 411 self._generateList(node) 412 413 def visitListComp(self, node): raise TranslationNotImplementedError("ListComp") 414 415 def visitListCompFor(self, node): raise TranslationNotImplementedError("ListCompFor") 416 417 def visitListCompIf(self, node): raise TranslationNotImplementedError("ListCompIf") 418 419 def visitName(self, node): 420 421 # Handle names referring to constants. 422 423 if self.importer.predefined_constants.has_key(node.name): 424 const = self.importer.get_predefined_constant(node.name) 425 self.new_op(LoadConst(const)) 426 427 # Handle all other names. 428 429 else: 430 self._visitName(node, self.name_load_instructions) 431 432 def visitSlice(self, node): raise TranslationNotImplementedError("Slice") 433 434 def visitSubscript(self, node): 435 self.dispatch(node.expr) 436 self._startCallFunc() 437 self._generateAttr(node, "__getitem__", self.attribute_load_instructions) 438 temp_target, target, temp_context = self._generateCallFunc(node.subs, node) 439 self._doCallFunc(temp_target, target) 440 self._endCallFunc(temp_target, target, temp_context) 441 442 def visitTuple(self, node): 443 self._generateTuple(node) 444 445 # Definitions. 446 447 def visitAssign(self, node): 448 449 """ 450 Evaluate the expression from the given 'node' and assign it to the 451 associated recipients. 452 """ 453 454 self.dispatch(node.expr) 455 456 # Record the value and then dispatch to the assignment targets. 457 458 self.record_value(self.has_immediate_usage(node.nodes)) 459 460 for n in node.nodes: 461 self.dispatch(n) 462 463 self.discard_value() 464 465 def visitAssAttr(self, node): 466 467 "Assign the assignment expression to the recipient 'node'." 468 469 self._visitAttr(node, self.attribute_store_instructions) 470 self.set_source() 471 472 def visitAssList(self, node): 473 474 """ 475 Assign items from the assignment expression to each of the recipients 476 found within the given 'node'. 477 """ 478 479 for i, n in enumerate(node.nodes): 480 self._startCallFunc() 481 self.new_op(self.expr_temp[-1]) 482 self._generateAttr(node, "__getitem__", self.attribute_load_instructions) 483 temp_target, target, temp_context = self._generateCallFunc([compiler.ast.Const(i)], node) 484 self._doCallFunc(temp_target, target) 485 self._endCallFunc(temp_target, target, temp_context) 486 487 # Provide a different source value. 488 # NOTE: Permitting immediate usage given that neither name nor 489 # NOTE: attribute accesses should involve a function call 490 # NOTE: overwriting the above result. 491 492 self.record_value(self.is_immediate_user(n)) 493 self.dispatch(n) 494 self.discard_value() 495 496 def visitAssName(self, node): 497 498 "Assign the assignment expression to the recipient 'node'." 499 500 if hasattr(node, "flags") and node.flags == "OP_DELETE": 501 raise TranslationNotImplementedError("AssName(OP_DELETE)") 502 503 self._visitName(node, self.name_store_instructions) 504 self.set_source() 505 506 # Add any attribute usage guards. 507 508 if self.optimiser.should_optimise_accesses_by_attribute_usage() and hasattr(node, "_attrnames"): 509 self._generateGuards(node) 510 511 visitAssTuple = visitAssList 512 513 def visitAugAssign(self, node): 514 use_binary_block = self.new_block() 515 end_block = self.new_block() 516 517 # Evaluate the expression. 518 519 self.dispatch(node.expr) 520 temp2 = self.optimiser.optimise_temp_storage() 521 522 # Evaluate the target. 523 524 self.dispatch(node.node) 525 temp1 = self.optimiser.optimise_temp_storage() 526 527 # Find the augmented assignment method and attempt to use it. 528 529 aug_method, (left_method, right_method) = augassign_methods[node.op] 530 temp_out = self._generateOpMethod(node, temp1, temp2, aug_method, use_binary_block, use_binary_block, end_block) 531 self.discard_temp(temp_out) # NOTE: Will re-use the same storage. 532 533 # Where no such method exists, use the binary operator methods. 534 535 self.set_block(use_binary_block) 536 temp_out = self._generateBinary(node, temp1, temp2, left_method, right_method) 537 538 # Assign the result to the name. 539 540 self.set_block(end_block) 541 self.new_op(temp_out) 542 self.record_value(1) 543 544 if isinstance(node.node, compiler.ast.Name): 545 self.visitAssName(node.node) 546 elif isinstance(node.node, compiler.ast.Getattr): 547 self.visitAssAttr(node.node) 548 else: 549 raise TranslationNotImplementedError("AugAssign(Slice or Subscript)") 550 551 self.discard_value() 552 553 # Compilation duties... 554 555 self.discard_temp(temp1) 556 self.discard_temp(temp2) 557 558 def visitClass(self, node): 559 if not node.unit.parent.has_key(node.unit.name): 560 return 561 562 # Store the name. 563 564 self.new_op(LoadClass(node.unit)) 565 self.record_value() 566 self._visitName(node, self.name_store_instructions) 567 self.set_source() 568 self.discard_value() 569 570 # Visit the code. 571 572 unit = self.unit 573 self.unit = node.unit 574 self.dispatch(node.code) 575 self.unit = unit 576 577 def visitDecorators(self, node): raise TranslationNotImplementedError("Decorators") 578 579 def visitFrom(self, node): pass 580 581 def visitFunction(self, node): 582 if not node.unit.parent.has_key(node.unit.name): 583 return 584 585 # Only store the name when visiting this node from outside. 586 587 if self.unit is not node.unit: 588 self._visitFunctionDeclaration(node) 589 590 # Record the declared function. 591 592 self.record_value() 593 594 self._visitName(node, self.name_store_instructions) # AssName equivalent 595 self.set_source() 596 self.discard_value() 597 598 # Visiting of the code occurs when get_code is invoked on this node. 599 600 else: 601 self._visitFunctionDefinition(node) 602 603 def visitGlobal(self, node): pass 604 605 def visitImport(self, node): pass 606 607 def visitKeyword(self, node): pass 608 609 def visitLambda(self, node): 610 611 """ 612 Lambda functions can be represented as globally defined functions 613 provided they do not define any default parameter values, since these 614 may defined in a non-global scope. 615 616 Where defaults are defined, an object must be created and its content 617 defined: the callable member of the object's structure must be set to 618 the lambda function definition; each default must be attached to the 619 object as an attribute, as is the case with normal functions and 620 methods. 621 """ 622 623 # Produce the reference to this function when visiting this node from 624 # outside. 625 626 if self.unit is not node.unit: 627 628 # Provide the declared function. 629 630 self._visitFunctionDeclaration(node) 631 632 # Visiting of the code occurs when get_code is invoked on this node. 633 634 else: 635 self._visitFunctionDefinition(node) 636 637 def visitModule(self, node): 638 extend = ExtendFrame() 639 self.new_op(extend) 640 self.dispatch(node.node) 641 self.set_frame_usage(node, extend) 642 643 # Statements. 644 645 def visitStmt(self, node): 646 647 "Process the collection of statements provided by 'node'." 648 649 for n in node.nodes: 650 651 # Process the statement. 652 653 self.dispatch(n) 654 655 # Discard temporary storage. 656 657 if self.temp_positions: 658 #print "Had temp", self.temp_positions 659 self.temp_positions = set() 660 661 # Prevent incorrect optimisation by resetting the optimiser after 662 # each statement. 663 664 self.optimiser.reset() 665 666 def visitAssert(self, node): raise TranslationNotImplementedError("Assert") 667 668 def visitBreak(self, node): 669 next_block, exit_block = self.get_loop_blocks() 670 self.new_op(Jump(exit_block)) 671 672 def visitContinue(self, node): 673 next_block, exit_block = self.get_loop_blocks() 674 self.new_op(Jump(next_block)) 675 676 def visitDiscard(self, node): 677 self.dispatch(node.expr) 678 self.optimiser.optimise_unused_results() 679 680 def visitFor(self, node): 681 next_handler_block = self.new_block() 682 end_handler_block = self.new_block() 683 exit_block = self.new_block() 684 next_block = self.new_block() 685 else_block = self.new_block() 686 687 # Get the "list" to be iterated over, obtain its iterator. 688 689 self._startCallFunc() 690 self.dispatch(node.list) 691 self._generateAttr(node, "__iter__", self.attribute_load_instructions) 692 temp_target, target, temp_context = self._generateCallFunc([], node) 693 self._doCallFunc(temp_target, target) 694 self._endCallFunc(temp_target, target, temp_context) 695 696 # Use a long-lasting temporary storage slot, since any result from the 697 # __iter__ method will not remain around for long. 698 699 temp_iterator = self.get_temp() 700 701 # In the loop... 702 703 self.set_block(next_block) 704 705 # Handle exceptions when calling "next"... 706 707 self.new_op(PushHandler(next_handler_block)) 708 709 # Use the iterator to get the next value. 710 711 self._startCallFunc() 712 self.new_op(temp_iterator) 713 self._generateAttr(node, "next", self.attribute_load_instructions) 714 temp_target, target, temp_context = self._generateCallFunc([], node) 715 self._doCallFunc(temp_target, target) 716 self._endCallFunc(temp_target, target, temp_context) 717 718 # Record the value to be assigned. 719 720 self.record_value() 721 722 # Skip the handler where the call was successful. 723 724 self.new_op(PopHandler()) 725 self.new_op(Jump(end_handler_block)) 726 727 # Enter the exception handler. 728 729 self.set_block(next_handler_block) 730 self.new_op(PopHandler()) 731 732 # Test for StopIteration. 733 734 self.load_builtin("StopIteration", node) 735 self.new_op(CheckException()) 736 if node.else_ is not None: 737 self.new_op(JumpIfTrue(else_block)) 738 else: 739 self.new_op(JumpIfTrue(exit_block)) 740 741 # Re-raise the exception otherwise. 742 743 self.new_op(RaiseException()) 744 745 # After the handler, clear the exception. 746 747 self.set_block(end_handler_block) 748 749 # Assign to the target. 750 751 self.dispatch(node.assign) 752 self.discard_value() 753 754 # Process the body with the current next and exit points. 755 756 self.add_loop_blocks(next_block, exit_block) 757 self.dispatch(node.body) 758 self.drop_loop_blocks() 759 760 # Repeat the loop. 761 762 self.new_op(Jump(next_block)) 763 764 # Produce the "else" section. 765 766 if node.else_ is not None: 767 self.set_block(else_block) 768 self.new_op(ClearException()) 769 self.dispatch(node.else_) 770 771 # After the loop... 772 773 self.set_block(exit_block) 774 775 else: 776 # After the loop... 777 778 self.set_block(exit_block) 779 self.new_op(ClearException()) 780 781 # Compilation duties... 782 783 self.discard_temp(temp_iterator) 784 785 def visitIf(self, node): 786 first = 1 787 next_block = None 788 exit_block = self.new_block() 789 790 clauses = node.tests + [(None, node.else_)] 791 792 for clause in clauses: 793 test, body = clause 794 if body is None: 795 break 796 797 if not first: 798 self.new_op(Jump(exit_block)) # finish last body 799 self.set_block(next_block) # start next test 800 next_block = None 801 802 if test is not None: 803 self.dispatch(test) 804 805 temp = self.optimiser.optimise_temp_storage() 806 self._generateTestBoolean(node, temp) 807 808 next_block = self.new_block() 809 self.new_op(JumpIfFalse(next_block)) 810 811 self.dispatch(body) 812 first = 0 813 814 if next_block is not None: 815 self.set_block(next_block) 816 817 self.set_block(exit_block) 818 819 def visitPass(self, node): pass 820 821 def visitPrint(self, node): raise TranslationNotImplementedError("Print") 822 823 def visitPrintnl(self, node): raise TranslationNotImplementedError("Printnl") 824 825 def visitRaise(self, node): 826 # NOTE: expr1 only => instance provided 827 self.dispatch(node.expr1) 828 829 if node.expr2 is not None: 830 temp = self.optimiser.optimise_temp_storage() 831 832 self.dispatch(node.expr2) 833 temp_arg = self.optimiser.optimise_temp_storage() 834 835 self._startCallFunc() 836 self.new_op(temp_arg) 837 self.new_op(StoreFrame(0)) 838 self._endCallFuncArgs(1) 839 self._doCallFunc(temp) 840 self._endCallFunc(temp) 841 842 self.discard_temp(temp_arg) 843 844 self.new_op(StoreException()) 845 self.new_op(RaiseException()) 846 847 def visitReturn(self, node): 848 if node.value is not None: 849 self.dispatch(node.value) 850 else: 851 self.dispatch(compiler.ast.Name("None")) 852 853 self.new_op(StoreResult()) 854 855 if self.in_exception_handler: 856 self.new_op(ClearException()) 857 858 self.new_op(Return()) 859 860 def visitTryExcept(self, node): 861 exit_block = self.new_block() 862 else_block = self.new_block() 863 handler_block = self.new_block() 864 865 self.add_exception_blocks(handler_block, exit_block) 866 867 # Try... 868 # Produce the code, then jump to the exit. 869 870 self.new_op(PushHandler(handler_block)) 871 self.dispatch(node.body) 872 self.new_op(PopHandler()) 873 874 if node.else_ is not None: 875 self.new_op(Jump(else_block)) 876 else: 877 self.new_op(Jump(exit_block)) 878 879 # Start of handlers. 880 881 self.set_block(handler_block) 882 self.new_op(PopHandler()) 883 884 for name, assignment, handler in node.handlers: 885 next_block = self.new_block() 886 887 # Test the given exception against the current exception. 888 889 if name is not None: 890 self.dispatch(name) 891 892 self.new_op(CheckException()) 893 self.new_op(JumpIfFalse(next_block)) 894 895 # Handle assignment to exception variable. 896 897 if assignment is not None: 898 self.new_op(LoadException()) 899 900 # Record the value to be assigned. 901 902 self.record_value() 903 self.dispatch(assignment) 904 self.discard_value() 905 906 # Produce the handler code, then jump to the exit. 907 908 self.in_exception_handler = 1 909 self.dispatch(handler) 910 self.in_exception_handler = 0 911 912 self.new_op(Jump(exit_block)) 913 914 self.set_block(next_block) 915 916 # Unhandled exceptions. 917 918 self.new_op(RaiseException()) 919 920 # Optional else clause. 921 922 if node.else_ is not None: 923 self.set_block(else_block) 924 self.dispatch(node.else_) 925 926 # Clear the exception. 927 928 self.set_block(exit_block) 929 self.new_op(ClearException()) 930 self.drop_exception_blocks() 931 932 def visitTryFinally(self, node): 933 934 """ 935 Add finally handler, potentially as an exception handler. 936 Generate body, potentially changing return statements so that they do 937 not return immediately. 938 Generate handler, removing the handler from the active handler list, 939 adding instructions which raise active exceptions. 940 """ 941 942 raise TranslationNotImplementedError("TryFinally") 943 944 def visitWhile(self, node): 945 exit_block = self.new_block() 946 next_block = self.new_block() 947 else_block = self.new_block() 948 949 self.set_block(next_block) 950 self.dispatch(node.test) 951 952 temp = self.optimiser.optimise_temp_storage() 953 self._generateTestBoolean(node, temp) 954 955 if node.else_ is not None: 956 self.new_op(JumpIfFalse(else_block)) 957 else: 958 self.new_op(JumpIfFalse(exit_block)) 959 960 self.add_loop_blocks(next_block, exit_block) 961 962 self.dispatch(node.body) 963 self.new_op(Jump(next_block)) 964 965 if node.else_ is not None: 966 self.set_block(else_block) 967 968 self.dispatch(node.else_) 969 970 self.set_block(exit_block) 971 972 self.drop_loop_blocks() 973 974 def visitWith(self, node): raise TranslationNotImplementedError("With") 975 976 def visitYield(self, node): raise TranslationNotImplementedError("Yield") 977 978 # vim: tabstop=4 expandtab shiftwidth=4