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, LoadAttrIndexContext, LoadAttrIndexContextCond 41 ) 42 attribute_store_instructions = ( 43 None, None, None, 44 StoreAttr, StoreAttrIndex, None, None 45 ) 46 47 # Name access instructions, for use with the appropriate handlers. 48 49 name_load_instructions = (LoadName, LoadAddress) 50 name_store_instructions = (StoreName, StoreAddress) 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 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, final=0): 118 119 """ 120 Return the top-level module code including finalising code if 'final' is 121 set to a true value. 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 final: 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 + 1 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 # Convert this frame back to being an invocation frame. 172 173 self.new_op(RecoverFrame()) 174 175 # Fix the current frame to include a new storage slot at the beginning. 176 177 self.new_op(AdjustFrame(-1)) 178 179 # Make an object. 180 181 self.make_object(cls, len(cls.instance_attributes())) 182 self.new_op(StoreFrame(0)) 183 184 # Invoke the appropriate initialiser. 185 186 self.new_op(LoadConst(init_method)) 187 self.new_op(LoadCallable()) 188 self.new_op(JumpWithFrame()) 189 190 # Store the object as the result. 191 192 self.new_op(LoadName(init_method.all_locals()["self"])) # load the context in the invocation frame 193 self.new_op(StoreResult()) 194 self.new_op(Return()) 195 196 self.unit.blocks = self.blocks 197 return self.blocks 198 199 # Visitor methods. 200 201 def default(self, node, *args): 202 raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__) 203 204 def dispatch(self, node, *args): 205 return ASTVisitor.dispatch(self, node, *args) 206 207 # Concrete visitor methods. 208 209 # Binary operators. 210 211 visitAdd = Helper._visitBinary 212 visitBitand = Helper._visitBinary 213 visitBitor = Helper._visitBinary 214 visitBitxor = Helper._visitBinary 215 visitDiv = Helper._visitBinary 216 visitFloorDiv = Helper._visitBinary 217 visitLeftShift = Helper._visitBinary 218 visitMod = Helper._visitBinary 219 visitMul = Helper._visitBinary 220 visitPower = Helper._visitBinary 221 visitRightShift = Helper._visitBinary 222 visitSub = Helper._visitBinary 223 224 # Unary operators. 225 226 visitInvert = Helper._visitUnary 227 visitUnaryAdd = Helper._visitUnary 228 visitUnarySub = Helper._visitUnary 229 230 # Logical operators. 231 232 def visitAnd(self, node): 233 end_block = self.new_block() 234 temp_pos = self.reserve_temp() 235 temp = LoadTemp(temp_pos) 236 237 for n in node.nodes[:-1]: 238 self.dispatch(n) 239 self.new_op(StoreTemp(temp_pos)) 240 241 self._generateTestBoolean(n, temp) 242 self.new_op(JumpIfFalse(end_block)) 243 244 self.dispatch(node.nodes[-1]) 245 self.new_op(StoreTemp(temp_pos)) 246 247 self.set_block(end_block) 248 249 self.new_op(temp) 250 self.discard_temp(temp) 251 252 def visitNot(self, node): 253 self.dispatch(node.expr) 254 255 temp = self.optimiser.optimise_temp_storage() 256 self._generateTestBoolean(node.expr, temp) 257 self.discard_temp(temp) 258 259 self.new_op(InvertBoolean()) 260 self._generateLoadBoolean(node) 261 262 def visitOr(self, node): 263 end_block = self.new_block() 264 temp_pos = self.reserve_temp() 265 temp = LoadTemp(temp_pos) 266 267 for n in node.nodes[:-1]: 268 self.dispatch(n) 269 self.new_op(StoreTemp(temp_pos)) 270 271 self._generateTestBoolean(n, temp) 272 self.new_op(JumpIfTrue(end_block)) 273 274 self.dispatch(node.nodes[-1]) 275 self.new_op(StoreTemp(temp_pos)) 276 277 self.set_block(end_block) 278 279 self.new_op(temp) 280 self.discard_temp(temp) 281 282 # Comparisons. 283 284 def visitCompare(self, node): 285 286 """ 287 _t1 = node.expr 288 _t1 op1 _t2 and _t2 op2 _t3 and ... 289 """ 290 291 end_block = self.new_block() 292 293 self.dispatch(node.expr) 294 temp2 = self.optimiser.optimise_temp_storage() 295 296 # NOTE: Replicated by some code in micropython.inspect.visitCompare. 297 298 last_op = node.ops[-1] 299 300 for op in node.ops: 301 op_name, next_node = op 302 methods = comparison_methods[op_name] 303 304 # Propagate the arguments as we traverse the construct. 305 306 temp1 = temp2 307 self.dispatch(next_node) 308 temp2 = self.optimiser.optimise_temp_storage() 309 310 # Use the appropriate mechanism, setting the boolean status for the 311 # comparison. 312 313 if methods is not None: 314 left_method, right_method = methods 315 316 # Generate method call using evaluated argument and next node. 317 318 temp_result = self._generateBinary(node, temp1, temp2, left_method, right_method) 319 self.new_op(temp_result) 320 self._generateTestBoolean(node, temp_result) 321 self.discard_temp(temp_result) 322 323 else: 324 # Deal with the special operators. 325 326 if op_name.startswith("is"): 327 self.new_op(temp1) 328 self.record_value() 329 self.new_op(temp2) 330 self.new_op(TestIdentity()) 331 self.set_source() 332 self.discard_value() 333 334 elif op_name.endswith("in"): 335 self.new_op(temp2) 336 337 # Get method on temp2. 338 339 self._generateAttr(node, "__contains__", self.attribute_load_instructions) 340 temp_method = self.optimiser.optimise_temp_storage() 341 342 # Add arguments. 343 # NOTE: No support for defaults. 344 345 self._startCallFunc() 346 self.new_op(temp2) 347 self.new_op(StoreFrame(0)) 348 self.new_op(temp1) 349 self.new_op(StoreFrame(1)) 350 self._endCallFuncArgs(2) 351 self._doCallFunc(temp_method) 352 self._endCallFunc(temp_method) 353 354 temp_result = self.get_temp() 355 self._generateTestBoolean(node, temp_result) 356 self.discard_temp(temp_result) 357 358 if op_name.find("not") != -1: 359 self.new_op(InvertBoolean()) 360 361 # Test the result and jump to the end block if false. 362 363 if op is not last_op: 364 self.new_op(JumpIfFalse(end_block)) 365 366 # Compilation duties... 367 368 self.discard_temp(temp1) 369 370 self.discard_temp(temp2) 371 372 # With the status set above, produce a boolean result. 373 374 self.set_block(end_block) 375 376 # Yield the appropriate value. 377 378 self._generateLoadBoolean(node) 379 380 # Expressions. 381 382 def visitBackquote(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Backquote") 383 384 def visitCallFunc(self, node): 385 386 """ 387 Evaluate positional arguments, evaluate and store keyword arguments in 388 the correct location, then invoke the function. 389 """ 390 391 # Mark the frame, evaluate the target, generate the call. 392 393 self._startCallFunc() 394 self.dispatch(node.node) 395 temp, target = self._generateCallFunc(node.args, node) 396 self._doCallFunc(temp, target) 397 self._endCallFunc(temp, target) 398 399 def visitConst(self, node): 400 const = self.importer.get_constant(node.value) 401 self.new_op(LoadConst(const)) 402 403 def visitDict(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Dict") 404 405 def visitEllipsis(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Ellipsis") 406 407 def visitExec(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Exec") 408 409 def visitExpression(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Expression") 410 411 def visitGenExpr(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExpr") 412 413 def visitGenExprFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprFor") 414 415 def visitGenExprIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprIf") 416 417 def visitGenExprInner(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprInner") 418 419 def visitGetattr(self, node): 420 self._visitAttr(node, self.attribute_load_instructions) 421 422 def visitList(self, node): 423 self._generateSequence("list", node) 424 425 def visitListComp(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListComp") 426 427 def visitListCompFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompFor") 428 429 def visitListCompIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompIf") 430 431 def visitName(self, node): 432 if self.importer.predefined_constants.has_key(node.name): 433 const = self.importer.get_predefined_constant(node.name) 434 self.new_op(LoadConst(const)) 435 else: 436 self._visitName(node, self.name_load_instructions) 437 438 def visitSlice(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Slice") 439 440 def visitSubscript(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Subscript") 441 442 def visitTuple(self, node): 443 self._generateSequence("tuple", 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 = self._generateCallFunc([compiler.ast.Const(i)], node) 484 self._doCallFunc(temp, target) 485 self._endCallFunc(temp, target) 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 self._visitName(node, self.name_store_instructions) 501 self.set_source() 502 503 visitAssTuple = visitAssList 504 505 def visitAugAssign(self, node): 506 use_binary_block = self.new_block() 507 end_block = self.new_block() 508 509 # Evaluate the expression. 510 511 self.dispatch(node.expr) 512 temp2 = self.optimiser.optimise_temp_storage() 513 514 # Evaluate the target. 515 516 self.dispatch(node.node) 517 temp1 = self.optimiser.optimise_temp_storage() 518 519 # Find the augmented assignment method and attempt to use it. 520 521 aug_method, (left_method, right_method) = augassign_methods[node.op] 522 temp_out = self._generateOpMethod(node, temp1, temp2, aug_method, use_binary_block, end_block) 523 self.discard_temp(temp_out) # NOTE: Will re-use the same storage. 524 525 # Where no such method exists, use the binary operator methods. 526 527 self.set_block(use_binary_block) 528 temp_out = self._generateBinary(node, temp1, temp2, left_method, right_method) 529 530 # Assign the result to the name. 531 532 self.set_block(end_block) 533 self.new_op(temp_out) 534 self.record_value(1) 535 536 if isinstance(node.node, compiler.ast.Name): 537 self.visitAssName(node.node) 538 elif isinstance(node.node, compiler.ast.Getattr): 539 self.visitAssAttr(node.node) 540 else: 541 raise TranslationNotImplementedError(self.module.full_name(), node, "AugAssign(Slice or Subscript)") 542 543 self.discard_value() 544 545 # Compilation duties... 546 547 self.discard_temp(temp1) 548 self.discard_temp(temp2) 549 550 def visitClass(self, node): 551 if not node.unit.referenced: 552 return 553 554 # Store the name. 555 556 self.new_op(LoadConst(node.unit)) 557 self.record_value() 558 self._visitName(node, self.name_store_instructions) 559 self.set_source() 560 self.discard_value() 561 562 # Visit the code. 563 564 unit = self.unit 565 self.unit = node.unit 566 self.dispatch(node.code) 567 self.unit = unit 568 569 def visitDecorators(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Decorators") 570 571 def visitFrom(self, node): pass 572 573 def visitFunction(self, node): 574 if not node.unit.referenced and (not node.unit.is_method() or not node.unit.parent.has_key(node.unit.name)): 575 return 576 577 # Only store the name when visiting this node from outside. 578 579 if self.unit is not node.unit: 580 self.new_op(LoadConst(node.unit)) 581 582 self.record_value() 583 self._visitName(node, self.name_store_instructions) # AssName equivalent 584 self.set_source() 585 self.discard_value() 586 587 self._generateFunctionDefaults(node.unit) 588 589 # Visiting of the code occurs when get_code is invoked on this node. 590 591 else: 592 extend = ExtendFrame() 593 self.new_op(extend) 594 595 self.dispatch(node.code) 596 if not isinstance(self.last_op(), Return): 597 self.dispatch(compiler.ast.Name("None")) 598 self.new_op(StoreResult()) 599 600 self.new_op(Return()) 601 602 self.set_frame_usage(node, extend) 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 temp = self._generateFunctionDefaults(node.unit) 629 self.new_op(LoadConst(node.unit)) 630 631 # Populate the new object required for the function. 632 633 if temp is not None: 634 self.new_op(LoadCallable()) 635 self.new_op(temp) 636 self.new_op(StoreCallable()) 637 638 self.new_op(temp) 639 #self.discard_temp(temp) 640 641 # Visiting of the code occurs when get_code is invoked on this node. 642 643 else: 644 self.dispatch(node.code) 645 self.new_op(StoreResult()) 646 self.new_op(Return()) 647 648 def visitModule(self, node): 649 extend = ExtendFrame() 650 self.new_op(extend) 651 self.dispatch(node.node) 652 self.set_frame_usage(node, extend) 653 654 # Statements. 655 656 def visitStmt(self, node): 657 658 "Process the collection of statements provided by 'node'." 659 660 for n in node.nodes: 661 662 # Process the statement. 663 664 self.dispatch(n) 665 666 # Discard temporary storage. 667 668 if self.temp_positions: 669 #print "Had temp", self.temp_positions 670 self.temp_positions = set() 671 672 # Prevent incorrect optimisation by resetting the optimiser after 673 # each statement. 674 675 self.optimiser.reset() 676 677 def visitAssert(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Assert") 678 679 def visitBreak(self, node): 680 next_block, exit_block = self.get_loop_blocks() 681 self.new_op(Jump(exit_block)) 682 683 def visitContinue(self, node): 684 next_block, exit_block = self.get_loop_blocks() 685 self.new_op(Jump(next_block)) 686 687 def visitDiscard(self, node): 688 self.dispatch(node.expr) 689 self.optimiser.optimise_unused_results() 690 691 def visitFor(self, node): 692 next_handler_block = self.new_block() 693 end_handler_block = self.new_block() 694 exit_block = self.new_block() 695 next_block = self.new_block() 696 else_block = self.new_block() 697 698 # Get the "list" to be iterated over, obtain its iterator. 699 700 self._startCallFunc() 701 self.dispatch(node.list) 702 self._generateAttr(node, "__iter__", self.attribute_load_instructions) 703 temp, target = self._generateCallFunc([], node) 704 self._doCallFunc(temp, target) 705 self._endCallFunc(temp, target) 706 707 temp_iterator = self.optimiser.optimise_temp_storage() 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 = self._generateCallFunc([], node) 723 self._doCallFunc(temp, target) 724 self._endCallFunc(temp, target) 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(Jump(end_handler_block)) 733 734 # Enter the exception handler. 735 736 self.set_block(next_handler_block) 737 self.new_op(PopHandler()) 738 739 # Test for StopIteration. 740 741 self.load_builtin("StopIteration", node) 742 self.new_op(CheckException()) 743 if node.else_ is not None: 744 self.new_op(JumpIfTrue(else_block)) 745 else: 746 self.new_op(JumpIfTrue(exit_block)) 747 748 # Re-raise the exception otherwise. 749 750 self.new_op(RaiseException()) 751 752 # After the handler. 753 754 self.set_block(end_handler_block) 755 756 # Assign to the target. 757 758 self.dispatch(node.assign) 759 self.discard_value() 760 761 # Process the body with the current next and exit points. 762 763 self.add_loop_blocks(next_block, exit_block) 764 self.dispatch(node.body) 765 self.drop_loop_blocks() 766 767 # Repeat the loop. 768 769 self.new_op(Jump(next_block)) 770 771 # Produce the "else" section. 772 773 if node.else_ is not None: 774 self.set_block(exit_block) 775 776 self.dispatch(node.else_) 777 778 # After the loop... 779 780 self.set_block(exit_block) 781 782 # Compilation duties... 783 784 self.discard_temp(temp_iterator) 785 786 def visitIf(self, node): 787 first = 1 788 exit_block = self.new_block() 789 790 clauses = node.tests + [(None, node.else_)] 791 last_clause = clauses[-1] 792 793 for clause in clauses: 794 test, body = clause 795 if body is None: 796 break 797 if not first: 798 self.set_block(next_block) 799 if test is not None: 800 self.dispatch(test) 801 next_block = self.new_block() 802 self.new_op(JumpIfFalse(next_block)) 803 self.dispatch(body) 804 if clause is not last_clause: 805 self.new_op(Jump(exit_block)) 806 807 first = 0 808 809 self.set_block(exit_block) 810 811 def visitPass(self, node): pass 812 813 def visitPrint(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Print") 814 815 def visitPrintnl(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Printnl") 816 817 def visitRaise(self, node): 818 # NOTE: expr1 only => instance provided 819 self.dispatch(node.expr1) 820 821 if node.expr2 is not None: 822 temp = self.optimiser.optimise_temp_storage() 823 824 self.dispatch(node.expr2) 825 temp_arg = self.optimiser.optimise_temp_storage() 826 827 self._startCallFunc() 828 self.new_op(temp_arg) 829 self.new_op(StoreFrame(0)) 830 self._endCallFuncArgs(1) 831 self._doCallFunc(temp) 832 self._endCallFunc(temp) 833 834 self.discard_temp(temp_arg) 835 836 self.new_op(StoreException()) 837 self.new_op(RaiseException()) 838 839 def visitReturn(self, node): 840 if node.value is not None: 841 self.dispatch(node.value) 842 else: 843 self.dispatch(compiler.ast.Name("None")) 844 845 self.new_op(StoreResult()) 846 self.new_op(Return()) 847 848 def visitTryExcept(self, node): 849 exit_block = self.new_block() 850 else_block = self.new_block() 851 handler_block = self.new_block() 852 853 self.add_exception_blocks(handler_block, exit_block) 854 855 # Try... 856 # Produce the code, then jump to the exit. 857 858 self.new_op(PushHandler(handler_block)) 859 self.dispatch(node.body) 860 self.new_op(PopHandler()) 861 862 if node.else_ is not None: 863 self.new_op(Jump(else_block)) 864 else: 865 self.new_op(Jump(exit_block)) 866 867 # Start of handlers. 868 869 self.set_block(handler_block) 870 871 self.new_op(PopHandler()) 872 873 for name, assignment, handler in node.handlers: 874 next_block = self.new_block() 875 876 # Test the given exception against the current exception. 877 878 if name is not None: 879 self.dispatch(name) 880 881 self.new_op(CheckException()) 882 self.new_op(JumpIfFalse(next_block)) 883 884 # Handle assignment to exception variable. 885 886 if assignment is not None: 887 self.new_op(LoadException()) 888 889 # Record the value to be assigned. 890 891 self.record_value() 892 self.dispatch(assignment) 893 self.discard_value() 894 895 # Produce the handler code, then jump to the exit. 896 897 self.dispatch(handler) 898 self.new_op(Jump(exit_block)) 899 900 self.set_block(next_block) 901 902 # Unhandled exceptions. 903 904 self.new_op(RaiseException()) 905 906 # Optional else clause. 907 908 if node.else_ is not None: 909 self.set_block(else_block) 910 911 self.dispatch(node.else_) 912 913 self.set_block(exit_block) 914 self.drop_exception_blocks() 915 916 def visitTryFinally(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "TryFinally") 917 918 def visitWhile(self, node): 919 exit_block = self.new_block() 920 next_block = self.new_block() 921 else_block = self.new_block() 922 923 self.set_block(next_block) 924 self.dispatch(node.test) 925 if node.else_ is not None: 926 self.new_op(JumpIfFalse(else_block)) 927 else: 928 self.new_op(JumpIfFalse(exit_block)) 929 930 self.add_loop_blocks(next_block, exit_block) 931 932 self.dispatch(node.body) 933 self.new_op(Jump(next_block)) 934 935 if node.else_ is not None: 936 self.set_block(else_block) 937 938 self.dispatch(node.else_) 939 940 self.set_block(exit_block) 941 942 self.drop_loop_blocks() 943 944 def visitWith(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "With") 945 946 def visitYield(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Yield") 947 948 # vim: tabstop=4 expandtab shiftwidth=4