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