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