# HG changeset patch # User Paul Boddie # Date 1247179924 -7200 # Node ID 26093a32f0e9356340c4ab0e81a6c17b97c71571 # Parent 862f407f999c9d3d75ad919406b3b6227e1c69a6 Attempt to separate RSVP instruction implementations from native function implementations. diff -r 862f407f999c -r 26093a32f0e9 rsvp.py --- a/rsvp.py Fri Jul 10 00:12:09 2009 +0200 +++ b/rsvp.py Fri Jul 10 00:52:04 2009 +0200 @@ -79,13 +79,12 @@ "A really simple virtual processor." - def __init__(self, memory, objlist, paramlist, true_constant, false_constant, pc=None, debug=0, abort_upon_exception=0): + def __init__(self, memory, objlist, paramlist, pc=None, debug=0, abort_upon_exception=0): """ Initialise the processor with a 'memory' (a list of values containing instructions and data), the object and parameter lists 'objlist' and - 'paramlist', the addresses 'true_constant' and 'false_constant', and the - optional program counter 'pc'. + 'paramlist', and the optional program counter 'pc'. """ self.memory = memory @@ -93,8 +92,7 @@ self._paramlist = paramlist self.objlist = objlist.as_raw() self.paramlist = paramlist.as_raw() - self.true_constant = true_constant - self.false_constant = false_constant + self.library = None self.pc = pc or 0 self.debug = debug @@ -133,17 +131,6 @@ self.index_error = cls.location self.index_error_instance = cls.instance_template_location - # Native class constants. - - cls = self._get_class("__builtins__", "int") - self.int_class = cls.location - self.int_instance = cls.instance_template_location - cls = self._get_class("__builtins__", "list") - self.list_class = cls.location - self.list_instance = cls.instance_template_location - cls = self._get_class("__builtins__", "tuple") - self.tuple_class = cls.location - # Debugging attributes. self.breakpoints = set() @@ -381,7 +368,7 @@ # of proper locations. if isinstance(addr, str): - handler = self.native_functions[addr](self) + handler = self.library and self.library.native_functions[addr](self.library) if handler is None: return next else: @@ -536,7 +523,7 @@ def DropFrame(self): self.local_sp_stack.pop() frame = self.invocation_sp_stack.pop() - self.frame_stack = self.frame_stack[:frame] # reset stack before call + del self.frame_stack[frame:] # reset stack before call def StoreFrame(self): frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame @@ -703,7 +690,7 @@ def PopHandler(self): # Reduce the local frame pointer stack to refer to the handler's frame. - self.local_sp_stack = self.local_sp_stack[:self.handler_local_sp_stack.pop()] + del self.local_sp_stack[self.handler_local_sp_stack.pop():] # Reduce the PC stack to discard all superfluous return addresses. self.pc_stack = self.pc_stack[:self.handler_pc_stack.pop()] self.handler_stack.pop() @@ -771,7 +758,35 @@ else: return context, ref - # Native function implementations. +class Library: + + "Native function implementations." + + def __init__(self, machine, true_constant, false_constant): + + """ + Initialise the library with the 'machine' and the addresses + 'true_constant' and 'false_constant'. + """ + + self.machine = machine + self.true_constant = true_constant + self.false_constant = false_constant + + # Native class constants. + + cls = self.machine._get_class("__builtins__", "int") + self.int_class = cls.location + self.int_instance = cls.instance_template_location + cls = self.machine._get_class("__builtins__", "list") + self.list_class = cls.location + self.list_instance = cls.instance_template_location + cls = self.machine._get_class("__builtins__", "tuple") + self.tuple_class = cls.location + + self.type_error_instance = self.machine.type_error_instance + self.frame_stack = self.machine.frame_stack + self.local_sp_stack = self.machine.local_sp_stack def builtins_int_arithmetic_op(self, op): frame = self.local_sp_stack[-1] @@ -784,9 +799,9 @@ # Test operand suitability. # NOTE: Support other types. - if not (self._CheckInstance(left, self.int_class) and self._CheckInstance(right, self.int_class)): - self.exception = self._MakeObject(2, self.type_error_instance) - return self.RaiseException() + if not (self.machine._CheckInstance(left, self.int_class) and self.machine._CheckInstance(right, self.int_class)): + self.machine.exception = self.machine._MakeObject(2, self.type_error_instance) + return self.machine.RaiseException() # NOTE: Assume single location for data. @@ -795,23 +810,23 @@ # Make a new object. - addr = self._MakeObject(2, self.int_instance) + addr = self.machine._MakeObject(2, self.int_instance) # Store the result. # NOTE: The data is considered ready to use. - self.save(addr + 1, op(self.load(left_data), self.load(right_data))) + self.machine.save(addr + 1, op(self.machine.load(left_data), self.machine.load(right_data))) # Return the new object. # Introduce object as context for the new object. - self.result = addr, addr + self.machine.result = addr, addr def builtins_int_add(self): - return self.builtins_int_arithmetic_op(operator.add) + return self.machine.builtins_int_arithmetic_op(operator.add) def builtins_int_sub(self): - return self.builtins_int_arithmetic_op(operator.sub) + return self.machine.builtins_int_arithmetic_op(operator.sub) def builtins_int_bool(self): frame = self.local_sp_stack[-1] @@ -822,9 +837,9 @@ # Test operand suitability. - if not self._CheckInstance(left, self.int_class): - self.exception = self._MakeObject(2, self.type_error_instance) - return self.RaiseException() + if not self.machine._CheckInstance(left, self.int_class): + self.machine.exception = self.machine._MakeObject(2, self.type_error_instance) + return self.machine.RaiseException() # NOTE: Assume single location for data. @@ -833,10 +848,10 @@ # Test the data. # NOTE: The data is considered ready to use. - if self.load(left_data) != 0: - self.result = self.true_constant, self.true_constant + if self.machine.load(left_data) != 0: + self.machine.result = self.true_constant, self.true_constant else: - self.result = self.false_constant, self.false_constant + self.machine.result = self.false_constant, self.false_constant def builtins_int_neg(self): frame = self.local_sp_stack[-1] @@ -847,9 +862,9 @@ # Test operand suitability. - if not self._CheckInstance(left, self.int_class): - self.exception = self._MakeObject(2, self.type_error_instance) - return self.RaiseException() + if not self.machine._CheckInstance(left, self.int_class): + self.machine.exception = self.machine._MakeObject(2, self.type_error_instance) + return self.machine.RaiseException() # NOTE: Assume single location for data. @@ -857,17 +872,17 @@ # Make a new object. - addr = self._MakeObject(2, self.int_instance) + addr = self.machine._MakeObject(2, self.int_instance) # Store the result. # NOTE: The data is considered ready to use. - self.save(addr + 1, -self.load(left_data)) + self.machine.save(addr + 1, -self.machine.load(left_data)) # Return the new object. # Introduce object as context for the new object. - self.result = addr, addr + self.machine.result = addr, addr def builtins_int_op(self, op, true_if_incompatible): frame = self.local_sp_stack[-1] @@ -881,11 +896,11 @@ # NOTE: Support other types. # NOTE: Handle comparisons of incompatible types more appropriately. - if not (self._CheckInstance(left, self.int_class) and self._CheckInstance(right, self.int_class)): + if not (self.machine._CheckInstance(left, self.int_class) and self.machine._CheckInstance(right, self.int_class)): if true_if_incompatible: - self.result = self.true_constant, self.true_constant + self.machine.result = self.true_constant, self.true_constant else: - self.result = self.false_constant, self.false_constant + self.machine.result = self.false_constant, self.false_constant return # NOTE: Assume single location for data. @@ -896,28 +911,28 @@ # Test the data. # NOTE: The data is considered ready to use. - if op(self.load(left_data), self.load(right_data)): - self.result = self.true_constant, self.true_constant + if op(self.machine.load(left_data), self.machine.load(right_data)): + self.machine.result = self.true_constant, self.true_constant else: - self.result = self.false_constant, self.false_constant + self.machine.result = self.false_constant, self.false_constant def builtins_int_lt(self): - return self.builtins_int_op(operator.lt, 0) + return self.machine.builtins_int_op(operator.lt, 0) def builtins_int_le(self): - return self.builtins_int_op(operator.le, 0) + return self.machine.builtins_int_op(operator.le, 0) def builtins_int_gt(self): - return self.builtins_int_op(operator.gt, 0) + return self.machine.builtins_int_op(operator.gt, 0) def builtins_int_ge(self): - return self.builtins_int_op(operator.ge, 0) + return self.machine.builtins_int_op(operator.ge, 0) def builtins_int_eq(self): - return self.builtins_int_op(operator.eq, 0) + return self.machine.builtins_int_op(operator.eq, 0) def builtins_int_ne(self): - return self.builtins_int_op(operator.ne, 1) + return self.machine.builtins_int_op(operator.ne, 1) def builtins_bool_bool(self): frame = self.local_sp_stack[-1] @@ -925,7 +940,7 @@ # Get operands addresses. left_context, left = self.frame_stack[frame] - self.result = left, left + self.machine.result = left, left def builtins_list_new(self): frame = self.local_sp_stack[-1] @@ -937,30 +952,30 @@ # Test operand suitability. - if self._CheckInstance(args, self.list_class): - _x, sequence = self.load(args + 1) - header = self.load(sequence) + if self.machine._CheckInstance(args, self.list_class): + _x, sequence = self.machine.load(args + 1) + header = self.machine.load(sequence) size = header.occupied_size - elif self._CheckInstance(args, self.tuple_class): + elif self.machine._CheckInstance(args, self.tuple_class): sequence = args - header = self.load(sequence) + header = self.machine.load(sequence) size = header.size else: - self.exception = self._MakeObject(2, self.type_error_instance) - return self.RaiseException() + self.machine.exception = self.machine._MakeObject(2, self.type_error_instance) + return self.machine.RaiseException() # Copy the sequence contents. - new_fragment = self._MakeFragment(size) + new_fragment = self.machine._MakeFragment(size) for i in range(1, size): - self.save(new_fragment + i, self.load(sequence + i)) + self.machine.save(new_fragment + i, self.machine.load(sequence + i)) # Make the list instance. - addr = self._MakeObject(2, self.list_instance) - self.save(addr + 1, (None, new_fragment)) + addr = self.machine._MakeObject(2, self.list_instance) + self.machine.save(addr + 1, (None, new_fragment)) - self.result = addr, addr + self.machine.result = addr, addr def builtins_list_getitem(self): frame = self.local_sp_stack[-1] @@ -976,27 +991,27 @@ # Get the fragment address. # NOTE: Assume single location for header. - _x, fragment = self.load(obj + 1) + _x, fragment = self.machine.load(obj + 1) # Get the fragment header. - header = self.load(fragment) + header = self.machine.load(fragment) nelements = header.occupied_size - 1 # NOTE: Assume single location for data and header. - item_pos = self.load(item + 1) + item_pos = self.machine.load(item + 1) if item_pos >= 0 and item_pos < nelements: pass elif item_pos < 0 and item_pos >= -nelements: item_pos = nelements + item_pos else: - self.exception = self._MakeObject(2, self.index_error_instance) - return self.RaiseException() + self.machine.exception = self.machine._MakeObject(2, self.index_error_instance) + return self.machine.RaiseException() # NOTE: Assume single location for header. - self.result = self.load(fragment + 1 + item_pos) + self.machine.result = self.machine.load(fragment + 1 + item_pos) def builtins_list_len(self): frame = self.local_sp_stack[-1] @@ -1008,26 +1023,26 @@ # Get the fragment address. # NOTE: Assume single location for header. - _x, fragment = self.load(obj + 1) + _x, fragment = self.machine.load(obj + 1) # Get the fragment header. - header = self.load(fragment) + header = self.machine.load(fragment) nelements = header.occupied_size - 1 # Make a new object. - addr = self._MakeObject(2, self.int_instance) + addr = self.machine._MakeObject(2, self.int_instance) # Store the result. # NOTE: The data is considered ready to use. - self.save(addr + 1, nelements) + self.machine.save(addr + 1, nelements) # Return the new object. # Introduce object as context for the new object. - self.result = addr, addr + self.machine.result = addr, addr def builtins_list_append(self): frame = self.local_sp_stack[-1] @@ -1043,35 +1058,35 @@ # Get the fragment address. # NOTE: Assume single location for header. - _x, fragment = self.load(obj + 1) + _x, fragment = self.machine.load(obj + 1) # Get the fragment header. - header = self.load(fragment) + header = self.machine.load(fragment) # Attempt to add the reference. if header.occupied_size < header.allocated_size: - self.save(fragment + header.occupied_size, (arg_context, arg)) + self.machine.save(fragment + header.occupied_size, (arg_context, arg)) header.occupied_size += 1 else: # Make a new fragment, maintaining more space than currently # occupied in order to avoid reallocation. - new_fragment = self._MakeFragment(header.allocated_size) + new_fragment = self.machine._MakeFragment(header.allocated_size) # Copy existing elements. for i in range(1, header.allocated_size): - self.save(new_fragment + i, self.load(fragment + i)) + self.machine.save(new_fragment + i, self.machine.load(fragment + i)) - self.save(new_fragment + header.allocated_size, (arg_context, arg)) + self.machine.save(new_fragment + header.allocated_size, (arg_context, arg)) # Set the new fragment in the object. # NOTE: The old fragment could be deallocated. - self.save(obj + 1, (None, new_fragment)) + self.machine.save(obj + 1, (None, new_fragment)) def builtins_object_init(self): pass @@ -1120,7 +1135,9 @@ importer = program.get_importer() true_constant = importer.get_constant(True).location false_constant = importer.get_constant(False).location - rm = RSVPMachine(rc, objlist, paramlist, true_constant, false_constant, debug=debug, abort_upon_exception=abort_upon_exception) + rm = RSVPMachine(rc, objlist, paramlist, debug=debug, abort_upon_exception=abort_upon_exception) + library = Library(rm, true_constant, false_constant) + rm.library = library rm.pc = program.code_location print "Returning program occupying %d locations." % len(rm.memory) return rm