1 #!/usr/bin/env python 2 3 """ 4 RSVP instruction classes. 5 6 Copyright (C) 2007, 2008 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 Label 23 from micropython.data import Attr, Const, Instance 24 25 def raw(code): 26 new_code = [] 27 for item in code: 28 if isinstance(item, Attr): 29 new_code.append((item.context and item.context.location, item.value and item.value.location)) 30 else: 31 new_code.append(item) 32 return new_code 33 34 def name(attr): 35 if isinstance(attr, Attr): 36 return attr.name 37 else: 38 return attr 39 40 class Instruction: 41 42 "A generic instruction." 43 44 stack_storage = [] 45 stack_access = [] 46 47 def __init__(self, attr=None): 48 self.attr = attr 49 self.accesses = [op(-1 - n) for n, op in enumerate(self.stack_access)] 50 self.results = [op(n) for n, op in enumerate(self.stack_storage)] 51 52 def copy(self): 53 return self.__class__(self.attr) 54 55 def remove_results(self): 56 57 "Remove the stack side-effects for instructions replacing stack operations." 58 59 self.results = [] 60 61 def fix_stack(self, level): 62 63 """ 64 Use the given 'level' to fix the details of this instruction's internal 65 stack operations. 66 """ 67 68 effect = 0 69 for stack_op in self.accesses: 70 stack_op.fix_stack(level) 71 effect += stack_op.get_effect() 72 73 level += effect 74 for stack_op in self.results: 75 stack_op.fix_stack(level) 76 77 def get_effect(self): 78 effect = 0 79 for stack_op in self.accesses + self.results: 80 effect += stack_op.get_effect() 81 return effect 82 83 def show_stack_ops(self): 84 return "%s%s" % ( 85 self.accesses and (" <- %s" % self.accesses) or "", 86 self.results and (" -> %s" % self.results) or "" 87 ) 88 89 def __repr__(self): 90 if self.attr is not None: 91 return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_stack_ops()) 92 else: 93 return "%s()%s" % (self.__class__.__name__, self.show_stack_ops()) 94 95 class StackRelativeInstruction(Instruction): 96 97 "An instruction operating on the local value stack." 98 99 def __repr__(self): 100 return "%s(%r)%s" % (self.__class__.__name__, self.get_operand(), self.show_stack_ops()) 101 102 def get_operand(self): 103 return self.attr.position 104 105 SR = StackRelativeInstruction 106 107 class AddressRelativeInstruction(Instruction): 108 109 "An instruction accessing an object's attribute." 110 111 def __repr__(self): 112 position = self.get_operand() 113 if position is not None: 114 return "%s(%r)%s # %s" % (self.__class__.__name__, position, self.show_stack_ops(), name(self.attr)) 115 else: 116 return "%s(%r)%s" % (self.__class__.__name__, self.show_stack_ops(), name(self.attr)) 117 118 def get_operand(self): 119 return self.attr.position 120 121 AR = AddressRelativeInstruction 122 123 class AddressInstruction(Instruction): 124 125 "An instruction loading an address directly." 126 127 def __repr__(self): 128 location, position, result = self.get_operands() 129 if location is not None: 130 return "%s(%r)%s # %r, %r (%s)" % ( 131 self.__class__.__name__, result, self.show_stack_ops(), location, position, name(self.attr)) 132 elif result is not None: 133 return "%s(%r)%s # %s" % ( 134 self.__class__.__name__, result, self.show_stack_ops(), name(self.attr)) 135 else: 136 return "%s(...)%s # %s" % ( 137 self.__class__.__name__, self.show_stack_ops(), name(self.attr)) 138 139 def get_operands(self): 140 if isinstance(self.attr, Attr): 141 position = self.attr.position 142 location = self.attr.parent.location 143 144 # NOTE: Unpositioned attributes are handled here. 145 146 if location is not None and position is not None: 147 result = location + position + 1 148 else: 149 location = self.attr.parent.name 150 position = self.attr.name 151 result = None 152 return location, position, result 153 elif isinstance(self.attr, Label): 154 return None, None, self.attr.location 155 else: 156 return None, None, self.attr.location 157 158 def get_operand(self): 159 return self.get_operands()[-1] 160 161 Address = AddressInstruction 162 163 class ImmediateInstruction(Instruction): 164 165 "An instruction employing a constant." 166 167 def __repr__(self): 168 return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_stack_ops()) 169 170 def get_operand(self): 171 return self.attr 172 173 Immediate = ImmediateInstruction 174 175 # Internal stack and frame operations for instructions. 176 177 class StackOp: 178 179 "A generic stack operation." 180 181 def __init__(self, n): 182 self.n = n 183 self.level = None 184 185 def fix_stack(self, level): 186 self.level = self.n + level 187 188 def __repr__(self): 189 return "%s(%s)" % (self.__class__.__name__, self.level == 0 and "0" or self.level or self.n) 190 191 class StackPull(StackOp): 192 193 "Load a value from the stack." 194 195 def get_effect(self): 196 return -1 197 198 class StackPush(StackOp): 199 200 "Save a value onto the stack." 201 202 def get_effect(self): 203 return 1 204 205 class StackLoad(StackOp): 206 207 "Load a value from the stack." 208 209 def get_effect(self): 210 return 0 211 212 # Mix-in classes for stack effects. 213 214 class StackAdd: 215 216 """ 217 Indicate that the stack must grow to accommodate the result of this 218 instruction. 219 """ 220 221 stack_storage = [StackPush] 222 223 class StackRemove: 224 225 "Indicate that the stack must shrink as an effect of this instruction." 226 227 stack_access = [StackPull] 228 229 class StackRemove2: 230 231 "Indicate that the stack must shrink as an effect of this instruction." 232 233 stack_access = [StackPull, StackPull] 234 235 class StackReplace(StackAdd, StackRemove): 236 237 """ 238 Indicate that the stack remains at the same level due to the replacement of 239 the topmost element. 240 """ 241 242 pass 243 244 class StackInspect: 245 246 "Indicate that the stack is inspected but unchanged by this instruction." 247 248 stack_access = [StackLoad] 249 250 # Access to stored constant data. 251 252 class LoadConst(StackAdd, Address): "Load the constant, class, function, module from the specified location." 253 254 # Access within an invocation frame. 255 256 class LoadName(StackAdd, SR): "Load the object from the given local attribute/variable." 257 class StoreName(StackRemove, SR): "Store the object in the given local attribute/variable." 258 class LoadTemp(StackAdd, Immediate): "Load the object from the given temporary location." 259 class StoreTemp(StackRemove, Immediate): "Store the object in the given temporary location." 260 261 # Access to static data. 262 263 class LoadAddress(StackAdd, Address): "Load the object from the given fixed attribute address." 264 class StoreAddress(StackRemove, Address): "Store an object in the given fixed attribute address." 265 class LoadAddressContext(StackReplace, Address):"Load the object from the given fixed attribute address, changing the context." 266 class StoreAddressContext(StackRemove2, Address):"Store an object in the given fixed attribute address, changing the context." 267 class MakeObject(StackAdd, Instruction): "Make a new object. There isn't a complementary DropObject." 268 269 # Access to address-relative data. 270 271 class LoadAttr(StackReplace, AR): "Load the object from the given attribute." 272 class StoreAttr(StackRemove2, AR): "Store an object in the given attribute." 273 class LoadAttrIndex(StackReplace, Immediate): "Load the object for the attribute with the given index." 274 class StoreAttrIndex(StackRemove2, Immediate): "Store an object in the attribute with the given index." 275 276 # Access to invocation frames in preparation. 277 278 class MakeFrame(Instruction): "Make a new invocation frame." 279 class DropFrame(Instruction): "Drop an invocation frame." 280 class StoreFrame(StackRemove, Immediate): "Store an argument for the parameter with the given position." 281 class StoreFrameIndex(StackRemove, Immediate): "Store an argument for the parameter with the given index." 282 class LoadCallable(StackInspect, Instruction): "Load the target of an invocation." 283 class LoadContext(StackReplace, Instruction): "Load the context of an invocation." 284 class CheckFrame(Instruction): "Check the invocation frame and context for the target." 285 class CheckSelf(StackAdd, Instruction): "Check the first argument of an invocation against the target." 286 287 # Invocation-related instructions, using a special result "register". 288 289 class JumpWithFrame(StackRemove, Instruction): "Jump, adopting the invocation frame, to the callable found on the stack." 290 class Return(StackRemove, Instruction): "Return a value from a subprogram." 291 class LoadResult(StackAdd, Instruction): "Load a returned value." 292 293 # Branch-related instructions. 294 295 class Jump(Address): "Jump unconditionally." 296 class JumpIfFalse(StackRemove, Address): "Jump if the last evaluation gave a false result." 297 class JumpIfTrue(StackRemove, Address): "Jump if the last evaluation gave a true result." 298 299 # Exception-related instructions, using a special exception "register". 300 301 class LoadException(StackAdd, Instruction): "Load the raised exception." 302 class RaiseException(StackRemove, Instruction): "Raise an exception." 303 class CheckException(Instruction): "Check the raised exception against another." 304 305 # General instructions. 306 307 class TestIdentity(Instruction): "Test whether the two topmost stack values are identical." 308 class TestIdentityAddress(Address): "Test whether the topmost stack value is identical to the given address." 309 310 # vim: tabstop=4 expandtab shiftwidth=4