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