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