1.1 --- a/micropython/__init__.py Sat Jun 29 01:28:12 2013 +0200
1.2 +++ b/micropython/__init__.py Sat Jun 29 21:12:51 2013 +0200
1.3 @@ -247,6 +247,7 @@
1.4
1.5 self.constant_values = {}
1.6 self.constants_used = set()
1.7 + self.all_constants_used = set()
1.8 self.constant_references = {}
1.9 self.init_predefined_constants()
1.10
1.11 @@ -264,7 +265,7 @@
1.12
1.13 self.attribute_users_visited = set()
1.14 self.attributes_to_visit = {}
1.15 - self.attribute_users_seen = 0
1.16 + self.collecting_dynamic = False
1.17
1.18 # Attribute usage type deduction failures.
1.19
1.20 @@ -445,7 +446,8 @@
1.21 # to be used.
1.22
1.23 if "__builtins__.getattr" in self.attribute_users_visited:
1.24 - self._collect_attributes("__builtins__.getattr", objtable)
1.25 + self.collecting_dynamic = True
1.26 + self._collect_attributes_from_getattr(objtable)
1.27
1.28 def add_attribute_to_visit(self, objname, attrname):
1.29
1.30 @@ -473,6 +475,38 @@
1.31 self.inferred_name_references[from_name].add((objname, attrname))
1.32 self._collect_attributes(objname + "." + attrname, objtable)
1.33
1.34 + def _collect_attributes_from_getattr(self, objtable):
1.35 +
1.36 + """
1.37 + The getattr function is a special case: it can potentially reference
1.38 + any known attribute. Since accessor attributes must be known
1.39 + constants, the intersection of known constants and attributes is used
1.40 + to build a set of objects that might be referenced by getattr.
1.41 + """
1.42 +
1.43 + all_attributes = set(objtable.attribute_names())
1.44 + all_string_constants = set([const.get_value() for const in self.constants_used
1.45 + if const.value_type_name() == "__builtins__.str"])
1.46 + all_attribute_constants = all_attributes.intersection(all_string_constants)
1.47 +
1.48 + self.all_constants_used.update(self.constants_used)
1.49 + self.constants_used = set()
1.50 +
1.51 + # Get the types supporting each attribute and visit the referenced
1.52 + # objects.
1.53 +
1.54 + all_objtypes = set()
1.55 +
1.56 + for attrname in all_attribute_constants:
1.57 + objtypes = objtable.any_possible_objects_plus_status([attrname])
1.58 + all_objtypes.update(objtypes)
1.59 +
1.60 + # Attribute assignment does not take place, so an empty list of
1.61 + # values is given.
1.62 +
1.63 + self._collect_attributes_for_types("__builtins__.getattr", objtable, all_objtypes,
1.64 + [{attrname : []} for attrname in all_attribute_constants])
1.65 +
1.66 def _collect_attributes(self, from_name, objtable):
1.67
1.68 """
1.69 @@ -481,47 +515,21 @@
1.70 types.
1.71 """
1.72
1.73 - if from_name != "__builtins__.getattr" and from_name in self.attribute_users_visited or \
1.74 - from_name == "__builtins__.getattr" and len(self.attribute_users_visited) == self.attribute_users_seen:
1.75 + if from_name != "__builtins__.getattr" and from_name in self.attribute_users_visited:
1.76 return
1.77
1.78 self.attribute_users_visited.add(from_name)
1.79
1.80 + if from_name == "__builtins__.getattr":
1.81 + if self.collecting_dynamic:
1.82 + self._collect_attributes_from_getattr(objtable)
1.83 + return
1.84 +
1.85 # Get constant references.
1.86
1.87 for const in self.constant_references.get(from_name, []):
1.88 self.constants_used.add(const)
1.89
1.90 - # The getattr function is a special case: it can potentially reference
1.91 - # any known attribute. Since accessor attributes must be known
1.92 - # constants, the intersection of known constants and attributes is used
1.93 - # to build a set of objects that might be referenced by getattr.
1.94 -
1.95 - if from_name == "__builtins__.getattr":
1.96 -
1.97 - # Note the number of attribute users visited at this point.
1.98 -
1.99 - self.attribute_users_seen = len(self.attribute_users_visited)
1.100 -
1.101 - all_attributes = set(objtable.attribute_names())
1.102 - all_string_constants = set([const.get_value() for const in self.constants() if const.value_type_name() == "__builtins__.str"])
1.103 - all_attribute_constants = all_attributes.intersection(all_string_constants)
1.104 -
1.105 - # Get the types supporting each attribute and visit the referenced
1.106 - # objects.
1.107 -
1.108 - all_objtypes = set()
1.109 -
1.110 - for attrname in all_attribute_constants:
1.111 - objtypes = objtable.any_possible_objects_plus_status([attrname])
1.112 - all_objtypes.update(objtypes)
1.113 -
1.114 - # Attribute assignment does not take place, so an empty list of
1.115 - # values is given.
1.116 -
1.117 - self._collect_attributes_for_types(from_name, objtable, all_objtypes,
1.118 - [{attrname : []} for attrname in all_attribute_constants])
1.119 -
1.120 # Get name references and find possible objects which support such
1.121 # combinations of attribute names.
1.122
1.123 @@ -729,7 +737,7 @@
1.124
1.125 "Return a list of constants."
1.126
1.127 - return self.constants_used
1.128 + return self.all_constants_used
1.129
1.130 # Import methods.
1.131