# HG changeset patch # User Paul Boddie # Date 1204587713 -3600 # Node ID 129e39a901170bceea8ddd8e0f24d1904a399a5a # Parent 8422dd84e10478166472d34f7bf03292b0fc4a2f Added notes about attributes and contexts. Changed most data classes to record the parent object in each instance, excluding UnresolvedName whose instances often have no legitimate parent object. Made various methods return a dictionary instead of the instance itself for a collection of attributes, since although Class and Function support a dictionary API, it is usually more convenient to obtain a genuine dictionary. Added registration of "descendant" classes for each class, potentially enabling support for self attribute access optimisations. Added parameter local initialisation employing initial single assignment. diff -r 8422dd84e104 -r 129e39a90117 README.txt --- a/README.txt Wed Feb 27 23:17:19 2008 +0100 +++ b/README.txt Tue Mar 04 00:41:53 2008 +0100 @@ -61,7 +61,7 @@ Instance-originating Preserved Methods retain their original context attribute -There is some scope for simplifying the above, to the detriment of Python +There may be some scope for simplifying the above, to the detriment of Python compatibility, since the unbound vs. bound methods situation can be confusing. Objects @@ -165,7 +165,25 @@ Attribute Operations -------------------- -Attribute access needs to go through the attribute lookup table. +Attribute access needs to go through the attribute lookup table. Some +optimisations are possible and are described in the appropriate section. + +One important aspect of attribute access is the appropriate setting of the +context in the acquired attribute value. From the table describing the +acquisition of values, it is clear that the principal exception is that where +a class-originating attribute is accessed on an instance. Consequently, the +following algorithm could be employed once an attribute has been located: + + 1. If the attribute's context is a special value, indicating that it should + be replaced upon instance access, then proceed to the next step; + otherwise, acquire both the context and the object as they are. + + 2. If the accessor is an instance, use that as the value's context, acquiring + only the object from the attribute. + +Where accesses can be determined ahead of time (as discussed in the +optimisations section), the above algorithm may not necessarily be employed in +the generated code for some accesses. Instruction Evaluation Model ============================ diff -r 8422dd84e104 -r 129e39a90117 docs/rationale.txt --- a/docs/rationale.txt Wed Feb 27 23:17:19 2008 +0100 +++ b/docs/rationale.txt Tue Mar 04 00:41:53 2008 +0100 @@ -101,3 +101,16 @@ * Construct efficient run-time representations * Predictable content means that access can be optimised * No shadowing means that only a single lookup is necessary + +References, attributes and values + + * Almost everything can be considered as a kind of attribute: + * Module, class, instance + * Local variable is the exception + * Acquired attributes are "values": + * An object being manipulated + * Its context + * Most kinds of values have no real context: + * Module and class attributes, locals + * The exception: + * Instance attributes diff -r 8422dd84e104 -r 129e39a90117 micropython/inspect.py --- a/micropython/inspect.py Wed Feb 27 23:17:19 2008 +0100 +++ b/micropython/inspect.py Tue Mar 04 00:41:53 2008 +0100 @@ -151,6 +151,10 @@ attr.assignments = 1 attr.assignment_values.add(value) + "A specialised set operation for parameters." + + set_parameter = set_module + def _set(self, name, value): "The underlying set operation associating 'name' with 'value'." @@ -208,9 +212,9 @@ def full_name(self): if self.name is not None: - return self.parent_name + "." + self.name + return self.parent.full_name() + "." + self.name else: - return self.parent_name + return self.parent.full_name() # Program data structures. @@ -282,15 +286,16 @@ "An inspected class." - def __init__(self, name, parent_name, global_namespace=None, node=None): + def __init__(self, name, parent, global_namespace=None, node=None): NamespaceDict.__init__(self, global_namespace) self.name = name - self.parent_name = parent_name + self.parent = parent self.node = node - # Superclasses and attributes. + # Superclasses, descendants and attributes. self.bases = [] + self.descendants = set() self.instattr = set() # instance attributes self.relocated = set() # attributes which do not have the same # position as those of the same name in @@ -312,9 +317,9 @@ def __repr__(self): if self.location is not None: - return "Class(%r, %r, location=%r)" % (self.name, self.parent_name, self.location) + return "Class(%r, %r, location=%r)" % (self.name, self.parent, self.location) else: - return "Class(%r, %r)" % (self.name, self.parent_name) + return "Class(%r, %r)" % (self.name, self.parent) def finalise_attributes(self): @@ -327,10 +332,16 @@ def add_base(self, base): self.bases.append(base) + base.add_descendant(self) def add_instance_attribute(self, name): self.instattr.add(name) + def add_descendant(self, cls): + self.descendants.add(cls) + for base in self.bases: + base.add_descendant(cls) + "Return the attribute names provided by this class only." class_attribute_names = NamespaceDict.keys @@ -340,7 +351,7 @@ "Return class attributes provided by this class only." self.finalise_class_attributes() - return self + return dict(self) def all_class_attribute_names(self): @@ -548,10 +559,10 @@ "An inspected function." - def __init__(self, name, parent_name, argnames, has_star, has_dstar, global_namespace=None, node=None): + def __init__(self, name, parent, argnames, has_star, has_dstar, global_namespace=None, node=None): NamespaceDict.__init__(self, global_namespace) self.name = name - self.parent_name = parent_name + self.parent = parent self.argnames = argnames self.has_star = has_star self.has_dstar = has_dstar @@ -575,16 +586,16 @@ if isinstance(name, tuple): self._add_parameters(name) else: - self[name] = None + self.set_parameter(name, None) def __repr__(self): if self.location is not None: return "Function(%r, %r, %r, %r, %r, location=%r)" % ( - self.name, self.parent_name, self.argnames, self.has_star, self.has_dstar, self.location + self.name, self.parent, self.argnames, self.has_star, self.has_dstar, self.location ) else: return "Function(%r, %r, %r, %r, %r)" % ( - self.name, self.parent_name, self.argnames, self.has_star, self.has_dstar + self.name, self.parent, self.argnames, self.has_star, self.has_dstar ) def make_global(self, name): @@ -609,7 +620,7 @@ "Return a dictionary mapping names to local and parameter details." - return self + return dict(self) def locals(self): @@ -622,7 +633,7 @@ del self.localnames[name] return self.localnames -class UnresolvedName(NamespaceDict, Naming): +class UnresolvedName(NamespaceDict): "A module, class or function which was mentioned but could not be imported." @@ -640,6 +651,12 @@ def __repr__(self): return "UnresolvedName(%r, %r)" % (self.name, self.parent_name) + def full_name(self): + if self.name is not None: + return self.parent_name + "." + self.name + else: + return self.parent_name + class Module(NamespaceDict): "An inspected module's core details." @@ -685,7 +702,7 @@ "Return a dictionary mapping names to module attributes." - return self + return dict(self) def constants(self): @@ -850,7 +867,7 @@ if self.namespaces: print "Class %r in %r is not global: ignored." % (node.name, self.namespaces[-1].full_name()) else: - cls = Class(node.name, self.get_parent().full_name(), self, node) + cls = Class(node.name, self.get_parent(), self, node) # Visit the base class expressions, attempting to find concrete # definitions of classes. @@ -946,7 +963,7 @@ def visitFunction(self, node): function = Function( node.name, - self.get_parent().full_name(), + self.get_parent(), node.argnames, (node.flags & 4 != 0), (node.flags & 8 != 0), @@ -1151,16 +1168,16 @@ 'frozenset', 'int', # 'list', 'long', 'object', 'set', 'slice', 'str', 'tuple', 'type', 'unicode', 'xrange']: - self.store(key, Class(key, self.full_name(), self)) + self.store(key, Class(key, self, self)) # NOTE: Temporary measure - provide detailed built-ins. - cls = Class("list", self.full_name(), self) - cls.set("__iter__", Function("__iter__", cls.full_name(), [], 0, 0, cls)) + cls = Class("list", self, self) + cls.set("__iter__", Function("__iter__", cls, [], 0, 0, cls)) self.store("list", cls) - cls = Class("listiterator", self.full_name(), self) - cls.set("next", Function("next", cls.full_name(), [], 0, 0, cls)) + cls = Class("listiterator", self, self) + cls.set("next", Function("next", cls, [], 0, 0, cls)) self.store("listiterator", cls) # NOTE: Incomplete: some functions have more than one parameter. @@ -1173,7 +1190,7 @@ 'open', 'ord', 'pow', 'property', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'setattr', 'sorted', 'staticmethod', 'sum', 'super', 'unichr', 'vars', 'zip']: - self[key] = Function(key, self.full_name(), ['arg'], 0, 0, self) + self[key] = Function(key, self, ['arg'], 0, 0, self) def store(self, name, obj): self.set(name, obj)