# HG changeset patch # User Paul Boddie # Date 1382834385 -7200 # Node ID 108075b4c4c41daf4beaea85fbdfd86d313e9e90 # Parent f65236401d4ed57240ae6db0dd680a00f7a0ddd3 Introduced workarounds to prevent special local attributes from having their results "materialised" prematurely, adding to local attribute objects the underlying generic namespace entry for each local name so that inspection-time operations can still make sense, but where precise assignment information is preserved until deduction. diff -r f65236401d4e -r 108075b4c4c4 micropython/data.py --- a/micropython/data.py Sun Oct 27 01:54:07 2013 +0200 +++ b/micropython/data.py Sun Oct 27 02:39:45 2013 +0200 @@ -188,7 +188,7 @@ users = self.attribute_users[-1] if users.has_key(name): - return LocalAttr(None, self, name, nodes=users[name]) + return LocalAttr(None, self, name, nodes=users[name], attr=attr) else: return attr @@ -285,8 +285,12 @@ for user in users[name]: user._values = user._values or {} - attr = user._values[name] = Attr(None, self, name) - self._set_using_attr(attr, attr_or_value) # enforce single assignment + if isinstance(attr_or_value, BaseAttr): + attr = attr_or_value + else: + attr = Attr(None, self, name) + self._set_using_attr(attr, attr_or_value) # enforce single assignment + user._values[name] = attr # Add and/or obtain the namespace entry. @@ -312,6 +316,8 @@ # Attempt to fix the context if not explicitly defined. if isinstance(attr_or_value, BaseAttr): + if isinstance(attr_or_value, LocalAttr): + attr_or_value = attr_or_value.attr return self.get_updated_context_values(attr_or_value.get_context_values()) else: return self.get_updated_context_values([get_context_and_value(attr_or_value)]) @@ -561,9 +567,10 @@ later point. """ - def __init__(self, position, parent, name, nodes): + def __init__(self, position, parent, name, nodes, attr): BaseAttr.__init__(self, position, parent, name) self.nodes = nodes or set() + self.attr = attr self.users = None def _get_defining_users(self): diff -r f65236401d4e -r 108075b4c4c4 micropython/inspect.py --- a/micropython/inspect.py Sun Oct 27 01:54:07 2013 +0200 +++ b/micropython/inspect.py Sun Oct 27 02:39:45 2013 +0200 @@ -677,7 +677,10 @@ # Attempt to identify the nature of the attribute. if isinstance(expr, BaseAttr): - value = expr.get_value() + if isinstance(expr, LocalAttr): + value = expr.attr.get_value() + else: + value = expr.get_value() # Get the attribute and record its usage. # NOTE: Need to provide concrete values for things like base classes @@ -863,7 +866,10 @@ # Record the attribute on the presumed target. if isinstance(expr, BaseAttr): - value = expr.get_value() + if isinstance(expr, LocalAttr): + value = expr.attr.get_value() + else: + value = expr.get_value() if expr.name == "self": self.store_instance_attr(attrname) @@ -928,10 +934,17 @@ # NOTE: this is merely creating aliases for such methods. if isinstance(self.get_namespace(), (Class, Module)): - if not isinstance(self.expr, BaseAttr) or not isinstance(self.expr.get_value(), Function): + if isinstance(self.expr, BaseAttr): + if isinstance(self.expr, LocalAttr): + value = self.expr.attr.get_value() + else: + value = self.expr.get_value() + else: + value = None + if not value or not isinstance(value, Function): self.use_specific_attribute(None, node.name) else: - fn = self.expr.get_value() + fn = value ns = self.get_namespace().full_name() self.use_specific_attribute(fn.parent.full_name(), fn.name, "%s.%s" % (ns, node.name)) @@ -1011,12 +1024,17 @@ # Each base class must be constant and known at compile-time. if isinstance(expr, BaseAttr): - if expr.assignments != 1: + if isinstance(expr, LocalAttr): + value = expr.attr.get_value() + else: + value = expr.get_value() + + if not value: raise InspectError("Base class %r for %r is not constant: %r" % (base, cls.full_name(), expr)) - elif not isinstance(expr.get_value(), Class): - raise InspectError("Base class %r for %r is not a class: %r" % (base, cls.full_name(), expr.get_value())) + elif not isinstance(value, Class): + raise InspectError("Base class %r for %r is not a class: %r" % (base, cls.full_name(), value)) else: - cls.add_base(expr.get_value()) + cls.add_base(value) # Where no expression value is available, the base class is # not identifiable. @@ -1378,8 +1396,8 @@ def visitName(self, node): attr = self.get_namespace().get_using_node(node.name, node) or make_instance() - node._attr = self.get_namespace().get_for_local(node.name) or make_instance() - return attr + node._attr = self.get_namespace().get_for_local(node.name) or attr + return node._attr def visitNot(self, node): self.use_name("__bool__", node)