1 #!/usr/bin/env python 2 3 """ 4 RSVP instruction classes. 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.data import Attr, Const 23 from micropython.program import Block 24 25 def name(attr): 26 if isinstance(attr, Attr): 27 return attr.name or "<unnamed>" 28 elif isinstance(attr, (Block, Const)): 29 return attr 30 else: 31 return attr.full_name() or "<unnamed>" 32 33 class Instruction: 34 35 "A generic instruction." 36 37 def __init__(self, attr=None): 38 self.attr = attr 39 self.input = None 40 self.source = None # for storage instructions 41 42 def copy(self): 43 return self.__class__(self.attr) 44 45 def __repr__(self): 46 if self.attr is not None: 47 return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_input()) 48 else: 49 return "%s()%s" % (self.__class__.__name__, self.show_input()) 50 51 def show_input(self): 52 if self.input is not None: 53 if self.source is not None: 54 return " <- (%r, %r)" % (self.input, self.source) 55 else: 56 return " <- %r" % self.input 57 elif self.source is not None: 58 return " <-- %r" % self.source 59 else: 60 return "" 61 62 def get_operand(self): 63 return None 64 65 class FrameRelativeInstruction(Instruction): 66 67 "An instruction operating on the current frame." 68 69 def __repr__(self): 70 return "%s(%r)%s" % (self.__class__.__name__, self.get_operand(), self.show_input()) 71 72 def get_operand(self): 73 return self.attr.position 74 75 FR = FrameRelativeInstruction 76 77 class AddressRelativeInstruction(Instruction): 78 79 "An instruction accessing an object's attribute." 80 81 def __repr__(self): 82 position = self.get_operand() 83 if position is not None: 84 return "%s(%r)%s # %s" % (self.__class__.__name__, position, self.show_input(), name(self.attr)) 85 else: 86 return "%s(%r)%s" % (self.__class__.__name__, name(self.attr), self.show_input()) 87 88 def get_operand(self): 89 return self.attr.position 90 91 AR = AddressRelativeInstruction 92 93 class AddressInstruction(Instruction): 94 95 "An instruction loading an address directly." 96 97 def __repr__(self): 98 location, position, result = self.get_operands() 99 if location is not None: 100 return "%s(%r)%s # %r, %r (%s)" % ( 101 self.__class__.__name__, result, self.show_input(), location, position, name(self.attr)) 102 elif result is not None: 103 return "%s(%r)%s # %s" % ( 104 self.__class__.__name__, result, self.show_input(), name(self.attr)) 105 else: 106 return "%s(...)%s # %s" % ( 107 self.__class__.__name__, self.show_input(), name(self.attr)) 108 109 def get_operands(self): 110 if isinstance(self.attr, Attr): 111 position = self.attr.position 112 location = self.attr.parent.location 113 114 # NOTE: Unpositioned attributes are handled here. 115 116 if location is not None and position is not None: 117 result = location + position + 1 118 else: 119 location = self.attr.parent.name 120 position = self.attr.name 121 result = None 122 return location, position, result 123 else: 124 return None, None, self.attr.location 125 126 def get_operand(self): 127 return self.get_operands()[-1] 128 129 Address = AddressInstruction 130 131 class TargetInstruction(Instruction): 132 133 "An instruction loading the address of an invocation target." 134 135 def __repr__(self): 136 return "%s(%r) # %r" % (self.__class__.__name__, self.get_operand(), name(self.attr)) 137 138 def get_operand(self): 139 return self.attr.code_body_location 140 141 Target = TargetInstruction 142 143 class ImmediateInstruction(Instruction): 144 145 "An instruction employing a constant." 146 147 def __repr__(self): 148 return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_input()) 149 150 def get_operand(self): 151 return self.attr 152 153 Immediate = ImmediateInstruction 154 155 # Access to stored constant data. 156 157 class LoadConst(Address): "Load the constant or module from the specified location." 158 class LoadClass(Address): "Load the class from the specified location." 159 class LoadFunction(Address): "Load the function from the specified location." 160 161 # Access within an invocation frame. 162 163 class LoadName(FR): "Load the current value from the given local attribute/variable." 164 class StoreName(FR): "Store the source value into the given local attribute/variable." 165 class LoadTemp(Immediate): "Load the current value from the given temporary location." 166 class StoreTemp(Immediate): "Store the current value into the given temporary location." 167 168 # Access to static data. 169 170 class LoadAddress(Address): "Load the current value from the given fixed attribute address." 171 class StoreAddress(Address): "Store the source value into the given fixed attribute address." 172 class LoadAddressContext(Address): "Load the current value from the given fixed attribute address, using the current value as context." 173 class StoreAddressContext(Address): "Store the current value into the given fixed attribute address, using the current value as context." 174 class LoadAddressContextCond(Address): 175 """Load the current value from the given fixed attribute address, only using the current value as 176 context if the attribute is compatible.""" 177 class MakeInstance(Immediate): "Make a new instance using the current value as a reference to a template." 178 class MakeFragment(Immediate): "Make a new list fragment." 179 180 # Access to address-relative data. (LoadAttrIndexContext not defined.) 181 182 class LoadAttr(AR): "Load into the current value the given attribute of the object referenced by the current value." 183 class StoreAttr(AR): "Store the source value into the given attribute of the object referenced by the current value." 184 class LoadAttrIndex(Immediate): "Load into the current value the attribute of the current value with the given index." 185 class StoreAttrIndex(Immediate): "Store the source value into the attribute of the current value with the given index." 186 class LoadAttrIndexContextCond(Immediate): 187 """Load into the current value the attribute of the current value with the given index, only making the 188 current value the context if the attribute is compatible.""" 189 190 # Access to object details. 191 192 class LoadCallable(Instruction): "Load the target of an invocation." 193 class StoreCallable(Instruction): "Store the source value into the object referenced by the current value." 194 195 # Access to invocation frames in preparation. 196 197 class MakeFrame(Immediate): "Make a new invocation frame." 198 class AdjustFrame(Immediate): "Adjust the current invocation frame for corrected invocations." 199 class DropFrame(Instruction): "Drop an invocation frame." 200 class StoreFrame(Immediate): "Store the current value as an argument for the parameter with the given position." 201 class StoreFrameIndex(Immediate): "Store the source value as an argument of the current value for the parameter with the given index." 202 class LoadContext(Instruction): "Load the context of an invocation." 203 204 # Context-related tests. 205 206 class CheckContext(Instruction): "Check to see if the context is valid." 207 class CheckClass(Instruction): "Check the current value to determine whether it is a class." 208 class CheckSelf(Instruction): "Check the first argument of an invocation against the target." 209 210 # Access to frames upon invocation. 211 212 class CheckFrame(Immediate): "Check the frame for the correct number of arguments." 213 class FillDefaults(Immediate): "Fill frame positions with defaults, if appropriate." 214 class ExtendFrame(Immediate): "Extend the current frame for temporary storage use." 215 216 # Invocation-related instructions, using a special result "register". 217 218 class JumpInFrame(Instruction): "Jump, using the current locals, to the current callable." 219 class JumpWithFrame(Instruction): "Jump, adopting the invocation frame, to the current callable." 220 class JumpWithFrameDirect(Target): "Jump to the specified address, adopting the invocation frame." 221 class Return(Instruction): "Return from a subprogram." 222 class LoadResult(Instruction): "Load into the current value a returned value." 223 class StoreResult(Instruction): "Store the current value as a value to be returned." 224 225 # Branch-related instructions. 226 227 class Jump(Address): "Jump unconditionally." 228 class JumpIfFalse(Address): "Jump if the last evaluation gave a false result." 229 class JumpIfTrue(Address): "Jump if the last evaluation gave a true result." 230 231 # Exception-related instructions, using a special exception "register". 232 233 class LoadException(Instruction): "Load the raised exception." 234 class StoreException(Instruction): "Store the current object in the exception register." 235 class ClearException(Instruction): "Reset the exception register." 236 class RaiseException(Instruction): "Raise an exception, jumping to the active handler." 237 class PushHandler(Address): "Push an exception handler onto the handler stack." 238 class PopHandler(Instruction): "Pop an exception handler from the handler stack." 239 class CheckException(Instruction): "Check the raised exception against another." 240 241 # Test instructions, operating on the boolean status register. 242 243 class TestIdentity(Instruction): "Test whether the current value is identical to the source value, setting the boolean status." 244 class TestIdentityAddress(Address): "Test whether the current value is identical to the given address, setting the boolean status." 245 class InvertBoolean(Instruction): "Invert the boolean status." 246 247 # Instructions which affect the current value. (LoadAttrIndexContext not defined.) 248 249 current_value_instructions = ( 250 LoadConst, LoadClass, LoadFunction, LoadName, LoadTemp, 251 LoadAddress, LoadAddressContext, LoadAddressContextCond, 252 LoadAttr, LoadAttrIndex, LoadAttrIndexContextCond, 253 LoadCallable, LoadContext, LoadResult, 254 LoadException, MakeInstance, MakeFragment 255 ) 256 257 # vim: tabstop=4 expandtab shiftwidth=4