1.1 --- a/rsvp.py Fri Jul 10 00:12:09 2009 +0200
1.2 +++ b/rsvp.py Fri Jul 10 00:52:04 2009 +0200
1.3 @@ -79,13 +79,12 @@
1.4
1.5 "A really simple virtual processor."
1.6
1.7 - def __init__(self, memory, objlist, paramlist, true_constant, false_constant, pc=None, debug=0, abort_upon_exception=0):
1.8 + def __init__(self, memory, objlist, paramlist, pc=None, debug=0, abort_upon_exception=0):
1.9
1.10 """
1.11 Initialise the processor with a 'memory' (a list of values containing
1.12 instructions and data), the object and parameter lists 'objlist' and
1.13 - 'paramlist', the addresses 'true_constant' and 'false_constant', and the
1.14 - optional program counter 'pc'.
1.15 + 'paramlist', and the optional program counter 'pc'.
1.16 """
1.17
1.18 self.memory = memory
1.19 @@ -93,8 +92,7 @@
1.20 self._paramlist = paramlist
1.21 self.objlist = objlist.as_raw()
1.22 self.paramlist = paramlist.as_raw()
1.23 - self.true_constant = true_constant
1.24 - self.false_constant = false_constant
1.25 + self.library = None
1.26
1.27 self.pc = pc or 0
1.28 self.debug = debug
1.29 @@ -133,17 +131,6 @@
1.30 self.index_error = cls.location
1.31 self.index_error_instance = cls.instance_template_location
1.32
1.33 - # Native class constants.
1.34 -
1.35 - cls = self._get_class("__builtins__", "int")
1.36 - self.int_class = cls.location
1.37 - self.int_instance = cls.instance_template_location
1.38 - cls = self._get_class("__builtins__", "list")
1.39 - self.list_class = cls.location
1.40 - self.list_instance = cls.instance_template_location
1.41 - cls = self._get_class("__builtins__", "tuple")
1.42 - self.tuple_class = cls.location
1.43 -
1.44 # Debugging attributes.
1.45
1.46 self.breakpoints = set()
1.47 @@ -381,7 +368,7 @@
1.48 # of proper locations.
1.49
1.50 if isinstance(addr, str):
1.51 - handler = self.native_functions[addr](self)
1.52 + handler = self.library and self.library.native_functions[addr](self.library)
1.53 if handler is None:
1.54 return next
1.55 else:
1.56 @@ -536,7 +523,7 @@
1.57 def DropFrame(self):
1.58 self.local_sp_stack.pop()
1.59 frame = self.invocation_sp_stack.pop()
1.60 - self.frame_stack = self.frame_stack[:frame] # reset stack before call
1.61 + del self.frame_stack[frame:] # reset stack before call
1.62
1.63 def StoreFrame(self):
1.64 frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame
1.65 @@ -703,7 +690,7 @@
1.66
1.67 def PopHandler(self):
1.68 # Reduce the local frame pointer stack to refer to the handler's frame.
1.69 - self.local_sp_stack = self.local_sp_stack[:self.handler_local_sp_stack.pop()]
1.70 + del self.local_sp_stack[self.handler_local_sp_stack.pop():]
1.71 # Reduce the PC stack to discard all superfluous return addresses.
1.72 self.pc_stack = self.pc_stack[:self.handler_pc_stack.pop()]
1.73 self.handler_stack.pop()
1.74 @@ -771,7 +758,35 @@
1.75 else:
1.76 return context, ref
1.77
1.78 - # Native function implementations.
1.79 +class Library:
1.80 +
1.81 + "Native function implementations."
1.82 +
1.83 + def __init__(self, machine, true_constant, false_constant):
1.84 +
1.85 + """
1.86 + Initialise the library with the 'machine' and the addresses
1.87 + 'true_constant' and 'false_constant'.
1.88 + """
1.89 +
1.90 + self.machine = machine
1.91 + self.true_constant = true_constant
1.92 + self.false_constant = false_constant
1.93 +
1.94 + # Native class constants.
1.95 +
1.96 + cls = self.machine._get_class("__builtins__", "int")
1.97 + self.int_class = cls.location
1.98 + self.int_instance = cls.instance_template_location
1.99 + cls = self.machine._get_class("__builtins__", "list")
1.100 + self.list_class = cls.location
1.101 + self.list_instance = cls.instance_template_location
1.102 + cls = self.machine._get_class("__builtins__", "tuple")
1.103 + self.tuple_class = cls.location
1.104 +
1.105 + self.type_error_instance = self.machine.type_error_instance
1.106 + self.frame_stack = self.machine.frame_stack
1.107 + self.local_sp_stack = self.machine.local_sp_stack
1.108
1.109 def builtins_int_arithmetic_op(self, op):
1.110 frame = self.local_sp_stack[-1]
1.111 @@ -784,9 +799,9 @@
1.112 # Test operand suitability.
1.113 # NOTE: Support other types.
1.114
1.115 - if not (self._CheckInstance(left, self.int_class) and self._CheckInstance(right, self.int_class)):
1.116 - self.exception = self._MakeObject(2, self.type_error_instance)
1.117 - return self.RaiseException()
1.118 + if not (self.machine._CheckInstance(left, self.int_class) and self.machine._CheckInstance(right, self.int_class)):
1.119 + self.machine.exception = self.machine._MakeObject(2, self.type_error_instance)
1.120 + return self.machine.RaiseException()
1.121
1.122 # NOTE: Assume single location for data.
1.123
1.124 @@ -795,23 +810,23 @@
1.125
1.126 # Make a new object.
1.127
1.128 - addr = self._MakeObject(2, self.int_instance)
1.129 + addr = self.machine._MakeObject(2, self.int_instance)
1.130
1.131 # Store the result.
1.132 # NOTE: The data is considered ready to use.
1.133
1.134 - self.save(addr + 1, op(self.load(left_data), self.load(right_data)))
1.135 + self.machine.save(addr + 1, op(self.machine.load(left_data), self.machine.load(right_data)))
1.136
1.137 # Return the new object.
1.138 # Introduce object as context for the new object.
1.139
1.140 - self.result = addr, addr
1.141 + self.machine.result = addr, addr
1.142
1.143 def builtins_int_add(self):
1.144 - return self.builtins_int_arithmetic_op(operator.add)
1.145 + return self.machine.builtins_int_arithmetic_op(operator.add)
1.146
1.147 def builtins_int_sub(self):
1.148 - return self.builtins_int_arithmetic_op(operator.sub)
1.149 + return self.machine.builtins_int_arithmetic_op(operator.sub)
1.150
1.151 def builtins_int_bool(self):
1.152 frame = self.local_sp_stack[-1]
1.153 @@ -822,9 +837,9 @@
1.154
1.155 # Test operand suitability.
1.156
1.157 - if not self._CheckInstance(left, self.int_class):
1.158 - self.exception = self._MakeObject(2, self.type_error_instance)
1.159 - return self.RaiseException()
1.160 + if not self.machine._CheckInstance(left, self.int_class):
1.161 + self.machine.exception = self.machine._MakeObject(2, self.type_error_instance)
1.162 + return self.machine.RaiseException()
1.163
1.164 # NOTE: Assume single location for data.
1.165
1.166 @@ -833,10 +848,10 @@
1.167 # Test the data.
1.168 # NOTE: The data is considered ready to use.
1.169
1.170 - if self.load(left_data) != 0:
1.171 - self.result = self.true_constant, self.true_constant
1.172 + if self.machine.load(left_data) != 0:
1.173 + self.machine.result = self.true_constant, self.true_constant
1.174 else:
1.175 - self.result = self.false_constant, self.false_constant
1.176 + self.machine.result = self.false_constant, self.false_constant
1.177
1.178 def builtins_int_neg(self):
1.179 frame = self.local_sp_stack[-1]
1.180 @@ -847,9 +862,9 @@
1.181
1.182 # Test operand suitability.
1.183
1.184 - if not self._CheckInstance(left, self.int_class):
1.185 - self.exception = self._MakeObject(2, self.type_error_instance)
1.186 - return self.RaiseException()
1.187 + if not self.machine._CheckInstance(left, self.int_class):
1.188 + self.machine.exception = self.machine._MakeObject(2, self.type_error_instance)
1.189 + return self.machine.RaiseException()
1.190
1.191 # NOTE: Assume single location for data.
1.192
1.193 @@ -857,17 +872,17 @@
1.194
1.195 # Make a new object.
1.196
1.197 - addr = self._MakeObject(2, self.int_instance)
1.198 + addr = self.machine._MakeObject(2, self.int_instance)
1.199
1.200 # Store the result.
1.201 # NOTE: The data is considered ready to use.
1.202
1.203 - self.save(addr + 1, -self.load(left_data))
1.204 + self.machine.save(addr + 1, -self.machine.load(left_data))
1.205
1.206 # Return the new object.
1.207 # Introduce object as context for the new object.
1.208
1.209 - self.result = addr, addr
1.210 + self.machine.result = addr, addr
1.211
1.212 def builtins_int_op(self, op, true_if_incompatible):
1.213 frame = self.local_sp_stack[-1]
1.214 @@ -881,11 +896,11 @@
1.215 # NOTE: Support other types.
1.216 # NOTE: Handle comparisons of incompatible types more appropriately.
1.217
1.218 - if not (self._CheckInstance(left, self.int_class) and self._CheckInstance(right, self.int_class)):
1.219 + if not (self.machine._CheckInstance(left, self.int_class) and self.machine._CheckInstance(right, self.int_class)):
1.220 if true_if_incompatible:
1.221 - self.result = self.true_constant, self.true_constant
1.222 + self.machine.result = self.true_constant, self.true_constant
1.223 else:
1.224 - self.result = self.false_constant, self.false_constant
1.225 + self.machine.result = self.false_constant, self.false_constant
1.226 return
1.227
1.228 # NOTE: Assume single location for data.
1.229 @@ -896,28 +911,28 @@
1.230 # Test the data.
1.231 # NOTE: The data is considered ready to use.
1.232
1.233 - if op(self.load(left_data), self.load(right_data)):
1.234 - self.result = self.true_constant, self.true_constant
1.235 + if op(self.machine.load(left_data), self.machine.load(right_data)):
1.236 + self.machine.result = self.true_constant, self.true_constant
1.237 else:
1.238 - self.result = self.false_constant, self.false_constant
1.239 + self.machine.result = self.false_constant, self.false_constant
1.240
1.241 def builtins_int_lt(self):
1.242 - return self.builtins_int_op(operator.lt, 0)
1.243 + return self.machine.builtins_int_op(operator.lt, 0)
1.244
1.245 def builtins_int_le(self):
1.246 - return self.builtins_int_op(operator.le, 0)
1.247 + return self.machine.builtins_int_op(operator.le, 0)
1.248
1.249 def builtins_int_gt(self):
1.250 - return self.builtins_int_op(operator.gt, 0)
1.251 + return self.machine.builtins_int_op(operator.gt, 0)
1.252
1.253 def builtins_int_ge(self):
1.254 - return self.builtins_int_op(operator.ge, 0)
1.255 + return self.machine.builtins_int_op(operator.ge, 0)
1.256
1.257 def builtins_int_eq(self):
1.258 - return self.builtins_int_op(operator.eq, 0)
1.259 + return self.machine.builtins_int_op(operator.eq, 0)
1.260
1.261 def builtins_int_ne(self):
1.262 - return self.builtins_int_op(operator.ne, 1)
1.263 + return self.machine.builtins_int_op(operator.ne, 1)
1.264
1.265 def builtins_bool_bool(self):
1.266 frame = self.local_sp_stack[-1]
1.267 @@ -925,7 +940,7 @@
1.268 # Get operands addresses.
1.269
1.270 left_context, left = self.frame_stack[frame]
1.271 - self.result = left, left
1.272 + self.machine.result = left, left
1.273
1.274 def builtins_list_new(self):
1.275 frame = self.local_sp_stack[-1]
1.276 @@ -937,30 +952,30 @@
1.277
1.278 # Test operand suitability.
1.279
1.280 - if self._CheckInstance(args, self.list_class):
1.281 - _x, sequence = self.load(args + 1)
1.282 - header = self.load(sequence)
1.283 + if self.machine._CheckInstance(args, self.list_class):
1.284 + _x, sequence = self.machine.load(args + 1)
1.285 + header = self.machine.load(sequence)
1.286 size = header.occupied_size
1.287 - elif self._CheckInstance(args, self.tuple_class):
1.288 + elif self.machine._CheckInstance(args, self.tuple_class):
1.289 sequence = args
1.290 - header = self.load(sequence)
1.291 + header = self.machine.load(sequence)
1.292 size = header.size
1.293 else:
1.294 - self.exception = self._MakeObject(2, self.type_error_instance)
1.295 - return self.RaiseException()
1.296 + self.machine.exception = self.machine._MakeObject(2, self.type_error_instance)
1.297 + return self.machine.RaiseException()
1.298
1.299 # Copy the sequence contents.
1.300
1.301 - new_fragment = self._MakeFragment(size)
1.302 + new_fragment = self.machine._MakeFragment(size)
1.303 for i in range(1, size):
1.304 - self.save(new_fragment + i, self.load(sequence + i))
1.305 + self.machine.save(new_fragment + i, self.machine.load(sequence + i))
1.306
1.307 # Make the list instance.
1.308
1.309 - addr = self._MakeObject(2, self.list_instance)
1.310 - self.save(addr + 1, (None, new_fragment))
1.311 + addr = self.machine._MakeObject(2, self.list_instance)
1.312 + self.machine.save(addr + 1, (None, new_fragment))
1.313
1.314 - self.result = addr, addr
1.315 + self.machine.result = addr, addr
1.316
1.317 def builtins_list_getitem(self):
1.318 frame = self.local_sp_stack[-1]
1.319 @@ -976,27 +991,27 @@
1.320 # Get the fragment address.
1.321 # NOTE: Assume single location for header.
1.322
1.323 - _x, fragment = self.load(obj + 1)
1.324 + _x, fragment = self.machine.load(obj + 1)
1.325
1.326 # Get the fragment header.
1.327
1.328 - header = self.load(fragment)
1.329 + header = self.machine.load(fragment)
1.330 nelements = header.occupied_size - 1
1.331
1.332 # NOTE: Assume single location for data and header.
1.333
1.334 - item_pos = self.load(item + 1)
1.335 + item_pos = self.machine.load(item + 1)
1.336 if item_pos >= 0 and item_pos < nelements:
1.337 pass
1.338 elif item_pos < 0 and item_pos >= -nelements:
1.339 item_pos = nelements + item_pos
1.340 else:
1.341 - self.exception = self._MakeObject(2, self.index_error_instance)
1.342 - return self.RaiseException()
1.343 + self.machine.exception = self.machine._MakeObject(2, self.index_error_instance)
1.344 + return self.machine.RaiseException()
1.345
1.346 # NOTE: Assume single location for header.
1.347
1.348 - self.result = self.load(fragment + 1 + item_pos)
1.349 + self.machine.result = self.machine.load(fragment + 1 + item_pos)
1.350
1.351 def builtins_list_len(self):
1.352 frame = self.local_sp_stack[-1]
1.353 @@ -1008,26 +1023,26 @@
1.354 # Get the fragment address.
1.355 # NOTE: Assume single location for header.
1.356
1.357 - _x, fragment = self.load(obj + 1)
1.358 + _x, fragment = self.machine.load(obj + 1)
1.359
1.360 # Get the fragment header.
1.361
1.362 - header = self.load(fragment)
1.363 + header = self.machine.load(fragment)
1.364 nelements = header.occupied_size - 1
1.365
1.366 # Make a new object.
1.367
1.368 - addr = self._MakeObject(2, self.int_instance)
1.369 + addr = self.machine._MakeObject(2, self.int_instance)
1.370
1.371 # Store the result.
1.372 # NOTE: The data is considered ready to use.
1.373
1.374 - self.save(addr + 1, nelements)
1.375 + self.machine.save(addr + 1, nelements)
1.376
1.377 # Return the new object.
1.378 # Introduce object as context for the new object.
1.379
1.380 - self.result = addr, addr
1.381 + self.machine.result = addr, addr
1.382
1.383 def builtins_list_append(self):
1.384 frame = self.local_sp_stack[-1]
1.385 @@ -1043,35 +1058,35 @@
1.386 # Get the fragment address.
1.387 # NOTE: Assume single location for header.
1.388
1.389 - _x, fragment = self.load(obj + 1)
1.390 + _x, fragment = self.machine.load(obj + 1)
1.391
1.392 # Get the fragment header.
1.393
1.394 - header = self.load(fragment)
1.395 + header = self.machine.load(fragment)
1.396
1.397 # Attempt to add the reference.
1.398
1.399 if header.occupied_size < header.allocated_size:
1.400 - self.save(fragment + header.occupied_size, (arg_context, arg))
1.401 + self.machine.save(fragment + header.occupied_size, (arg_context, arg))
1.402 header.occupied_size += 1
1.403 else:
1.404
1.405 # Make a new fragment, maintaining more space than currently
1.406 # occupied in order to avoid reallocation.
1.407
1.408 - new_fragment = self._MakeFragment(header.allocated_size)
1.409 + new_fragment = self.machine._MakeFragment(header.allocated_size)
1.410
1.411 # Copy existing elements.
1.412
1.413 for i in range(1, header.allocated_size):
1.414 - self.save(new_fragment + i, self.load(fragment + i))
1.415 + self.machine.save(new_fragment + i, self.machine.load(fragment + i))
1.416
1.417 - self.save(new_fragment + header.allocated_size, (arg_context, arg))
1.418 + self.machine.save(new_fragment + header.allocated_size, (arg_context, arg))
1.419
1.420 # Set the new fragment in the object.
1.421 # NOTE: The old fragment could be deallocated.
1.422
1.423 - self.save(obj + 1, (None, new_fragment))
1.424 + self.machine.save(obj + 1, (None, new_fragment))
1.425
1.426 def builtins_object_init(self):
1.427 pass
1.428 @@ -1120,7 +1135,9 @@
1.429 importer = program.get_importer()
1.430 true_constant = importer.get_constant(True).location
1.431 false_constant = importer.get_constant(False).location
1.432 - rm = RSVPMachine(rc, objlist, paramlist, true_constant, false_constant, debug=debug, abort_upon_exception=abort_upon_exception)
1.433 + rm = RSVPMachine(rc, objlist, paramlist, debug=debug, abort_upon_exception=abort_upon_exception)
1.434 + library = Library(rm, true_constant, false_constant)
1.435 + rm.library = library
1.436 rm.pc = program.code_location
1.437 print "Returning program occupying %d locations." % len(rm.memory)
1.438 return rm