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 = 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 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 = 1 516 517 for n in node.nodes: 518 self.dispatch(n) 519 520 self.in_assignment = 0 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 hasattr(node, "flags") and node.flags == "OP_DELETE": 565 raise TranslationNotImplementedError("AssName(OP_DELETE)") 566 567 self.start_target() 568 self._visitName(node, self.name_store_instructions) 569 self.assign_value() 570 571 # Add any attribute usage guards. 572 573 self._generateGuards(node) 574 575 visitAssTuple = visitAssList 576 577 def visitAugAssign(self, node): 578 579 # Find the augmented assignment function and attempt to use it. 580 581 temp_fn = self._getOperatorAugAssignFunction(node) 582 self._visitCall(node, temp_fn, (node.node, node.expr)) 583 self.discard_temp(temp_fn) 584 585 # Assign the result to the name. 586 587 self.record_value(1) 588 589 if isinstance(node.node, compiler.ast.Name): 590 self.visitAssName(node.node) 591 elif isinstance(node.node, compiler.ast.Getattr): 592 self.visitAssAttr(node.node) 593 else: 594 raise TranslationNotImplementedError("AugAssign(Slice or Subscript)") 595 596 self.discard_value() 597 598 def visitClass(self, node): 599 if not used_by_unit(node): 600 return 601 602 # Store the name. 603 604 self.new_op(LoadClass(node.unit)) 605 self._storeName(node) 606 607 # Visit the code. 608 609 unit = self.unit 610 self.unit = node.unit 611 self.dispatch(node.code) 612 self.unit = unit 613 614 def visitDecorators(self, node): raise TranslationNotImplementedError("Decorators") 615 616 def visitFrom(self, node): 617 self._visitImport(node) 618 619 # Store each imported name if its reference is not set as a constant 620 # module global. 621 622 module = self.importer.get_module(node.modname) 623 624 for name, alias in node.names: 625 if name != "*": 626 self._importName(module, name, alias, node) 627 else: 628 for attrname in module.module_attributes().keys(): 629 self._importName(module, attrname, None, node) 630 631 def visitFunction(self, node): 632 if not used_by_unit(node): 633 return 634 635 # Only store the name when visiting this node from outside. 636 637 if self.unit is not node.unit: 638 self._visitFunctionDeclaration(node) 639 640 # Record the declared function. 641 642 self._storeName(node) 643 644 # Visiting of the code occurs when get_code is invoked on this node. 645 646 else: 647 self._visitFunctionDefinition(node) 648 649 def visitGlobal(self, node): pass 650 651 def visitImport(self, node): 652 self._visitImport(node) 653 654 for name, alias in node.names: 655 module = self.importer.get_module(name) 656 self.new_op(LoadConst(module)) 657 self._storeName(node, alias or name) 658 659 def visitKeyword(self, node): pass 660 661 def visitLambda(self, node): 662 663 """ 664 Lambda functions can be represented as globally defined functions 665 provided they do not define any default parameter values, since these 666 may defined in a non-global scope. 667 668 Where defaults are defined, an object must be created and its content 669 defined: the callable member of the object's structure must be set to 670 the lambda function definition; each default must be attached to the 671 object as an attribute, as is the case with normal functions and 672 methods. 673 """ 674 675 # Produce the reference to this function when visiting this node from 676 # outside. 677 678 if self.unit is not node.unit: 679 680 # Provide the declared function. 681 682 self._visitFunctionDeclaration(node) 683 684 # Visiting of the code occurs when get_code is invoked on this node. 685 686 else: 687 self._visitFunctionDefinition(node) 688 689 def visitModule(self, node): 690 extend = ExtendFrame() 691 self.new_op(extend) 692 self.dispatch(node.node) 693 self.set_frame_usage(node, extend) 694 695 # Statements. 696 697 def visitStmt(self, node): 698 699 "Process the collection of statements provided by 'node'." 700 701 for n in node.nodes: 702 703 # Process the statement. 704 705 self.dispatch(n) 706 707 # Prevent incorrect optimisation by resetting the optimiser after 708 # each statement. 709 710 self.optimiser.reset() 711 712 def visitAssert(self, node): raise TranslationNotImplementedError("Assert") 713 714 def visitBreak(self, node): 715 next_block, exit_block = self.get_loop_blocks() 716 self.new_op(Jump(exit_block)) 717 718 def visitContinue(self, node): 719 next_block, exit_block = self.get_loop_blocks() 720 self.new_op(Jump(next_block)) 721 722 def visitDiscard(self, node): 723 self.dispatch(node.expr) 724 self.optimiser.optimise_unused_results() 725 726 def visitFor(self, node): 727 temp_iterator, next_block, exit_block, else_block = self._startFor(node, node.else_) 728 self.dispatch(node.body) 729 self._endFor(node, temp_iterator, next_block, exit_block, else_block, node.else_) 730 731 def visitIf(self, node): 732 first = 1 733 next_block = None 734 exit_block = self.new_block() 735 736 clauses = node.tests + [(None, node.else_)] 737 738 for clause in clauses: 739 test, body = clause 740 if body is None: 741 break 742 743 if not first: 744 self.new_op(Jump(exit_block)) # finish last body 745 self.set_block(next_block) # start next test 746 next_block = None 747 748 if test is not None: 749 self.dispatch(test) 750 751 temp = self.optimiser.optimise_temp_storage() 752 self.new_op(temp) 753 self._generateTestBoolean(node, temp) 754 755 next_block = self.new_block() 756 self.new_op(JumpIfFalse(next_block, working="status")) 757 758 self.dispatch(body) 759 first = 0 760 761 if next_block is not None: 762 self.set_block(next_block) 763 764 self.set_block(exit_block) 765 766 def visitIfExp(self, node): raise TranslationNotImplementedError("IfExp") 767 768 def visitPass(self, node): pass 769 770 def visitPrint(self, node): 771 self._visitPrint(node, "_print") 772 773 def visitPrintnl(self, node): 774 self._visitPrint(node, "_printnl") 775 776 def visitRaise(self, node): 777 778 if node.expr1 is not None: 779 780 # NOTE: expr1 only => instance provided 781 782 self.dispatch(node.expr1) 783 784 if node.expr2 is not None: 785 temp = self.optimiser.optimise_temp_storage() 786 787 self.dispatch(node.expr2) 788 temp_arg = self.optimiser.optimise_temp_storage() 789 790 self._generateInvocation(temp, (temp_arg,)) 791 792 self.discard_temp(temp_arg) 793 794 self.new_op(Transfer(source="working", target="exception")) 795 796 self.new_op(RaiseException()) 797 798 def visitReturn(self, node): 799 if node.value is not None: 800 self.dispatch(node.value) 801 else: 802 self.dispatch(compiler.ast.Name("None")) 803 804 if self.in_exception_handler: 805 self.new_op(ClearException(target="exception")) 806 807 # NOTE: Support finally blocks here. 808 809 if self.exception_blocks[-1]: 810 self.new_op(PopHandler(len(self.exception_blocks[-1]))) 811 812 self.new_op(Return()) 813 814 def visitTryExcept(self, node): 815 exit_block = self.new_block() 816 else_block = self.new_block() 817 handler_block = self.new_block() 818 819 self.add_exception_blocks(handler_block, exit_block) 820 821 # Try... 822 # Produce the code, then jump to the exit. 823 824 self.new_op(PushHandler(handler_block)) 825 self.dispatch(node.body) 826 self.new_op(PopHandler(1)) 827 828 if node.else_ is not None: 829 self.new_op(Jump(else_block)) 830 else: 831 self.new_op(Jump(exit_block)) 832 833 # Start of handlers. 834 835 self.set_block(handler_block) 836 self.new_op(PopHandler(1)) 837 838 # Disable the handlers. 839 840 self.drop_exception_blocks() 841 842 for name, assignment, handler in node.handlers: 843 next_block = self.new_block() 844 845 # Test the given exception against the current exception. 846 847 if name is not None: 848 self.dispatch(name) 849 850 self.new_op(CheckException(target="status")) 851 self.new_op(JumpIfFalse(next_block, working="status")) 852 853 # Handle assignment to exception variable. 854 855 if assignment is not None: 856 self.new_op(Transfer(source="working", target="exception")) 857 858 # Record the value to be assigned. 859 860 self.record_value() 861 self.dispatch(assignment) 862 self.discard_value() 863 864 # Produce the handler code, then jump to the exit. 865 866 self.in_exception_handler = 1 867 self.dispatch(handler) 868 self.in_exception_handler = 0 869 870 self.new_op(Jump(exit_block)) 871 872 self.set_block(next_block) 873 874 # Unhandled exceptions. 875 876 self.new_op(RaiseException()) 877 878 # Optional else clause. 879 880 if node.else_ is not None: 881 self.set_block(else_block) 882 self.dispatch(node.else_) 883 884 # Clear the exception. 885 886 self.set_block(exit_block) 887 self.new_op(ClearException(target="exception")) 888 889 def visitTryFinally(self, node): 890 891 """ 892 Add finally handler, potentially as an exception handler. 893 Generate body, potentially changing return statements so that they do 894 not return immediately. 895 Generate handler, removing the handler from the active handler list, 896 adding instructions which raise active exceptions. 897 """ 898 899 raise TranslationNotImplementedError("TryFinally") 900 901 def visitWhile(self, node): 902 exit_block = self.new_block() 903 next_block = self.new_block() 904 else_block = self.new_block() 905 906 self.set_block(next_block) 907 self.dispatch(node.test) 908 909 temp = self.optimiser.optimise_temp_storage() 910 self.new_op(temp) 911 self._generateTestBoolean(node, temp) 912 913 if node.else_ is not None: 914 self.new_op(JumpIfFalse(else_block, working="status")) 915 else: 916 self.new_op(JumpIfFalse(exit_block, working="status")) 917 918 self.add_loop_blocks(next_block, exit_block) 919 920 self.dispatch(node.body) 921 self.new_op(Jump(next_block)) 922 923 if node.else_ is not None: 924 self.set_block(else_block) 925 926 self.dispatch(node.else_) 927 928 self.set_block(exit_block) 929 930 self.drop_loop_blocks() 931 932 def visitWith(self, node): raise TranslationNotImplementedError("With") 933 934 def visitYield(self, node): raise TranslationNotImplementedError("Yield") 935 936 # vim: tabstop=4 expandtab shiftwidth=4