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(LoadValueIntoResult()) 164 self.new_op(Return()) 165 166 self.unit.blocks = self.blocks 167 return self.blocks 168 169 # Visitor methods. 170 171 def default(self, node, *args): 172 raise TranslateError("Node class %r is not supported." % node.__class__) 173 174 # Concrete visitor methods. 175 176 # Binary operators. 177 178 visitAdd = Helper._visitBinary 179 visitBitand = Helper._visitBinaryBit 180 visitBitor = Helper._visitBinaryBit 181 visitBitxor = Helper._visitBinaryBit 182 visitDiv = Helper._visitBinary 183 visitFloorDiv = Helper._visitBinary 184 visitLeftShift = Helper._visitBinary 185 visitMod = Helper._visitBinary 186 visitMul = Helper._visitBinary 187 visitPower = Helper._visitBinary 188 visitRightShift = Helper._visitBinary 189 visitSub = Helper._visitBinary 190 191 # Unary operators. 192 193 visitInvert = Helper._visitUnary 194 visitUnaryAdd = Helper._visitUnary 195 visitUnarySub = Helper._visitUnary 196 197 # Logical operators. 198 199 def visitAnd(self, node): 200 end_block = self.new_block() 201 temp_pos = self.reserve_temp() 202 temp = LoadTemp(temp_pos) 203 204 for n in node.nodes[:-1]: 205 self.dispatch(n) 206 self.new_op(StoreTemp(temp_pos)) 207 208 self._generateTestBoolean(n, temp) 209 self.new_op(JumpIfFalse(end_block)) 210 211 self.dispatch(node.nodes[-1]) 212 self.new_op(StoreTemp(temp_pos)) 213 214 self.set_block(end_block) 215 216 self.new_op(temp) 217 self.discard_temp(temp) 218 219 def visitNot(self, node): 220 self.dispatch(node.expr) 221 222 temp = self.optimiser.optimise_temp_storage() 223 self._generateTestBoolean(node.expr, temp) 224 self.discard_temp(temp) 225 226 self.new_op(InvertBoolean()) 227 self._generateLoadBoolean(node) 228 229 def visitOr(self, node): 230 end_block = self.new_block() 231 temp_pos = self.reserve_temp() 232 temp = LoadTemp(temp_pos) 233 234 for n in node.nodes[:-1]: 235 self.dispatch(n) 236 self.new_op(StoreTemp(temp_pos)) 237 238 self._generateTestBoolean(n, temp) 239 self.new_op(JumpIfTrue(end_block)) 240 241 self.dispatch(node.nodes[-1]) 242 self.new_op(StoreTemp(temp_pos)) 243 244 self.set_block(end_block) 245 246 self.new_op(temp) 247 self.discard_temp(temp) 248 249 # Comparisons. 250 251 def visitCompare(self, node): 252 253 """ 254 _t1 = node.expr 255 _t1 op1 _t2 and _t2 op2 _t3 and ... 256 """ 257 258 end_block = self.new_block() 259 260 self.dispatch(node.expr) 261 temp2 = self.optimiser.optimise_temp_storage() 262 263 # NOTE: Replicated by some code in micropython.inspect.visitCompare. 264 265 last_op = node.ops[-1] 266 267 for op in node.ops: 268 op_name, next_node = op 269 operator_fn = operator_functions.get(op_name) 270 271 # Propagate the arguments as we traverse the construct. 272 273 temp1 = temp2 274 self.dispatch(next_node) 275 temp2 = self.optimiser.optimise_temp_storage() 276 277 # Use the appropriate mechanism, setting the boolean status for the 278 # comparison. 279 280 if operator_fn is not None: 281 282 # Generate function call using evaluated argument and next node. 283 284 temp_fn = self._generateOperatorFunction(op_name) 285 self._generateInvocation(temp_fn, (temp1, temp2)) 286 self.discard_temp(temp_fn) 287 288 temp_result = self.optimiser.optimise_temp_storage() 289 self._generateTestBoolean(node, temp_result) 290 self.discard_temp(temp_result) 291 292 else: 293 # Deal with the special operators. 294 295 if op_name.startswith("is"): 296 self.new_op(temp1) 297 self.record_value() 298 self.new_op(temp2) 299 self.new_op(TestIdentity()) 300 self.set_source() 301 self.discard_value() 302 303 elif op_name.endswith("in"): 304 self.new_op(temp2) 305 306 # Get method on temp2. 307 308 self._generateAttr(node, "__contains__", self.attribute_load_instructions) 309 temp_method = self.optimiser.optimise_temp_storage() 310 311 # Add arguments. 312 # NOTE: No support for defaults. 313 314 self._generateInvocation(temp_method, (temp2, temp1)) 315 316 temp_result = self.get_temp() 317 self._generateTestBoolean(node, temp_result) 318 self.discard_temp(temp_result) 319 320 if op_name.find("not") != -1: 321 self.new_op(InvertBoolean()) 322 323 # Test the result and jump to the end block if false. 324 325 if op is not last_op: 326 self.new_op(JumpIfFalse(end_block)) 327 328 # Compilation duties... 329 330 self.discard_temp(temp1) 331 332 self.discard_temp(temp2) 333 334 # With the status set above, produce a boolean result. 335 336 self.set_block(end_block) 337 338 # Yield the appropriate value. 339 340 self._generateLoadBoolean(node) 341 342 # Expressions. 343 344 def visitBackquote(self, node): raise TranslationNotImplementedError("Backquote") 345 346 def visitCallFunc(self, node): 347 348 """ 349 Evaluate positional arguments, evaluate and store keyword arguments in 350 the correct location, then invoke the function. 351 """ 352 353 # Mark the frame, evaluate the target, generate the call. 354 355 self._startCallFunc() 356 self.dispatch(node.node) 357 temp_target, target, temp_context = self._generateCallFunc(node.args, node) 358 self._doCallFunc(temp_target, target) 359 self._endCallFunc(temp_target, temp_context) 360 361 def visitConst(self, node): 362 const = self.importer.get_constant(node.value) 363 self.new_op(LoadConst(const)) 364 365 def visitDict(self, node): raise TranslationNotImplementedError("Dict") 366 367 def visitEllipsis(self, node): raise TranslationNotImplementedError("Ellipsis") 368 369 def visitExec(self, node): raise TranslationNotImplementedError("Exec") 370 371 def visitExpression(self, node): raise TranslationNotImplementedError("Expression") 372 373 def visitGenExpr(self, node): raise TranslationNotImplementedError("GenExpr") 374 375 def visitGenExprFor(self, node): raise TranslationNotImplementedError("GenExprFor") 376 377 def visitGenExprIf(self, node): raise TranslationNotImplementedError("GenExprIf") 378 379 def visitGenExprInner(self, node): raise TranslationNotImplementedError("GenExprInner") 380 381 def visitGetattr(self, node): 382 self._visitAttr(node, self.attribute_load_instructions) 383 384 def visitList(self, node): 385 self._generateList(node) 386 387 def visitListComp(self, node): raise TranslationNotImplementedError("ListComp") 388 389 def visitListCompFor(self, node): raise TranslationNotImplementedError("ListCompFor") 390 391 def visitListCompIf(self, node): raise TranslationNotImplementedError("ListCompIf") 392 393 def visitName(self, node): 394 self._visitName(node, self.name_load_instructions) 395 396 def visitSlice(self, node): 397 args = [node.expr] 398 399 if node.lower is None: 400 args.append(compiler.ast.Name("None")) 401 if node.upper is None: 402 args.append(compiler.ast.Name("None")) 403 else: 404 args.append(node.upper) 405 else: 406 args.append(node.lower) 407 if node.upper is None: 408 args.append(compiler.ast.Name("None")) 409 else: 410 args.append(node.upper) 411 412 temp_fn = self._getOperatorFunction(node, self.in_assignment and "AssSlice" or "Slice") 413 self._visitCall(node, temp_fn, args) 414 self.discard_temp(temp_fn) 415 416 def visitSubscript(self, node): 417 temp_fn = self._getOperatorFunction(node, self.in_assignment and "AssSubscript" or "Subscript") 418 self._visitCall(node, temp_fn, [node.expr] + node.subs) 419 self.discard_temp(temp_fn) 420 421 def visitTuple(self, node): 422 self._generateTuple(node) 423 424 # Definitions. 425 426 def visitAssign(self, node): 427 428 """ 429 Evaluate the expression from the given 'node' and assign it to the 430 associated recipients. 431 """ 432 433 self.dispatch(node.expr) 434 435 # Record the value and then dispatch to the assignment targets. 436 437 self.record_value(self.has_immediate_usage(node.nodes)) 438 439 self.in_assignment = 1 440 441 for n in node.nodes: 442 self.dispatch(n) 443 444 self.in_assignment = 0 445 self.discard_value() 446 447 def visitAssAttr(self, node): 448 449 "Assign the assignment expression to the recipient 'node'." 450 451 self._visitAttr(node, self.optimiser.get_attribute_store_instructions()) 452 self.set_source() 453 454 def visitAssList(self, node): 455 456 """ 457 Assign items from the assignment expression to each of the recipients 458 found within the given 'node'. 459 """ 460 461 self.new_op(self.expr_temp[-1]) 462 self._generateAttr(node, "__getitem__", self.attribute_load_instructions) 463 temp_getitem = self.optimiser.optimise_temp_storage() 464 465 for i, n in enumerate(node.nodes): 466 self._startCallFunc() 467 self.new_op(temp_getitem) 468 temp_target, target, temp_context = self._generateCallFunc([compiler.ast.Const(i)], node) 469 self._doCallFunc(temp_target, target) 470 self._endCallFunc() 471 472 # Provide a different source value. 473 # NOTE: Permitting immediate usage given that neither name nor 474 # NOTE: attribute accesses should involve a function call 475 # NOTE: overwriting the above result. 476 477 self.record_value(self.is_immediate_user(n)) 478 self.dispatch(n) 479 self.discard_value() 480 481 self.discard_temp(temp_getitem) 482 483 def visitAssName(self, node): 484 485 "Assign the assignment expression to the recipient 'node'." 486 487 if hasattr(node, "flags") and node.flags == "OP_DELETE": 488 raise TranslationNotImplementedError("AssName(OP_DELETE)") 489 490 self._visitName(node, self.name_store_instructions) 491 self.set_source() 492 493 # Add any attribute usage guards. 494 495 self._generateGuards(node) 496 497 visitAssTuple = visitAssList 498 499 def visitAugAssign(self, node): 500 501 # Find the augmented assignment function and attempt to use it. 502 503 temp_fn = self._getOperatorAugAssignFunction(node) 504 self._visitCall(node, temp_fn, (node.node, node.expr)) 505 self.discard_temp(temp_fn) 506 507 # Assign the result to the name. 508 509 self.record_value(1) 510 511 if isinstance(node.node, compiler.ast.Name): 512 self.visitAssName(node.node) 513 elif isinstance(node.node, compiler.ast.Getattr): 514 self.visitAssAttr(node.node) 515 else: 516 raise TranslationNotImplementedError("AugAssign(Slice or Subscript)") 517 518 self.discard_value() 519 520 def visitClass(self, node): 521 if not used_by_unit(node): 522 return 523 524 # Store the name. 525 526 self.new_op(LoadClass(node.unit)) 527 self.record_value() 528 self._visitName(node, self.name_store_instructions) 529 self.set_source() 530 self.discard_value() 531 532 # Visit the code. 533 534 unit = self.unit 535 self.unit = node.unit 536 self.dispatch(node.code) 537 self.unit = unit 538 539 def visitDecorators(self, node): raise TranslationNotImplementedError("Decorators") 540 541 def visitFrom(self, node): pass 542 543 def visitFunction(self, node): 544 if not used_by_unit(node): 545 return 546 547 # Only store the name when visiting this node from outside. 548 549 if self.unit is not node.unit: 550 self._visitFunctionDeclaration(node) 551 552 # Record the declared function. 553 554 self.record_value() 555 556 self._visitName(node, self.name_store_instructions) # AssName equivalent 557 self.set_source() 558 self.discard_value() 559 560 # Visiting of the code occurs when get_code is invoked on this node. 561 562 else: 563 self._visitFunctionDefinition(node) 564 565 def visitGlobal(self, node): pass 566 567 def visitImport(self, node): pass 568 569 def visitKeyword(self, node): pass 570 571 def visitLambda(self, node): 572 573 """ 574 Lambda functions can be represented as globally defined functions 575 provided they do not define any default parameter values, since these 576 may defined in a non-global scope. 577 578 Where defaults are defined, an object must be created and its content 579 defined: the callable member of the object's structure must be set to 580 the lambda function definition; each default must be attached to the 581 object as an attribute, as is the case with normal functions and 582 methods. 583 """ 584 585 # Produce the reference to this function when visiting this node from 586 # outside. 587 588 if self.unit is not node.unit: 589 590 # Provide the declared function. 591 592 self._visitFunctionDeclaration(node) 593 594 # Visiting of the code occurs when get_code is invoked on this node. 595 596 else: 597 self._visitFunctionDefinition(node) 598 599 def visitModule(self, node): 600 extend = ExtendFrame() 601 self.new_op(extend) 602 self.dispatch(node.node) 603 self.set_frame_usage(node, extend) 604 605 # Statements. 606 607 def visitStmt(self, node): 608 609 "Process the collection of statements provided by 'node'." 610 611 for n in node.nodes: 612 613 # Process the statement. 614 615 self.dispatch(n) 616 617 # Discard temporary storage. 618 619 if self.temp_positions: 620 #print "Had temp", self.temp_positions 621 self.temp_positions = set() 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()) 703 if node.else_ is not None: 704 self.new_op(JumpIfTrue(else_block)) 705 else: 706 self.new_op(JumpIfTrue(exit_block)) 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()) 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()) 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._generateTestBoolean(node, temp) 774 775 next_block = self.new_block() 776 self.new_op(JumpIfFalse(next_block)) 777 778 self.dispatch(body) 779 first = 0 780 781 if next_block is not None: 782 self.set_block(next_block) 783 784 self.set_block(exit_block) 785 786 def visitPass(self, node): pass 787 788 def visitPrint(self, node): 789 self._visitPrint(node, "_print") 790 791 def visitPrintnl(self, node): 792 self._visitPrint(node, "_printnl") 793 794 def visitRaise(self, node): 795 796 if node.expr1 is not None: 797 798 # NOTE: expr1 only => instance provided 799 800 self.dispatch(node.expr1) 801 802 if node.expr2 is not None: 803 temp = self.optimiser.optimise_temp_storage() 804 805 self.dispatch(node.expr2) 806 temp_arg = self.optimiser.optimise_temp_storage() 807 808 self._generateInvocation(temp, (temp_arg,)) 809 810 self.discard_temp(temp_arg) 811 812 self.new_op(StoreException()) 813 814 self.new_op(RaiseException()) 815 816 def visitReturn(self, node): 817 if node.value is not None: 818 self.dispatch(node.value) 819 else: 820 self.dispatch(compiler.ast.Name("None")) 821 822 self.new_op(LoadValueIntoResult()) 823 824 if self.in_exception_handler: 825 self.new_op(ClearException()) 826 827 # NOTE: Support finally blocks here. 828 829 if self.exception_blocks[-1]: 830 self.new_op(PopHandler(len(self.exception_blocks[-1]))) 831 832 self.new_op(Return()) 833 834 def visitTryExcept(self, node): 835 exit_block = self.new_block() 836 else_block = self.new_block() 837 handler_block = self.new_block() 838 839 self.add_exception_blocks(handler_block, exit_block) 840 841 # Try... 842 # Produce the code, then jump to the exit. 843 844 self.new_op(PushHandler(handler_block)) 845 self.dispatch(node.body) 846 self.new_op(PopHandler(1)) 847 848 if node.else_ is not None: 849 self.new_op(Jump(else_block)) 850 else: 851 self.new_op(Jump(exit_block)) 852 853 # Start of handlers. 854 855 self.set_block(handler_block) 856 self.new_op(PopHandler(1)) 857 858 # Disable the handlers. 859 860 self.drop_exception_blocks() 861 862 for name, assignment, handler in node.handlers: 863 next_block = self.new_block() 864 865 # Test the given exception against the current exception. 866 867 if name is not None: 868 self.dispatch(name) 869 870 self.new_op(CheckException()) 871 self.new_op(JumpIfFalse(next_block)) 872 873 # Handle assignment to exception variable. 874 875 if assignment is not None: 876 self.new_op(LoadException()) 877 878 # Record the value to be assigned. 879 880 self.record_value() 881 self.dispatch(assignment) 882 self.discard_value() 883 884 # Produce the handler code, then jump to the exit. 885 886 self.in_exception_handler = 1 887 self.dispatch(handler) 888 self.in_exception_handler = 0 889 890 self.new_op(Jump(exit_block)) 891 892 self.set_block(next_block) 893 894 # Unhandled exceptions. 895 896 self.new_op(RaiseException()) 897 898 # Optional else clause. 899 900 if node.else_ is not None: 901 self.set_block(else_block) 902 self.dispatch(node.else_) 903 904 # Clear the exception. 905 906 self.set_block(exit_block) 907 self.new_op(ClearException()) 908 909 def visitTryFinally(self, node): 910 911 """ 912 Add finally handler, potentially as an exception handler. 913 Generate body, potentially changing return statements so that they do 914 not return immediately. 915 Generate handler, removing the handler from the active handler list, 916 adding instructions which raise active exceptions. 917 """ 918 919 raise TranslationNotImplementedError("TryFinally") 920 921 def visitWhile(self, node): 922 exit_block = self.new_block() 923 next_block = self.new_block() 924 else_block = self.new_block() 925 926 self.set_block(next_block) 927 self.dispatch(node.test) 928 929 temp = self.optimiser.optimise_temp_storage() 930 self._generateTestBoolean(node, temp) 931 932 if node.else_ is not None: 933 self.new_op(JumpIfFalse(else_block)) 934 else: 935 self.new_op(JumpIfFalse(exit_block)) 936 937 self.add_loop_blocks(next_block, exit_block) 938 939 self.dispatch(node.body) 940 self.new_op(Jump(next_block)) 941 942 if node.else_ is not None: 943 self.set_block(else_block) 944 945 self.dispatch(node.else_) 946 947 self.set_block(exit_block) 948 949 self.drop_loop_blocks() 950 951 def visitWith(self, node): raise TranslationNotImplementedError("With") 952 953 def visitYield(self, node): raise TranslationNotImplementedError("Yield") 954 955 # vim: tabstop=4 expandtab shiftwidth=4