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