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_usage = 0 45 stack_access = 0 46 47 def __init__(self, attr=None): 48 self.attr = attr 49 self.operands = [StackLoad(-1 - n) for n in range(0, self.stack_access)] 50 51 def fix_stack(self, level): 52 for operand in self.operands: 53 operand.fix_stack(level) 54 55 def show_operands(self): 56 return self.operands and (" %s" % self.operands) or "" 57 58 def __repr__(self): 59 if self.attr is not None: 60 return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_operands()) 61 else: 62 return "%s()%s" % (self.__class__.__name__, self.show_operands()) 63 64 class StackRelativeInstruction(Instruction): 65 66 "An instruction operating on the local value stack." 67 68 def __repr__(self): 69 return "%s(%r)%s" % (self.__class__.__name__, self.get_operand(), self.show_operands()) 70 71 def get_operand(self): 72 return self.attr.position 73 74 SR = StackRelativeInstruction 75 76 class AddressRelativeInstruction(Instruction): 77 78 "An instruction accessing an object's attribute." 79 80 def __repr__(self): 81 position = self.get_operand() 82 if position is not None: 83 return "%s(%r)%s # %s" % (self.__class__.__name__, position, self.show_operands(), name(self.attr)) 84 else: 85 return "%s(%r)%s" % (self.__class__.__name__, self.show_operands(), name(self.attr)) 86 87 def get_operand(self): 88 return self.attr.position 89 90 AR = AddressRelativeInstruction 91 92 class AddressInstruction(Instruction): 93 94 "An instruction loading an address directly." 95 96 def __repr__(self): 97 location, position, result = self.get_operands() 98 if location is not None: 99 return "%s(%r)%s # %r, %r (%s)" % (self.__class__.__name__, result, self.show_operands(), location, position, name(self.attr)) 100 elif result is not None: 101 return "%s(%r)%s # %s" % (self.__class__.__name__, result, self.show_operands(), name(self.attr)) 102 else: 103 return "%s(...)%s # %s" % (self.__class__.__name__, self.show_operands(), name(self.attr)) 104 105 def get_operands(self): 106 if isinstance(self.attr, Attr): 107 position = self.attr.position 108 location = self.attr.parent.location 109 110 # NOTE: Unpositioned attributes are handled here. 111 112 if location is not None and position is not None: 113 result = location + position + 1 114 else: 115 location = self.attr.parent.name 116 position = self.attr.name 117 result = None 118 return location, position, result 119 elif isinstance(self.attr, Label): 120 return None, None, self.attr.location 121 else: 122 return None, None, self.attr.location 123 124 def get_operand(self): 125 return self.get_operands()[-1] 126 127 Address = AddressInstruction 128 129 class ImmediateInstruction(Instruction): 130 131 "An instruction employing a constant." 132 133 def __repr__(self): 134 return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_operands()) 135 136 def get_operand(self): 137 return self.attr 138 139 Immediate = ImmediateInstruction 140 141 # Mix-in classes for stack effects. 142 143 class StackAdd: 144 145 """ 146 Indicate that the stack must grow to accommodate the result of this 147 instruction. 148 """ 149 150 stack_usage = 1 151 152 class StackRemove: 153 154 "Indicate that the stack must shrink as an effect of this instruction." 155 156 stack_usage = -1 157 stack_access = 1 158 159 class StackRemove2: 160 161 "Indicate that the stack must shrink as an effect of this instruction." 162 163 stack_usage = -2 164 stack_access = 2 165 166 # Instructions operating on the value stack. 167 168 class Duplicate(StackAdd, Instruction): "Duplicate the top of the stack." 169 class ResetStack(Instruction): "Pop entries from the stack." 170 171 # Access to stored constant data. 172 173 class LoadConst(StackAdd, Address): "Load the constant, class, function, module from the specified location." 174 175 # Access within an invocation frame. 176 177 class LoadName(StackAdd, SR): "Load the object from the given local attribute/variable." 178 class StoreName(StackRemove, SR): "Store the object in the given local attribute/variable." 179 class LoadTemp(Immediate): "Load the object from the given temporary location." 180 class StoreTemp(StackRemove, Immediate): "Store the object in the given temporary location." 181 182 # Access to address-relative data. 183 184 class MakeObject(StackAdd, Instruction): "Make a new object. There isn't a complementary DropObject." 185 class LoadAttr(AR): "Load the object from the given attribute." 186 class StoreAttr(StackRemove2, AR): "Store an object in the given attribute." 187 class LoadAttrIndex(Immediate): "Load the object for the attribute with the given index." 188 class StoreAttrIndex(StackRemove2, Immediate): "Store an object in the attribute with the given index." 189 class LoadAddress(StackAdd, Address): "Load the object from the given fixed attribute address." 190 class StoreAddress(StackRemove, Address): "Store an object in the given fixed attribute address." 191 192 # Access to invocation frames in preparation. 193 194 class MakeFrame(Instruction): "Make a new invocation frame." 195 class ReserveFrame(Immediate): "Reserve the given number of entries for the invocation frame." 196 class DropFrame(Instruction): "Drop an invocation frame." 197 class StoreFrame(StackRemove, Immediate): "Store an argument at the given frame location." 198 class StoreFrameIndex(StackRemove, Immediate): "Store an argument for the parameter with the given index." 199 class CheckFrame(Instruction): "Check the invocation frame for the target." 200 class JumpWithFrame(Instruction): "Jump, adopting the invocation frame, to the callable found on the stack." 201 202 # Invocation-related instructions. 203 204 class Jump(Address): "Jump unconditionally." 205 class JumpIfFalse(Address): "Jump if the last evaluation gave a false result." 206 class JumpIfTrue(Address): "Jump if the last evaluation gave a true result." 207 class LoadCallable(Instruction): "Load the target of an invocation." 208 class LoadContext(Instruction): "Load the context of an invocation." 209 class CheckContext(Instruction): """Check the context of an invocation against the target, 210 potentially discarding the context.""" 211 class CheckSelf(Instruction): "Check the first argument of an invocation against the target." 212 class RaiseException(Instruction): "Raise an exception." 213 class Return(Instruction): "Return a value from a subprogram." 214 class CheckException(Instruction): "Check the raised exception against another." 215 216 # General instructions. 217 218 class TestIdentity(Instruction): "Test whether the two topmost stack values are identical." 219 class TestIdentityAddress(Address): "Test whether the topmost stack value is identical to the given address." 220 221 # Internal stack operations for instructions. 222 223 class StackLoad: 224 225 "Load a value from the stack." 226 227 def __init__(self, n): 228 self.n = n 229 self.level = None 230 231 def fix_stack(self, level): 232 self.level = self.n + level 233 234 def __repr__(self): 235 return "%s(%r)" % (self.__class__.__name__, self.n) 236 237 # vim: tabstop=4 expandtab shiftwidth=4