# HG changeset patch # User Paul Boddie # Date 1220550279 -7200 # Node ID 4c95794770e60f83af3c84b5ad9d7bbe761313f9 # Parent f660fe1aac5cf22c911ca934ae65b7dbbe07fa33 Made object construction through MakeObject use details of a supplied class, reserving an extra location for type information. Changed some LoadAddress usage to LoadConst in order to feed instructions which require a value, not the type information of an object (which is what LoadAddress acting on a reference to an object, as opposed to an attribute, would provide). Added parameter default details to raw class and function information, although further default details are required. Added convenience methods to the RSVPMachine class for inspecting and stepping through execution of a program. Changed various RSVP implementations, fixing stack manipulation and returning from subroutines. Made the test of lists wider in scope. diff -r f660fe1aac5c -r 4c95794770e6 micropython/ast.py --- a/micropython/ast.py Mon Sep 01 01:32:32 2008 +0200 +++ b/micropython/ast.py Thu Sep 04 19:44:39 2008 +0200 @@ -159,12 +159,12 @@ # Make an object. - self.new_op(MakeObject(len(cls.instance_attributes()))) + self.make_object(cls, len(cls.instance_attributes())) self.new_op(StoreFrame(0)) # Invoke the appropriate initialiser. - self.new_op(LoadAddress(init_method)) + self.new_op(LoadConst(init_method)) self.new_op(LoadCallable()) self.new_op(JumpWithFrame()) @@ -176,6 +176,19 @@ return self.code + # Allocation-related methods. + + def make_object(self, cls, n): + + """ + Request a new object with the given class 'cls' and with 'n' attributes. + """ + + # NOTE: Object headers are one location. + + self.new_op(LoadConst(cls)) + self.new_op(MakeObject(n + 1)) + # Name-related methods. def get_scope(self, name): @@ -195,6 +208,9 @@ self.new_op(LoadAddress(self.get_builtin(name, node))) + def get_builtin_class(self, name, node): + return self.get_builtin(name, node).value + def get_builtin(self, name, node): """ @@ -418,7 +434,7 @@ instruction). """ - return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadAddress, MakeObject)) + return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadAddress)) def _is_simple_input_user(self, instruction): @@ -430,7 +446,7 @@ StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced LoadCallable, TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands - CheckFrame, + CheckFrame, MakeObject, LoadContext # as the object providing the result )) @@ -851,7 +867,7 @@ # to the __init__ method. elif isinstance(target, Class): - self.new_op(MakeObject(len(target.instance_attributes()))) + self.make_object(target, len(target.instance_attributes())) self.new_op(StoreFrame(0)) # Otherwise omit the context. @@ -1107,7 +1123,7 @@ "Make the invocation." if isinstance(target, Class): - self.new_op(LoadAddress(target.get_init_method())) + self.new_op(LoadConst(target.get_init_method())) else: self.new_op(instruction) self.new_op(LoadCallable()) @@ -1154,7 +1170,7 @@ dynamic = function.name is None if dynamic: - self.new_op(MakeObject(("function", len(attr_to_default)))) + self.make_object(self.get_builtin_class("function", function), len(attr_to_default)) temp = self.get_temp() for attr, default in attr_to_default: @@ -1398,7 +1414,7 @@ "Make a sequence of 'sequence_type' for the given program 'node'." - self.new_op(MakeObject((sequence_type, len(node.nodes)))) + self.make_object(self.get_builtin(sequence_type, node), len(node.nodes)) temp = self.get_temp() for i, n in enumerate(node.nodes): diff -r f660fe1aac5c -r 4c95794770e6 micropython/rsvp.py --- a/micropython/rsvp.py Mon Sep 01 01:32:32 2008 +0200 +++ b/micropython/rsvp.py Thu Sep 04 19:44:39 2008 +0200 @@ -33,11 +33,13 @@ elif isinstance(item, Class): # NOTE: Need initialiser details! new_code.append(( - objtable.as_list().get_code(item.full_name()), - objtable.get_index(item.full_name()), - item.get_instantiator().code_location, - len(item.get_instantiator().positional_names) - )) + objtable.as_list().get_code(item.full_name()), + objtable.get_index(item.full_name()), + item.get_instantiator().code_location, + ( + len(item.get_instantiator().positional_names), + len(item.get_instantiator().defaults) + ))) elif isinstance(item, Const): # NOTE: Need class details! new_code.append(( @@ -51,8 +53,10 @@ objtable.as_list().get_code("__builtins__.function"), objtable.get_index("__builtins__.function"), item.code_location, - len(item.positional_names) - )) + ( + len(item.positional_names), + len(item.defaults) + ))) else: new_code.append(item) return new_code @@ -200,6 +204,11 @@ class LoadAttrIndex(Immediate): "Load into the current value the attribute of the current value with the given index." class StoreAttrIndex(Immediate): "Store an object in the attribute with the given index." +# Access to object details. + +class LoadCallable(Instruction): "Load the target of an invocation." +class StoreCallable(Instruction): "Store the source value into the object referenced by the current value." + # Access to invocation frames in preparation. class MakeFrame(Immediate): "Make a new invocation frame." @@ -207,8 +216,6 @@ class RecoverFrame(Instruction): "Recover the current frame as an invocation frame." class StoreFrame(Immediate): "Store the current value as an argument for the parameter with the given position." class StoreFrameIndex(Immediate): "Store the current value as an argument for the parameter with the given index." -class LoadCallable(Instruction): "Load the target of an invocation." -class StoreCallable(Instruction): "Store the source value into the object referenced by the current value." class LoadContext(Instruction): "Load the context of an invocation." class CheckFrame(Immediate): "Check the invocation frame and context for the target." class CheckSelf(Instruction): "Check the first argument of an invocation against the target." diff -r f660fe1aac5c -r 4c95794770e6 micropython/table.py --- a/micropython/table.py Mon Sep 01 01:32:32 2008 +0200 +++ b/micropython/table.py Thu Sep 04 19:44:39 2008 +0200 @@ -202,6 +202,7 @@ self.objnames = [] self.names = [] self.displaced_list = None + self.raw = None def add(self, objname, attributes): @@ -321,7 +322,9 @@ "Return the raw contents of the table as a list of values." - return self.as_list().as_raw() + if self.raw is None: + self.raw = self.as_list().as_raw() + return self.raw class ObjectTable(Table): diff -r f660fe1aac5c -r 4c95794770e6 rsvp.py --- a/rsvp.py Mon Sep 01 01:32:32 2008 +0200 +++ b/rsvp.py Thu Sep 04 19:44:39 2008 +0200 @@ -58,7 +58,7 @@ "A really simple virtual processor." - def __init__(self, memory, objtable, paramtable, pc=None, debug=0): + def __init__(self, memory, objlist, paramlist, pc=None, debug=0): """ Initialise the processor with a 'memory' (a list of values containing @@ -66,8 +66,8 @@ """ self.memory = memory - self.objtable = objtable - self.paramtable = paramtable + self.objlist = objlist + self.paramlist = paramlist self.pc = pc or 0 self.debug = debug @@ -91,7 +91,7 @@ self.exception = None def dump(self): - print "PC", self.pc + print "PC", self.pc, "->", self.load(self.pc) print "PC stack", self.pc_stack print "Frame stack", self.frame_stack print "Local stack pointers", self.local_sp_stack @@ -107,6 +107,10 @@ print "Result", self.result print "Exception", self.exception + def step(self): + self.execute() + self.dump() + def load(self, address): "Return the value at the given 'address'." @@ -226,7 +230,7 @@ getattr(self, addr)() return next else: - self.push_pc(self.pc + 2) + self.push_pc(self.pc + 1) return addr # Instructions. @@ -259,8 +263,14 @@ self.save(self.operand, self.value) def MakeObject(self): + size = self.operand + context, ref = self.value + classcode, attrcode, codeaddr, codedetails = self.load(ref) + addr = self.new(size) + # Set the header to resemble the class. + self.save(addr, (classcode, attrcode, None, None)) # NOTE: __call__ method not yet provided. # Introduce null context for new object. - self.value = None, self.new(self.operand) + self.value = None, addr def LoadAttr(self): context, ref = self.value @@ -275,7 +285,7 @@ def LoadAttrIndex(self): context, ref = self.value classcode, attrcode, codeaddr, codedetails = self.load(ref) - element = self.objtable[classcode + self.operand] + element = self.objlist[classcode + self.operand] attr_index, class_attr, replace_context, offset = element if attr_index == self.operand: if class_attr: @@ -293,7 +303,7 @@ def StoreAttrIndex(self): context, ref = self.value classcode, attrcode, codeaddr, codedetails = self.load(ref) - element = self.objtable[classcode + self.operand] + element = self.objlist[classcode + self.operand] attr_index, class_attr, replace_context, offset = element if attr_index == self.operand: if class_attr: @@ -327,7 +337,7 @@ def StoreFrameIndex(self): frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame classcode, attrcode, codeaddr, codedetails = self.load(ref) - element = self.objtable[classcode + self.operand] + element = self.objlist[classcode + self.operand] attr_index, offset = element if attr_index == self.operand: self.frame_stack[frame + offset] = self.value @@ -359,11 +369,11 @@ # Support sliding of the frame to exclude any inappropriate context. if context is None: - frame = frame[1:] + self.invocation_sp_stack[-1] += 1 operand -= 1 else: if contexttype == self.typetype: - frame = frame[1:] + self.invocation_sp_stack[-1] += 1 operand -= 1 nargs, ndefaults = codedetails @@ -383,7 +393,7 @@ # Find the table entry for the descendant. - element = self.objtable[target_classcode + attrcode] + element = self.objlist[target_classcode + attrcode] attr_index, class_attr, replace_context, offset = element if attr_index == attrcode: self.status = 1 @@ -391,23 +401,23 @@ self.status = 0 def JumpWithFrame(self): + codeaddr, codedetails = self.callable self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame - return self.jump(self.callable, self.pc + 1) # return to the instruction after this one + return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one def ExtendFrame(self): - frame = self.local_sp_stack[-1] - frame.extend([None] * self.operand) + self.frame_stack.extend([None] * self.operand) def AdjustFrame(self): if self.operand > 0: - frame.append([None] * self.operand) + self.frame_stack.append([None] * self.operand) elif self.operand == -1: self.invocation_sp_stack[-1] -= 1 else: raise Exception, "AdjustFrame %r" % self.operand def Return(self): - self.pc = self.pull_pc() + return self.pull_pc() def LoadResult(self): self.value = self.result diff -r f660fe1aac5c -r 4c95794770e6 test.py --- a/test.py Mon Sep 01 01:32:32 2008 +0200 +++ b/test.py Thu Sep 04 19:44:39 2008 +0200 @@ -27,15 +27,17 @@ print "%6d" % (len(table_slice) - table_slice.count(None)), \ "".join(entry and "#" or "_" for entry in table_slice) -def machine(importer): +def machine(importer, with_builtins=0, optimisations=None): print "Making the image..." - make(importer) - rc = raw(importer.get_image()) - print "Getting raw tables..." - objtable = importer.get_object_table().as_raw() - paramtable = importer.get_parameter_table().as_raw() + make(importer, with_builtins, optimisations) + print "Getting raw structures..." + ot = importer.get_object_table() + pt = importer.get_parameter_table() + objlist = ot.as_raw() + paramlist = pt.as_raw() + rc = raw(importer.get_image(), ot, pt) print "Initialising the machine..." - rm = rsvp.RSVPMachine(rc, objtable, paramtable) + rm = rsvp.RSVPMachine(rc, objlist, paramlist) rm.pc = importer.code_location return rm diff -r f660fe1aac5c -r 4c95794770e6 tests/list.py --- a/tests/list.py Mon Sep 01 01:32:32 2008 +0200 +++ b/tests/list.py Thu Sep 04 19:44:39 2008 +0200 @@ -3,5 +3,6 @@ [1, 2, 3] a = [1, 2, 3] [1, [2, 3], 4, 5] +b = list((9, 8, 7)) # vim: tabstop=4 expandtab shiftwidth=4