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