1 #!/usr/bin/env python 2 3 """ 4 Native library generation. 5 6 Copyright (C) 2007, 2008, 2009, 2010, 2011 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.code import Assembler 23 from micropython.rsvp import * 24 25 class NativeLibrary(Assembler): 26 27 "A native library generator providing common routines." 28 29 def __init__(self, program): 30 31 """ 32 Initialise a native library for the given 'program'. 33 """ 34 35 Assembler.__init__(self, program) 36 37 self.importer = self.program.get_importer() 38 self.builtins = None 39 40 self.unknown_target_block = None 41 self.unknown_target_testable_self_block = None 42 self.known_target_testable_self_block = None 43 44 # Reset the assembler. 45 46 self.reset() 47 48 def get_native_code(self): 49 self.builtins = self.importer.modules.get("__builtins__") 50 51 if self.unknown_target_block is not None: 52 self._generateCallFuncUnknownTarget() 53 54 if self.unknown_target_testable_self_block is not None: 55 self._generateCallFuncUnknownTargetTestableSelf() 56 57 if self.known_target_testable_self_block is not None: 58 self._generateCallFuncKnownTargetTestableSelf() 59 60 return self.blocks 61 62 def _commonCallFunc(self, adjust_block, continue_block): 63 self.new_op(CheckContext(working="source", target="status")) 64 self.new_op(JumpIfFalse(adjust_block, working="status")) 65 66 # Skip adjustment and tests if the context is not a class. 67 # Classes themselves employ a placeholder context so that 68 # instantiators can be callable with a context which will be 69 # overwritten in the frame. 70 71 # Here, the source value should still refer to the context. 72 73 self.new_op(CheckClass(working="source", target="status")) 74 self.new_op(JumpIfFalse(continue_block, working="status")) 75 76 def _commonTestContext(self, success_block): 77 self.new_op(CheckInstance(source="source", target="status")) 78 self.new_op(JumpIfTrue(success_block, working="status")) 79 80 # Where the context is inappropriate, drop the incomplete frame and 81 # raise an exception. 82 83 self.new_op(DropFrame()) 84 85 self.make_exception("TypeError") 86 self.set_target("exception") 87 self.new_op(RaiseException()) 88 89 def _commonAdjustFrame(self, adjust_block, continue_block): 90 self.set_block(adjust_block) 91 self.new_op(AdjustFrame(1)) 92 self.set_block(continue_block) 93 94 def getCallFuncUnknownTarget(self): 95 if self.unknown_target_block is None: 96 self.unknown_target_block = self.new_block() 97 98 return self.unknown_target_block 99 100 def _generateCallFuncUnknownTarget(self): 101 102 """ 103 Some preliminary tests where the target of an invocation is not known. 104 Requires the context in the working value register. 105 """ 106 107 adjust_block = self.new_block() 108 continue_block = self.new_block() 109 110 self.set_block(self.unknown_target_block) 111 self._commonCallFunc(adjust_block, continue_block) 112 self._commonAdjustFrame(adjust_block, continue_block) 113 self.new_op(Return()) 114 115 def getCallFuncUnknownTargetTestableSelf(self): 116 if self.unknown_target_testable_self_block is None: 117 self.unknown_target_testable_self_block = self.new_block() 118 119 return self.unknown_target_testable_self_block 120 121 def _generateCallFuncUnknownTargetTestableSelf(self): 122 123 """ 124 Test any explicit first argument against the context. 125 """ 126 127 adjust_block = self.new_block() 128 continue_block = self.new_block() 129 130 self.set_block(self.unknown_target_testable_self_block) 131 self._commonCallFunc(adjust_block, continue_block) 132 self._commonTestContext(adjust_block) 133 self._commonAdjustFrame(adjust_block, continue_block) 134 self.new_op(Return()) 135 136 def getCallFuncKnownTargetTestableSelf(self): 137 if self.known_target_testable_self_block is None: 138 self.known_target_testable_self_block = self.new_block() 139 140 return self.known_target_testable_self_block 141 142 def _generateCallFuncKnownTargetTestableSelf(self): 143 144 """ 145 Test any explicit first argument against the context. 146 """ 147 148 adjust_block = self.new_block() 149 continue_block = self.new_block() 150 151 self.set_block(self.known_target_testable_self_block) 152 self._commonTestContext(continue_block) 153 self._commonAdjustFrame(adjust_block, continue_block) 154 self.new_op(Return()) 155 156 # vim: tabstop=4 expandtab shiftwidth=4