1.1 --- a/rsvp.py Mon Jun 15 00:40:25 2009 +0200
1.2 +++ b/rsvp.py Sun Jun 21 02:02:53 2009 +0200
1.3 @@ -52,7 +52,7 @@
1.4 current callable
1.5 """
1.6
1.7 -from micropython.program import ReplaceableContext, PlaceholderContext
1.8 +from micropython.program import ReplaceableContext, PlaceholderContext, FragmentObject
1.9 import operator
1.10
1.11 class IllegalInstruction(Exception):
1.12 @@ -79,7 +79,7 @@
1.13
1.14 "A really simple virtual processor."
1.15
1.16 - def __init__(self, memory, objlist, paramlist, true_constant, false_constant, pc=None, debug=0):
1.17 + def __init__(self, memory, objlist, paramlist, true_constant, false_constant, pc=None, debug=0, abort_upon_exception=0):
1.18
1.19 """
1.20 Initialise the processor with a 'memory' (a list of values containing
1.21 @@ -98,6 +98,7 @@
1.22
1.23 self.pc = pc or 0
1.24 self.debug = debug
1.25 + self.abort_upon_exception = abort_upon_exception
1.26
1.27 # Stacks.
1.28
1.29 @@ -138,7 +139,10 @@
1.30 self.int_class = cls.location
1.31 self.int_instance = cls.instance_template_location
1.32 cls = self._get_class("__builtins__", "list")
1.33 + self.list_class = cls.location
1.34 self.list_instance = cls.instance_template_location
1.35 + cls = self._get_class("__builtins__", "tuple")
1.36 + self.tuple_class = cls.location
1.37
1.38 # Debugging attributes.
1.39
1.40 @@ -447,6 +451,12 @@
1.41 # Introduce object as context for the new object.
1.42 self.value = addr, addr
1.43
1.44 + def MakeFragment(self):
1.45 + size = self.operand
1.46 + addr = self._MakeFragment(size)
1.47 + # NOTE: Context is not relevant for fragments.
1.48 + self.value = None, addr
1.49 +
1.50 def LoadAttr(self):
1.51 context, ref = self.value
1.52 # Retrieved context should already be appropriate for the instance.
1.53 @@ -682,6 +692,8 @@
1.54 # NOTE: Adding the program counter as the first attribute.
1.55 self.save(self.exception + 1, self.pc)
1.56 # Jumping to the current handler.
1.57 + if self.abort_upon_exception:
1.58 + raise Exception
1.59 return self.handler_stack[-1]
1.60
1.61 def PushHandler(self):
1.62 @@ -743,6 +755,13 @@
1.63 self.save(addr, data.with_size(size))
1.64 return addr
1.65
1.66 + def _MakeFragment(self, size):
1.67 + # Reserve twice the amount of space.
1.68 + addr = self.new(size * 2)
1.69 + # Save the header, overriding the size.
1.70 + self.save(addr, FragmentObject(size, size * 2))
1.71 + return addr
1.72 +
1.73 def _LoadAddressContextCond(self, context, ref, inst_ref):
1.74 # Check the instance context against the target's context.
1.75 # This provides the context overriding for methods.
1.76 @@ -915,26 +934,56 @@
1.77 # NOTE: Specific copying of tuples/lists.
1.78
1.79 args_context, args = self.frame_stack[frame + 1]
1.80 - header = self.load(args)
1.81 +
1.82 + # Test operand suitability.
1.83
1.84 - list = self._MakeObject(header.size, self.list_instance)
1.85 - for i in range(1, header.size):
1.86 - self.save(list + i, self.load(args + i))
1.87 + if self._CheckInstance(args, self.list_class):
1.88 + _x, sequence = self.load(args + 1)
1.89 + header = self.load(sequence)
1.90 + size = header.occupied_size
1.91 + elif self._CheckInstance(args, self.tuple_class):
1.92 + sequence = args
1.93 + header = self.load(sequence)
1.94 + size = header.size
1.95 + else:
1.96 + self.exception = self._MakeObject(2, self.type_error_instance)
1.97 + return self.RaiseException()
1.98
1.99 - self.result = list, list
1.100 + # Copy the sequence contents.
1.101 +
1.102 + new_fragment = self._MakeFragment(size)
1.103 + for i in range(1, size):
1.104 + self.save(new_fragment + i, self.load(sequence + i))
1.105 +
1.106 + # Make the list instance.
1.107 +
1.108 + addr = self._MakeObject(2, self.list_instance)
1.109 + self.save(addr + 1, (None, new_fragment))
1.110 +
1.111 + self.result = addr, addr
1.112
1.113 def builtins_list_getitem(self):
1.114 frame = self.local_sp_stack[-1]
1.115
1.116 - # Get operands addresses.
1.117 + # Get the operand address.
1.118
1.119 - obj_context, obj = self.frame_stack[frame]
1.120 item_context, item = self.frame_stack[frame + 1]
1.121
1.122 - header = self.load(obj)
1.123 - nelements = header.size - 1
1.124 + # Get the list address.
1.125 +
1.126 + obj_context, obj = self.frame_stack[frame]
1.127 +
1.128 + # Get the fragment address.
1.129 + # NOTE: Assume single location for header.
1.130
1.131 - # NOTE: Assume single location for data.
1.132 + _x, fragment = self.load(obj + 1)
1.133 +
1.134 + # Get the fragment header.
1.135 +
1.136 + header = self.load(fragment)
1.137 + nelements = header.occupied_size - 1
1.138 +
1.139 + # NOTE: Assume single location for data and header.
1.140
1.141 item_pos = self.load(item + 1)
1.142 if item_pos >= 0 and item_pos < nelements:
1.143 @@ -945,7 +994,84 @@
1.144 self.exception = self._MakeObject(2, self.index_error_instance)
1.145 return self.RaiseException()
1.146
1.147 - self.result = self.load(obj + 1 + item_pos)
1.148 + # NOTE: Assume single location for header.
1.149 +
1.150 + self.result = self.load(fragment + 1 + item_pos)
1.151 +
1.152 + def builtins_list_len(self):
1.153 + frame = self.local_sp_stack[-1]
1.154 +
1.155 + # Get the list address.
1.156 +
1.157 + obj_context, obj = self.frame_stack[frame]
1.158 +
1.159 + # Get the fragment address.
1.160 + # NOTE: Assume single location for header.
1.161 +
1.162 + _x, fragment = self.load(obj + 1)
1.163 +
1.164 + # Get the fragment header.
1.165 +
1.166 + header = self.load(fragment)
1.167 + nelements = header.occupied_size - 1
1.168 +
1.169 + # Make a new object.
1.170 +
1.171 + addr = self._MakeObject(2, self.int_instance)
1.172 +
1.173 + # Store the result.
1.174 + # NOTE: The data is considered ready to use.
1.175 +
1.176 + self.save(addr + 1, nelements)
1.177 +
1.178 + # Return the new object.
1.179 + # Introduce object as context for the new object.
1.180 +
1.181 + self.result = addr, addr
1.182 +
1.183 + def builtins_list_append(self):
1.184 + frame = self.local_sp_stack[-1]
1.185 +
1.186 + # Get operand address.
1.187 +
1.188 + arg_context, arg = self.frame_stack[frame + 1]
1.189 +
1.190 + # Get the list address.
1.191 +
1.192 + obj_context, obj = self.frame_stack[frame]
1.193 +
1.194 + # Get the fragment address.
1.195 + # NOTE: Assume single location for header.
1.196 +
1.197 + _x, fragment = self.load(obj + 1)
1.198 +
1.199 + # Get the fragment header.
1.200 +
1.201 + header = self.load(fragment)
1.202 +
1.203 + # Attempt to add the reference.
1.204 +
1.205 + if header.occupied_size < header.allocated_size:
1.206 + self.save(fragment + header.occupied_size, (arg_context, arg))
1.207 + header.occupied_size += 1
1.208 + else:
1.209 +
1.210 + # Make a new fragment, maintaining more space than currently
1.211 + # occupied in order to avoid reallocation.
1.212 +
1.213 + new_fragment = self._MakeFragment(header.allocated_size)
1.214 +
1.215 + # Copy existing elements.
1.216 +
1.217 + for i in range(1, header.allocated_size):
1.218 + self.save(new_fragment + i, self.load(fragment + i))
1.219 +
1.220 + self.save(new_fragment + header.allocated_size, (arg_context, arg))
1.221 +
1.222 + # Set the new fragment in the object.
1.223 + # NOTE: The old fragment could be deallocated.
1.224 +
1.225 + self.save(obj + 1, (None, new_fragment))
1.226
1.227 def builtins_object_init(self):
1.228 pass
1.229 @@ -968,6 +1094,8 @@
1.230 "__builtins__.int.__ne__" : builtins_int_ne,
1.231 "__builtins__.bool.__bool__" : builtins_bool_bool,
1.232 "__builtins__.list.__getitem__" : builtins_list_getitem,
1.233 + "__builtins__.list.__len__" : builtins_list_len,
1.234 + "__builtins__.list.append" : builtins_list_append,
1.235 "__builtins__.object.__init__" : builtins_object_init, # NOTE: A no-operation.
1.236 "__builtins__.BaseException.__init__" : builtins_object_init, # NOTE: To be made distinct, potentially in the builtins module.
1.237
1.238 @@ -978,7 +1106,7 @@
1.239
1.240 # Convenience functions.
1.241
1.242 -def machine(program, with_builtins=0, debug=0):
1.243 +def machine(program, with_builtins=0, debug=0, abort_upon_exception=0):
1.244 print "Making the image..."
1.245 code = program.get_image(with_builtins)
1.246 print "Getting raw structures..."
1.247 @@ -992,7 +1120,7 @@
1.248 importer = program.get_importer()
1.249 true_constant = importer.get_constant(True).location
1.250 false_constant = importer.get_constant(False).location
1.251 - rm = RSVPMachine(rc, objlist, paramlist, true_constant, false_constant, debug=debug)
1.252 + rm = RSVPMachine(rc, objlist, paramlist, true_constant, false_constant, debug=debug, abort_upon_exception=abort_upon_exception)
1.253 rm.pc = program.code_location
1.254 print "Returning program occupying %d locations." % len(rm.memory)
1.255 return rm