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