# HG changeset patch # User Paul Boddie # Date 1233534875 -3600 # Node ID 5c8320ec4c464d0f0f325acf3be41e8cb54cdd3c # Parent 168c6f68045d406a0d2252cb141f179a71764655 Introduced a DataObject class to provide a nicer representation of the raw objects for classes, functions, instances and modules. Fixed the run-time initialisation of the int class reference. Fixed attribute access for situations where an attribute's nature cannot be determined; added a test of mix-in classes which requires such access behaviour. Added initial support and a test for instance invocation, although work is still required in the initialisation of instance structures. diff -r 168c6f68045d -r 5c8320ec4c46 docs/structures.txt --- a/docs/structures.txt Mon Jan 26 01:25:30 2009 +0100 +++ b/docs/structures.txt Mon Feb 02 01:34:35 2009 +0100 @@ -197,7 +197,10 @@ return instance If C has a __call__ attribute, the invocation "slot" of C instances would -refer to the same thing as C.__call__. +refer to the same thing as C.__call__. This "slot" has to be prepared when +creating instances, potentially using a template instance or by modifying the +sequence of instructions used in, amongst other places, the instantiator +function. For functions, the same general layout applies: diff -r 168c6f68045d -r 5c8320ec4c46 micropython/__init__.py --- a/micropython/__init__.py Mon Jan 26 01:25:30 2009 +0100 +++ b/micropython/__init__.py Mon Feb 02 01:34:35 2009 +0100 @@ -257,28 +257,34 @@ instantiator_code_location = item.get_instantiator().blocks[0].location # NOTE: Need initialiser details! - self.raw_code.append(( - objtable.as_list().get_code(item.full_name()), - objtable.get_index(item.full_name()), - instantiator_code_location, - ( - len(item.get_instantiator().positional_names), - len(item.get_instantiator().defaults) - ), - 0 - )) + self.raw_code.append( + DataObject( + objtable.as_list().get_code(item.full_name()), + objtable.get_index(item.full_name()), + instantiator_code_location, + ( + len(item.get_instantiator().positional_names), + len(item.get_instantiator().defaults) + ), + 0, + item.full_name() + ) + ) elif isinstance(item, micropython.data.Const): assert item.location == len(self.raw_code) # NOTE: Need class details! - self.raw_code.append(( - objtable.as_list().get_code(item.value_type_name()), - objtable.get_index(item.value_type_name()), - None, - None, - 1 - )) + self.raw_code.append( + DataObject( + objtable.as_list().get_code(item.value_type_name()), + objtable.get_index(item.value_type_name()), + None, + None, + 1, + item.value_type_name() + ) + ) self.raw_code += self.raw_data(item) @@ -286,16 +292,19 @@ assert item.location == len(self.raw_code) # NOTE: Need class and parameter details! Should arguably be types.FunctionType. - self.raw_code.append(( - objtable.as_list().get_code("__builtins__.function"), - objtable.get_index("__builtins__.function"), - item.code_location, - ( - len(item.positional_names), - len(item.defaults) - ), - 0 - )) + self.raw_code.append( + DataObject( + objtable.as_list().get_code("__builtins__.function"), + objtable.get_index("__builtins__.function"), + item.code_location, + ( + len(item.positional_names), + len(item.defaults) + ), + 0, + "__builtins__.function" + ) + ) # Check the code location only where the code has been generated. @@ -305,13 +314,16 @@ elif isinstance(item, micropython.data.Module): assert item.location == len(self.raw_code) - self.raw_code.append(( - objtable.as_list().get_code(item.full_name()), - None, # module name not used as an attribute - None, - None, - 0 - )) + self.raw_code.append( + DataObject( + objtable.as_list().get_code(item.full_name()), + None, # module name not used as an attribute + None, + None, + 0, + item.full_name() + ) + ) else: self.raw_code.append(item) @@ -458,7 +470,7 @@ # Name records (used to track actual use of names). # Include names which may not be explicitly used in programs. - self.names_used = set(["__init__"]) + self.names_used = set(["__init__", "__call__"]) # Status information. diff -r 168c6f68045d -r 5c8320ec4c46 micropython/ast.py --- a/micropython/ast.py Mon Jan 26 01:25:30 2009 +0100 +++ b/micropython/ast.py Mon Feb 02 01:34:35 2009 +0100 @@ -197,9 +197,11 @@ Request a new object with the given class 'cls' and with 'n' attributes. """ + self.new_op(LoadConst(cls)) + + # NOTE: Provide __call__ details, if any. # NOTE: Object headers are one location. - self.new_op(LoadConst(cls)) self.new_op(MakeObject(n + 1)) # Name-related methods. @@ -517,36 +519,45 @@ try: attr = self.unit.parent.instance_attributes()[attrname] self.new_op(AttrInstruction(attr)) + return # Or generate an instruction operating on a class attribute. except KeyError: - attr = self.unit.parent.all_attributes()[attrname] - - # Switch the context if the class attribute is compatible with - # the instance. - - if attr.defined_within_hierarchy(): - - # Only permit loading (not storing) of class attributes via self. - - if AddressContextInstruction is not None: - self.new_op(AddressContextInstruction(attr)) + + try: + attr = self.unit.parent.all_attributes()[attrname] + + # Switch the context if the class attribute is compatible with + # the instance. + + if attr.defined_within_hierarchy(): + + # Only permit loading (not storing) of class attributes via self. + + if AddressContextInstruction is not None: + self.new_op(AddressContextInstruction(attr)) + else: + raise TranslateError(self.module.full_name(), node, + "Storing of class attribute %r via self not permitted." % attrname) + + # Preserve the context if the class attribute comes from an + # incompatible class. + else: - raise TranslateError(self.module.full_name(), node, - "Storing of class attribute %r via self not permitted." % attrname) - - # Preserve the context if the class attribute comes from an - # incompatible class. - - else: - if AddressInstruction is not None: - self.new_op(AddressInstruction(attr)) - else: - raise TranslateError(self.module.full_name(), node, - "Storing of class attribute %r via self not permitted." % attrname) - - return + if AddressInstruction is not None: + self.new_op(AddressInstruction(attr)) + else: + raise TranslateError(self.module.full_name(), node, + "Storing of class attribute %r via self not permitted." % attrname) + + return + + # Or delegate the attribute access to a general instruction + # since the kind of attribute cannot be deduced. + + except KeyError: + pass # Otherwise, perform a normal operation. diff -r 168c6f68045d -r 5c8320ec4c46 micropython/common.py --- a/micropython/common.py Mon Jan 26 01:25:30 2009 +0100 +++ b/micropython/common.py Mon Feb 02 01:34:35 2009 +0100 @@ -84,6 +84,23 @@ def __repr__(self): return "Block(%r, location=%r)" % (id(self), self.location) +# Program data representations. + +class DataObject: + + "A representation of a raw program data object." + + def __init__(self, classcode, attrcode, codeaddr, codedetails, instance, name): + self.classcode = classcode + self.attrcode = attrcode + self.codeaddr = codeaddr + self.codedetails = codedetails + self.instance = instance + self.name = name + + def __repr__(self): + return "%r # %s" % ((self.classcode, self.attrcode, self.codeaddr, self.codedetails, self.instance), self.name) + # Inspection representations. class AtLeast: diff -r 168c6f68045d -r 5c8320ec4c46 rsvp.py --- a/rsvp.py Mon Jan 26 01:25:30 2009 +0100 +++ b/rsvp.py Mon Feb 02 01:34:35 2009 +0100 @@ -52,6 +52,8 @@ current callable """ +from micropython.common import DataObject # for creating "nice" new objects + class IllegalInstruction(Exception): pass @@ -114,7 +116,8 @@ # Native class constants. - self.int_class = objlist.access("__builtins__", "int").value.location + cls = objlist.access("__builtins__", "int") + self.int_class = cls and cls.value.location # Debugging methods. @@ -342,8 +345,8 @@ def LoadAttrIndex(self): context, ref = self.value - classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) - element = self.objlist[classcode + self.operand] + data = self.load(ref) + element = self.objlist[data.classcode + self.operand] attr_index, class_attr, replace_context, offset = element if attr_index == self.operand: if class_attr: @@ -359,8 +362,8 @@ def StoreAttrIndex(self): context, ref = self.value - classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) - element = self.objlist[classcode + self.operand] + data = self.load(ref) + element = self.objlist[data.classcode + self.operand] attr_index, class_attr, replace_context, offset = element if attr_index == self.operand: if class_attr: @@ -390,8 +393,8 @@ def StoreFrameIndex(self): frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame - classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) - element = self.objlist[classcode + self.operand] + data = self.load(ref) + element = self.objlist[data.classcode + self.operand] attr_index, offset = element if attr_index == self.operand: self.frame_stack[frame + offset] = self.value @@ -400,14 +403,14 @@ def LoadCallable(self): context, ref = self.value - classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) - self.callable = codeaddr, codedetails + data = self.load(ref) + self.callable = data.codeaddr, data.codedetails def StoreCallable(self): context, ref = self.value # NOTE: Should improve the representation and permit direct saving. - classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) - self.save(ref, (classcode, attrcode) + self.callable + (instance,)) + data = self.load(ref) + self.save(ref, (data.classcode, data.attrcode) + self.callable + (data.instance,)) def LoadContext(self): context, ref = self.value @@ -417,7 +420,7 @@ operand = self.operand frame = self.invocation_sp_stack[-1] context, ref = self.value - classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) + data = self.load(ref) # Support sliding of the frame to exclude any inappropriate context. @@ -425,12 +428,12 @@ self.invocation_sp_stack[-1] += 1 operand -= 1 else: - context_classcode, context_attrcode, context_codeaddr, context_codedetails, context_instance = self.load(context) - if not context_instance: + context_data = self.load(context) + if not context_data.instance: self.invocation_sp_stack[-1] += 1 operand -= 1 - nargs, ndefaults = codedetails + nargs, ndefaults = data.codedetails if not (nargs - ndefaults <= operand <= nargs): raise Exception, "CheckFrame %r" % (nargs - ndefaults, self.operand, nargs) @@ -519,20 +522,20 @@ # Common implementation details. def _CheckInstance(self, ref, cls): - classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) - target_classcode, target_attrcode, target_codeaddr, target_codedetails, target_instance = self.load(cls) + data = self.load(ref) + target_data = self.load(cls) # Find the table entry for the descendant. - element = self.objlist[target_classcode + attrcode] + element = self.objlist[target_data.classcode + data.attrcode] attr_index, class_attr, replace_context, offset = element - return attr_index == attrcode + return attr_index == data.attrcode def _MakeObject(self, size, ref): - classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) + data = self.load(ref) addr = self.new(size) # Set the header to resemble the class. - self.save(addr, (classcode, attrcode, None, None, 1)) # NOTE: __call__ method not yet provided. + self.save(addr, DataObject(data.classcode, data.attrcode, None, None, 1, data.name)) # NOTE: __call__ method not yet provided. return addr # Native function implementations. diff -r 168c6f68045d -r 5c8320ec4c46 tests/call_instance.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/call_instance.py Mon Feb 02 01:34:35 2009 +0100 @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +class C: + def __call__(self): + return "called" + +c = C() +c() + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 168c6f68045d -r 5c8320ec4c46 tests/mixins.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/mixins.py Mon Feb 02 01:34:35 2009 +0100 @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +class A: + def a(self): + return self.x + +class B(A): + x = 123 + +class C(A): + def __init__(self, x): + self.x = x + +b = B() +c = C(456) + +p = b.a() +q = c.a() + +# vim: tabstop=4 expandtab shiftwidth=4