paul@17 | 1 | #!/usr/bin/env python |
paul@17 | 2 | |
paul@17 | 3 | """ |
paul@265 | 4 | RSVP instruction and serialisation classes. |
paul@17 | 5 | |
paul@180 | 6 | Copyright (C) 2007, 2008, 2009 Paul Boddie <paul@boddie.org.uk> |
paul@17 | 7 | |
paul@17 | 8 | This program is free software; you can redistribute it and/or modify it under |
paul@17 | 9 | the terms of the GNU General Public License as published by the Free Software |
paul@17 | 10 | Foundation; either version 3 of the License, or (at your option) any later |
paul@17 | 11 | version. |
paul@17 | 12 | |
paul@17 | 13 | This program is distributed in the hope that it will be useful, but WITHOUT |
paul@17 | 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
paul@17 | 15 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
paul@17 | 16 | details. |
paul@17 | 17 | |
paul@17 | 18 | You should have received a copy of the GNU General Public License along with |
paul@17 | 19 | this program. If not, see <http://www.gnu.org/licenses/>. |
paul@17 | 20 | """ |
paul@17 | 21 | |
paul@265 | 22 | from micropython.data import Attr, Const, Class, Function, Module |
paul@265 | 23 | from micropython.program import Block, DataObject, DataValue |
paul@165 | 24 | |
paul@91 | 25 | def name(attr): |
paul@91 | 26 | if isinstance(attr, Attr): |
paul@107 | 27 | return attr.name or "<unnamed>" |
paul@181 | 28 | elif isinstance(attr, (Block, Const)): |
paul@180 | 29 | return attr |
paul@91 | 30 | else: |
paul@180 | 31 | return attr.full_name() or "<unnamed>" |
paul@91 | 32 | |
paul@265 | 33 | # Serialisation-related classes. |
paul@265 | 34 | |
paul@265 | 35 | class RSVPObject: |
paul@265 | 36 | |
paul@265 | 37 | "A generic data object wrapper." |
paul@265 | 38 | |
paul@265 | 39 | def __init__(self, item): |
paul@265 | 40 | self.item = item |
paul@265 | 41 | |
paul@265 | 42 | def set_location(self, location, with_builtins): |
paul@265 | 43 | self.item.location = location |
paul@265 | 44 | return location + 1 |
paul@265 | 45 | |
paul@265 | 46 | def finalise_location(self, with_builtins): |
paul@265 | 47 | pass |
paul@265 | 48 | |
paul@265 | 49 | def _finalise_location(self, with_builtins): |
paul@265 | 50 | |
paul@265 | 51 | """ |
paul@265 | 52 | Set the code body location for items now that the code blocks have been |
paul@265 | 53 | positioned. |
paul@265 | 54 | """ |
paul@265 | 55 | |
paul@265 | 56 | item = self.item |
paul@265 | 57 | |
paul@265 | 58 | if not with_builtins and item.module.name == "__builtins__" and item.astnode.doc is None: |
paul@265 | 59 | item.code_body_location = item.full_name() |
paul@265 | 60 | else: |
paul@265 | 61 | item.code_body_location = item.get_body_block().location |
paul@265 | 62 | |
paul@265 | 63 | class RSVPAttr(RSVPObject): |
paul@265 | 64 | |
paul@265 | 65 | "A wrapper for attributes/values." |
paul@265 | 66 | |
paul@265 | 67 | def as_raw(self, objtable, paramtable, with_builtins): |
paul@265 | 68 | item = self.item |
paul@265 | 69 | return [ |
paul@265 | 70 | DataValue( |
paul@265 | 71 | item.get_context() and item.get_context().location, |
paul@265 | 72 | item.get_value() and item.get_value().location |
paul@265 | 73 | ) |
paul@265 | 74 | ] |
paul@265 | 75 | |
paul@265 | 76 | class RSVPBlock(RSVPObject): |
paul@265 | 77 | |
paul@265 | 78 | "A wrapper for blocks." |
paul@265 | 79 | |
paul@265 | 80 | def set_location(self, location, with_builtins): |
paul@265 | 81 | item = self.item |
paul@265 | 82 | item.location = location |
paul@265 | 83 | return location + len(item.code) |
paul@265 | 84 | |
paul@265 | 85 | def as_raw(self, objtable, paramtable, with_builtins): |
paul@265 | 86 | return self.item.code |
paul@265 | 87 | |
paul@265 | 88 | class RSVPClass(RSVPObject): |
paul@265 | 89 | |
paul@265 | 90 | "A wrapper for classes." |
paul@265 | 91 | |
paul@265 | 92 | def set_location(self, location, with_builtins): |
paul@265 | 93 | self.item.instance_template_location = location |
paul@265 | 94 | return RSVPObject.set_location(self, location + 1, with_builtins) |
paul@265 | 95 | |
paul@265 | 96 | def finalise_location(self, with_builtins): |
paul@265 | 97 | self._finalise_location(with_builtins) |
paul@265 | 98 | |
paul@265 | 99 | def as_raw(self, objtable, paramtable, with_builtins): |
paul@265 | 100 | item = self.item |
paul@265 | 101 | classcode = objtable.as_list().get_code(item.full_name()) |
paul@265 | 102 | attrcode = objtable.get_index(item.full_name()) |
paul@265 | 103 | |
paul@265 | 104 | # Include a template of an instance for use when instantiating classes. |
paul@265 | 105 | |
paul@265 | 106 | call_method = item.all_class_attributes().get("__call__") |
paul@265 | 107 | call_method_value = call_method and call_method.get_value() |
paul@265 | 108 | call_method_code_location = call_method_value and call_method_value.code_location |
paul@265 | 109 | call_method_funccode = call_method_value and paramtable.as_list().get_code(call_method_value.full_name()) |
paul@265 | 110 | |
paul@265 | 111 | instantiator_funccode = paramtable.as_list().get_code(item.get_instantiator().full_name()) |
paul@265 | 112 | |
paul@265 | 113 | # NOTE: The instantiator code is the first block of the class. |
paul@265 | 114 | |
paul@265 | 115 | with_instantiator = with_builtins or item.module.name != "__builtins__" or item.astnode.doc is not None |
paul@265 | 116 | |
paul@265 | 117 | if not with_instantiator: |
paul@265 | 118 | instantiator_code_location = item.full_name() |
paul@265 | 119 | else: |
paul@265 | 120 | instantiator_code_location = item.get_instantiator().blocks[0].location |
paul@265 | 121 | |
paul@265 | 122 | return [ |
paul@265 | 123 | |
paul@265 | 124 | # Template instance... |
paul@265 | 125 | |
paul@265 | 126 | DataObject( |
paul@265 | 127 | classcode, |
paul@265 | 128 | attrcode, # is instance |
paul@265 | 129 | call_method_code_location, |
paul@265 | 130 | item.full_name(), |
paul@265 | 131 | len(item.instance_attributes()) + 1, # size |
paul@265 | 132 | call_method_funccode # funccode |
paul@265 | 133 | ), |
paul@265 | 134 | |
paul@265 | 135 | # Class... |
paul@265 | 136 | |
paul@265 | 137 | DataObject( |
paul@265 | 138 | classcode, |
paul@265 | 139 | None, # is not instance |
paul@265 | 140 | instantiator_code_location, |
paul@265 | 141 | item.full_name(), |
paul@265 | 142 | len(item.class_attributes()) + 1, # size |
paul@265 | 143 | instantiator_funccode # funccode |
paul@265 | 144 | ) |
paul@265 | 145 | ] |
paul@265 | 146 | |
paul@265 | 147 | class RSVPConst(RSVPObject): |
paul@265 | 148 | |
paul@265 | 149 | "A wrapper for constants." |
paul@265 | 150 | |
paul@265 | 151 | def set_location(self, location, with_builtins): |
paul@265 | 152 | location = RSVPObject.set_location(self, location, with_builtins) |
paul@265 | 153 | return location + len(self.raw_data()) |
paul@265 | 154 | |
paul@265 | 155 | def as_raw(self, objtable, paramtable, with_builtins): |
paul@265 | 156 | item = self.item |
paul@265 | 157 | # NOTE: Need class details! |
paul@265 | 158 | return [ |
paul@265 | 159 | DataObject( |
paul@265 | 160 | objtable.as_list().get_code(item.value_type_name()), |
paul@265 | 161 | objtable.get_index(item.value_type_name()), # is instance |
paul@265 | 162 | None, |
paul@265 | 163 | item.value_type_name(), |
paul@265 | 164 | 1 # size |
paul@265 | 165 | ) |
paul@265 | 166 | ] + self.raw_data() |
paul@265 | 167 | |
paul@265 | 168 | def raw_data(self): |
paul@265 | 169 | item = self.item |
paul@265 | 170 | value = item.get_value() |
paul@265 | 171 | # NOTE: Start simple and use single entries for most types. |
paul@265 | 172 | if item.value_type_name() in ("__builtins__.tuple", "__builtins__.list"): |
paul@265 | 173 | return [len(value)] + list(value) |
paul@265 | 174 | else: |
paul@265 | 175 | return [value] |
paul@265 | 176 | |
paul@265 | 177 | class RSVPFunction(RSVPObject): |
paul@265 | 178 | |
paul@265 | 179 | "A wrapper for functions." |
paul@265 | 180 | |
paul@265 | 181 | def set_location(self, location, with_builtins): |
paul@265 | 182 | item = self.item |
paul@265 | 183 | location = RSVPObject.set_location(self, location, with_builtins) |
paul@265 | 184 | |
paul@265 | 185 | # Set the code location only where the code has been |
paul@265 | 186 | # generated. |
paul@265 | 187 | |
paul@265 | 188 | if not with_builtins and item.module.name == "__builtins__" and item.astnode.doc is None: |
paul@265 | 189 | item.code_location = item.full_name() |
paul@265 | 190 | |
paul@265 | 191 | # Skip any defaults for named functions. |
paul@265 | 192 | |
paul@265 | 193 | elif item.name is not None: |
paul@265 | 194 | item.code_location = location + len(item.defaults) |
paul@265 | 195 | |
paul@265 | 196 | # Skip any defaults for lambda functions. |
paul@265 | 197 | |
paul@265 | 198 | else: |
paul@265 | 199 | item.code_location = location |
paul@265 | 200 | |
paul@265 | 201 | return location |
paul@265 | 202 | |
paul@265 | 203 | def finalise_location(self, with_builtins): |
paul@265 | 204 | self._finalise_location(with_builtins) |
paul@265 | 205 | |
paul@265 | 206 | def as_raw(self, objtable, paramtable, with_builtins): |
paul@265 | 207 | item = self.item |
paul@265 | 208 | # NOTE: Need class and parameter details! Should arguably be an instance of types.FunctionType. |
paul@265 | 209 | return [ |
paul@265 | 210 | DataObject( |
paul@265 | 211 | objtable.as_list().get_code("__builtins__.function"), |
paul@265 | 212 | objtable.get_index("__builtins__.function"), # is instance |
paul@265 | 213 | item.code_location, |
paul@265 | 214 | "__builtins__.function", |
paul@265 | 215 | len(item.defaults) + 1, # size (not accurate for lambda functions before instantiation) |
paul@265 | 216 | paramtable.as_list().get_code(item.full_name()) # funccode |
paul@265 | 217 | ) |
paul@265 | 218 | ] |
paul@265 | 219 | |
paul@265 | 220 | class RSVPModule(RSVPObject): |
paul@265 | 221 | |
paul@265 | 222 | "A wrapper for modules." |
paul@265 | 223 | |
paul@265 | 224 | def as_raw(self, objtable, paramtable, with_builtins): |
paul@265 | 225 | item = self.item |
paul@265 | 226 | return [ |
paul@265 | 227 | DataObject( |
paul@265 | 228 | objtable.as_list().get_code(item.full_name()), |
paul@265 | 229 | None, # modules treated like classes |
paul@265 | 230 | None, |
paul@265 | 231 | item.full_name(), |
paul@265 | 232 | len(item.module_attributes()) + 1 # size |
paul@265 | 233 | ) |
paul@265 | 234 | ] |
paul@265 | 235 | |
paul@265 | 236 | # Serialisation-related data and functions. |
paul@265 | 237 | |
paul@265 | 238 | def get_object(item): |
paul@265 | 239 | if isinstance(item, Attr): |
paul@265 | 240 | cls = RSVPAttr |
paul@265 | 241 | elif isinstance(item, Block): |
paul@265 | 242 | cls = RSVPBlock |
paul@265 | 243 | elif isinstance(item, Class): |
paul@265 | 244 | cls = RSVPClass |
paul@265 | 245 | elif isinstance(item, Const): |
paul@265 | 246 | cls = RSVPConst |
paul@265 | 247 | elif isinstance(item, Function): |
paul@265 | 248 | cls = RSVPFunction |
paul@265 | 249 | elif isinstance(item, Module): |
paul@265 | 250 | cls = RSVPModule |
paul@265 | 251 | else: |
paul@265 | 252 | cls = None |
paul@265 | 253 | |
paul@265 | 254 | if cls is not None: |
paul@265 | 255 | return cls(item) |
paul@265 | 256 | else: |
paul@265 | 257 | return None |
paul@265 | 258 | |
paul@265 | 259 | # Instruction-related classes. |
paul@265 | 260 | |
paul@17 | 261 | class Instruction: |
paul@17 | 262 | |
paul@17 | 263 | "A generic instruction." |
paul@17 | 264 | |
paul@87 | 265 | def __init__(self, attr=None): |
paul@17 | 266 | self.attr = attr |
paul@103 | 267 | self.input = None |
paul@103 | 268 | self.source = None # for storage instructions |
paul@95 | 269 | |
paul@95 | 270 | def copy(self): |
paul@95 | 271 | return self.__class__(self.attr) |
paul@95 | 272 | |
paul@101 | 273 | def __repr__(self): |
paul@101 | 274 | if self.attr is not None: |
paul@103 | 275 | return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_input()) |
paul@101 | 276 | else: |
paul@103 | 277 | return "%s()%s" % (self.__class__.__name__, self.show_input()) |
paul@103 | 278 | |
paul@103 | 279 | def show_input(self): |
paul@103 | 280 | if self.input is not None: |
paul@103 | 281 | if self.source is not None: |
paul@103 | 282 | return " <- (%r, %r)" % (self.input, self.source) |
paul@103 | 283 | else: |
paul@103 | 284 | return " <- %r" % self.input |
paul@104 | 285 | elif self.source is not None: |
paul@104 | 286 | return " <-- %r" % self.source |
paul@103 | 287 | else: |
paul@103 | 288 | return "" |
paul@95 | 289 | |
paul@137 | 290 | def get_operand(self): |
paul@137 | 291 | return None |
paul@137 | 292 | |
paul@101 | 293 | class FrameRelativeInstruction(Instruction): |
paul@95 | 294 | |
paul@101 | 295 | "An instruction operating on the current frame." |
paul@17 | 296 | |
paul@17 | 297 | def __repr__(self): |
paul@103 | 298 | return "%s(%r)%s" % (self.__class__.__name__, self.get_operand(), self.show_input()) |
paul@90 | 299 | |
paul@90 | 300 | def get_operand(self): |
paul@90 | 301 | return self.attr.position |
paul@55 | 302 | |
paul@101 | 303 | FR = FrameRelativeInstruction |
paul@55 | 304 | |
paul@55 | 305 | class AddressRelativeInstruction(Instruction): |
paul@55 | 306 | |
paul@55 | 307 | "An instruction accessing an object's attribute." |
paul@55 | 308 | |
paul@55 | 309 | def __repr__(self): |
paul@91 | 310 | position = self.get_operand() |
paul@91 | 311 | if position is not None: |
paul@103 | 312 | return "%s(%r)%s # %s" % (self.__class__.__name__, position, self.show_input(), name(self.attr)) |
paul@91 | 313 | else: |
paul@103 | 314 | return "%s(%r)%s" % (self.__class__.__name__, name(self.attr), self.show_input()) |
paul@90 | 315 | |
paul@90 | 316 | def get_operand(self): |
paul@90 | 317 | return self.attr.position |
paul@82 | 318 | |
paul@82 | 319 | AR = AddressRelativeInstruction |
paul@82 | 320 | |
paul@82 | 321 | class AddressInstruction(Instruction): |
paul@82 | 322 | |
paul@82 | 323 | "An instruction loading an address directly." |
paul@82 | 324 | |
paul@82 | 325 | def __repr__(self): |
paul@90 | 326 | location, position, result = self.get_operands() |
paul@90 | 327 | if location is not None: |
paul@103 | 328 | return "%s(%r)%s # %r, %r (%s)" % ( |
paul@103 | 329 | self.__class__.__name__, result, self.show_input(), location, position, name(self.attr)) |
paul@91 | 330 | elif result is not None: |
paul@103 | 331 | return "%s(%r)%s # %s" % ( |
paul@103 | 332 | self.__class__.__name__, result, self.show_input(), name(self.attr)) |
paul@90 | 333 | else: |
paul@103 | 334 | return "%s(...)%s # %s" % ( |
paul@103 | 335 | self.__class__.__name__, self.show_input(), name(self.attr)) |
paul@90 | 336 | |
paul@90 | 337 | def get_operands(self): |
paul@82 | 338 | if isinstance(self.attr, Attr): |
paul@82 | 339 | position = self.attr.position |
paul@55 | 340 | location = self.attr.parent.location |
paul@56 | 341 | |
paul@56 | 342 | # NOTE: Unpositioned attributes are handled here. |
paul@56 | 343 | |
paul@56 | 344 | if location is not None and position is not None: |
paul@56 | 345 | result = location + position + 1 |
paul@56 | 346 | else: |
paul@56 | 347 | location = self.attr.parent.name |
paul@56 | 348 | position = self.attr.name |
paul@56 | 349 | result = None |
paul@90 | 350 | return location, position, result |
paul@82 | 351 | else: |
paul@90 | 352 | return None, None, self.attr.location |
paul@90 | 353 | |
paul@90 | 354 | def get_operand(self): |
paul@90 | 355 | return self.get_operands()[-1] |
paul@55 | 356 | |
paul@70 | 357 | Address = AddressInstruction |
paul@70 | 358 | |
paul@215 | 359 | class TargetInstruction(Instruction): |
paul@215 | 360 | |
paul@215 | 361 | "An instruction loading the address of an invocation target." |
paul@215 | 362 | |
paul@215 | 363 | def __repr__(self): |
paul@215 | 364 | return "%s(%r) # %r" % (self.__class__.__name__, self.get_operand(), name(self.attr)) |
paul@215 | 365 | |
paul@215 | 366 | def get_operand(self): |
paul@240 | 367 | return self.attr.code_body_location |
paul@215 | 368 | |
paul@215 | 369 | Target = TargetInstruction |
paul@215 | 370 | |
paul@70 | 371 | class ImmediateInstruction(Instruction): |
paul@70 | 372 | |
paul@70 | 373 | "An instruction employing a constant." |
paul@70 | 374 | |
paul@70 | 375 | def __repr__(self): |
paul@103 | 376 | return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_input()) |
paul@70 | 377 | |
paul@90 | 378 | def get_operand(self): |
paul@90 | 379 | return self.attr |
paul@90 | 380 | |
paul@55 | 381 | Immediate = ImmediateInstruction |
paul@55 | 382 | |
paul@86 | 383 | # Access to stored constant data. |
paul@86 | 384 | |
paul@237 | 385 | class LoadConst(Address): "Load the constant or module from the specified location." |
paul@237 | 386 | class LoadClass(Address): "Load the class from the specified location." |
paul@223 | 387 | class LoadFunction(Address): "Load the function from the specified location." |
paul@86 | 388 | |
paul@21 | 389 | # Access within an invocation frame. |
paul@21 | 390 | |
paul@105 | 391 | class LoadName(FR): "Load the current value from the given local attribute/variable." |
paul@105 | 392 | class StoreName(FR): "Store the source value into the given local attribute/variable." |
paul@105 | 393 | class LoadTemp(Immediate): "Load the current value from the given temporary location." |
paul@105 | 394 | class StoreTemp(Immediate): "Store the current value into the given temporary location." |
paul@21 | 395 | |
paul@98 | 396 | # Access to static data. |
paul@98 | 397 | |
paul@105 | 398 | class LoadAddress(Address): "Load the current value from the given fixed attribute address." |
paul@105 | 399 | class StoreAddress(Address): "Store the source value into the given fixed attribute address." |
paul@223 | 400 | class LoadAddressContext(Address): "Load the current value from the given fixed attribute address, using the current value as context." |
paul@223 | 401 | class StoreAddressContext(Address): "Store the current value into the given fixed attribute address, using the current value as context." |
paul@194 | 402 | class LoadAddressContextCond(Address): |
paul@223 | 403 | """Load the current value from the given fixed attribute address, only using the current value as |
paul@194 | 404 | context if the attribute is compatible.""" |
paul@246 | 405 | class MakeInstance(Immediate): "Make a new instance using the current value as a reference to a template." |
paul@246 | 406 | class MakeFragment(Immediate): "Make a new list fragment." |
paul@98 | 407 | |
paul@234 | 408 | # Access to address-relative data. (LoadAttrIndexContext not defined.) |
paul@21 | 409 | |
paul@105 | 410 | class LoadAttr(AR): "Load into the current value the given attribute of the object referenced by the current value." |
paul@105 | 411 | class StoreAttr(AR): "Store the source value into the given attribute of the object referenced by the current value." |
paul@105 | 412 | class LoadAttrIndex(Immediate): "Load into the current value the attribute of the current value with the given index." |
paul@190 | 413 | class StoreAttrIndex(Immediate): "Store the source value into the attribute of the current value with the given index." |
paul@194 | 414 | class LoadAttrIndexContextCond(Immediate): |
paul@194 | 415 | """Load into the current value the attribute of the current value with the given index, only making the |
paul@194 | 416 | current value the context if the attribute is compatible.""" |
paul@21 | 417 | |
paul@138 | 418 | # Access to object details. |
paul@138 | 419 | |
paul@138 | 420 | class LoadCallable(Instruction): "Load the target of an invocation." |
paul@138 | 421 | class StoreCallable(Instruction): "Store the source value into the object referenced by the current value." |
paul@138 | 422 | |
paul@21 | 423 | # Access to invocation frames in preparation. |
paul@21 | 424 | |
paul@117 | 425 | class MakeFrame(Immediate): "Make a new invocation frame." |
paul@234 | 426 | class AdjustFrame(Immediate): "Adjust the current invocation frame for corrected invocations." |
paul@101 | 427 | class DropFrame(Instruction): "Drop an invocation frame." |
paul@105 | 428 | class StoreFrame(Immediate): "Store the current value as an argument for the parameter with the given position." |
paul@190 | 429 | class StoreFrameIndex(Immediate): "Store the source value as an argument of the current value for the parameter with the given index." |
paul@101 | 430 | class LoadContext(Instruction): "Load the context of an invocation." |
paul@215 | 431 | |
paul@234 | 432 | # Context-related tests. |
paul@215 | 433 | |
paul@222 | 434 | class CheckContext(Instruction): "Check to see if the context is valid." |
paul@234 | 435 | class CheckClass(Instruction): "Check the current value to determine whether it is a class." |
paul@234 | 436 | class CheckSelf(Instruction): "Check the first argument of an invocation against the target." |
paul@234 | 437 | |
paul@234 | 438 | # Access to frames upon invocation. |
paul@234 | 439 | |
paul@234 | 440 | class CheckFrame(Immediate): "Check the frame for the correct number of arguments." |
paul@256 | 441 | class CheckExtra(Immediate): "Ensure that the frame can provide extra arguments." |
paul@215 | 442 | class FillDefaults(Immediate): "Fill frame positions with defaults, if appropriate." |
paul@234 | 443 | class ExtendFrame(Immediate): "Extend the current frame for temporary storage use." |
paul@255 | 444 | class CopyExtra(Immediate): "Copy extra arguments into a separate sequence, starting from the given position." |
paul@97 | 445 | |
paul@97 | 446 | # Invocation-related instructions, using a special result "register". |
paul@97 | 447 | |
paul@230 | 448 | class JumpInFrame(Instruction): "Jump, using the current locals, to the current callable." |
paul@137 | 449 | class JumpWithFrame(Instruction): "Jump, adopting the invocation frame, to the current callable." |
paul@215 | 450 | class JumpWithFrameDirect(Target): "Jump to the specified address, adopting the invocation frame." |
paul@104 | 451 | class Return(Instruction): "Return from a subprogram." |
paul@105 | 452 | class LoadResult(Instruction): "Load into the current value a returned value." |
paul@105 | 453 | class StoreResult(Instruction): "Store the current value as a value to be returned." |
paul@21 | 454 | |
paul@97 | 455 | # Branch-related instructions. |
paul@21 | 456 | |
paul@101 | 457 | class Jump(Address): "Jump unconditionally." |
paul@101 | 458 | class JumpIfFalse(Address): "Jump if the last evaluation gave a false result." |
paul@101 | 459 | class JumpIfTrue(Address): "Jump if the last evaluation gave a true result." |
paul@97 | 460 | |
paul@97 | 461 | # Exception-related instructions, using a special exception "register". |
paul@97 | 462 | |
paul@101 | 463 | class LoadException(Instruction): "Load the raised exception." |
paul@105 | 464 | class StoreException(Instruction): "Store the current object in the exception register." |
paul@232 | 465 | class ClearException(Instruction): "Reset the exception register." |
paul@105 | 466 | class RaiseException(Instruction): "Raise an exception, jumping to the active handler." |
paul@102 | 467 | class PushHandler(Address): "Push an exception handler onto the handler stack." |
paul@103 | 468 | class PopHandler(Instruction): "Pop an exception handler from the handler stack." |
paul@105 | 469 | class CheckException(Instruction): "Check the raised exception against another." |
paul@17 | 470 | |
paul@116 | 471 | # Test instructions, operating on the boolean status register. |
paul@76 | 472 | |
paul@116 | 473 | class TestIdentity(Instruction): "Test whether the current value is identical to the source value, setting the boolean status." |
paul@116 | 474 | class TestIdentityAddress(Address): "Test whether the current value is identical to the given address, setting the boolean status." |
paul@116 | 475 | class InvertBoolean(Instruction): "Invert the boolean status." |
paul@76 | 476 | |
paul@234 | 477 | # Instructions which affect the current value. (LoadAttrIndexContext not defined.) |
paul@140 | 478 | |
paul@140 | 479 | current_value_instructions = ( |
paul@237 | 480 | LoadConst, LoadClass, LoadFunction, LoadName, LoadTemp, |
paul@194 | 481 | LoadAddress, LoadAddressContext, LoadAddressContextCond, |
paul@226 | 482 | LoadAttr, LoadAttrIndex, LoadAttrIndexContextCond, |
paul@194 | 483 | LoadCallable, LoadContext, LoadResult, |
paul@255 | 484 | LoadException, MakeInstance, MakeFragment, |
paul@255 | 485 | CopyExtra |
paul@140 | 486 | ) |
paul@140 | 487 | |
paul@256 | 488 | # Instructions which use the current value. |
paul@256 | 489 | |
paul@256 | 490 | simple_input_user_instructions = ( |
paul@256 | 491 | StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored |
paul@256 | 492 | LoadAddressContext, LoadAddressContextCond, # as the object being referenced |
paul@256 | 493 | LoadAttr, LoadAttrIndex, # LoadAttrIndexContext, # as the object being referenced |
paul@256 | 494 | LoadAttrIndexContextCond, # as the object being referenced |
paul@256 | 495 | StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced |
paul@256 | 496 | StoreFrameIndex, # as the object being referenced |
paul@256 | 497 | StoreAddressContext, # as the context |
paul@256 | 498 | LoadCallable, |
paul@256 | 499 | TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands |
paul@256 | 500 | CheckException, CheckFrame, FillDefaults, |
paul@256 | 501 | MakeInstance, |
paul@256 | 502 | CheckContext, CheckClass, |
paul@256 | 503 | LoadContext # as the object providing the result |
paul@256 | 504 | ) |
paul@256 | 505 | |
paul@17 | 506 | # vim: tabstop=4 expandtab shiftwidth=4 |