1.1 --- a/micropython/deduce.py Thu Oct 24 23:30:41 2013 +0200
1.2 +++ b/micropython/deduce.py Fri Oct 25 00:59:37 2013 +0200
1.3 @@ -36,6 +36,7 @@
1.4 self.program = program
1.5 self.objtable = program.get_object_table()
1.6 self.units = []
1.7 + self.expr = None
1.8
1.9 def get_unit(self):
1.10 return self.units[-1]
1.11 @@ -105,7 +106,9 @@
1.12 # cases.
1.13
1.14 target = node._expr
1.15 - instance_target = isinstance(target, Const)
1.16 + instance_target = isinstance(target, TypedInstance)
1.17 + typed_instance_attr = isinstance(target, Attr) and isinstance(target.get_value(), TypedInstance)
1.18 + self_access = self.provides_self_access(node, unit)
1.19
1.20 # Attempt to deduce attributes from explicit annotations.
1.21
1.22 @@ -143,14 +146,34 @@
1.23 node._access_type = "impossible"
1.24 return
1.25
1.26 - # Attributes of self, which is by definition an instance.
1.27 + # Attributes of self, which is by definition an instance, or typed
1.28 + # instances, which act somewhat like self in that their properties
1.29 + # should be known.
1.30 +
1.31 + if instance_target or typed_instance_attr or self_access:
1.32
1.33 - if self.provides_self_access(node, unit):
1.34 + if instance_target:
1.35 + value = target
1.36 + elif typed_instance_attr:
1.37 + value = target.get_value()
1.38 +
1.39 + # Find the class of the instance.
1.40 +
1.41 + if instance_target or typed_instance_attr:
1.42 + if isinstance(value, Const):
1.43 + cls = get_constant_class(value.get_class_name())
1.44 + else:
1.45 + cls = value.cls
1.46 + else:
1.47 + cls = unit.parent
1.48
1.49 # Find instance attributes.
1.50
1.51 - attr = unit.parent.instance_attributes().get(node.attrname)
1.52 - attrs = filter(None, [cls.instance_attributes().get(node.attrname) for cls in unit.parent.descendants])
1.53 + attr = cls.instance_attributes().get(node.attrname)
1.54 +
1.55 + # Where self is involved, descendants can also provide attributes.
1.56 +
1.57 + attrs = self_access and filter(None, [desc.instance_attributes().get(node.attrname) for desc in cls.descendants]) or []
1.58
1.59 # A "leaf" class whose instances provide an attribute.
1.60
1.61 @@ -185,7 +208,7 @@
1.62 # The context will be overridden for compatible class attributes
1.63 # only.
1.64
1.65 - attr = unit.parent.get(node.attrname)
1.66 + attr = cls.all_class_attributes().get(node.attrname)
1.67
1.68 if attr:
1.69
1.70 @@ -195,6 +218,7 @@
1.71 if self.provides_constant_result(attr.get_value()):
1.72 node._access_type = "constant"
1.73 node._value_deduced = attr.get_value()
1.74 + node._set_context = "set"
1.75 return
1.76
1.77 # Compatible class attributes.
1.78 @@ -287,6 +311,32 @@
1.79
1.80 visitAssAttr = visitGetattr = _visitAttr
1.81
1.82 + def visitAssign(self, node):
1.83 + self.expr = self.dispatch(node.expr)
1.84 + for n in node.nodes:
1.85 + self.dispatch(n)
1.86 +
1.87 + def visitAssName(self, node):
1.88 + if self.expr:
1.89 + if isinstance(self.expr, Attr):
1.90 + expr = self.expr.get_value()
1.91 + elif isinstance(self.expr, TypedInstance):
1.92 + expr = self.expr
1.93 + else:
1.94 + return
1.95 + else:
1.96 + return
1.97 +
1.98 + attr = node._attr
1.99 +
1.100 + if attr:
1.101 + value = attr.get_value()
1.102 +
1.103 + # Need to replace any uncertain value with a concrete value.
1.104 +
1.105 + if value and isinstance(value, Instance) and not isinstance(value, TypedInstance):
1.106 + attr.context_values = set([get_context_and_value(expr)])
1.107 +
1.108 def visitCallFunc(self, node):
1.109
1.110 "Identify any concrete types involved with instantiation."
1.111 @@ -301,7 +351,7 @@
1.112 if attr:
1.113 value = attr.get_value()
1.114 if value and isinstance(value, Class):
1.115 - return attr
1.116 + return TypedInstance(value)
1.117
1.118 # Convenience functions.
1.119