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