# HG changeset patch # User Paul Boddie # Date 1304885728 -7200 # Node ID 0044fb55ab2b46e8a92336148148a8d94559782c # Parent 932a3592c796ac0658b6d074e51bd466e806c3d5 Introduced speculative attribute coverage for getattr as a special case. Moved attribute coverage expansion for deduced objects according to attribute usage into a separate method in the importer. Fixed the native _getattr function to retrieve class attributes via instances with the correct context information. diff -r 932a3592c796 -r 0044fb55ab2b micropython/__init__.py --- a/micropython/__init__.py Sun May 08 20:31:23 2011 +0200 +++ b/micropython/__init__.py Sun May 08 22:15:28 2011 +0200 @@ -573,6 +573,31 @@ self.attribute_users_visited.add(from_name) + # The getattr function is a special case: it can potentially reference + # any known attribute. Since accessor attributes must be known + # constants, the intersection of known constants and attributes is used + # to build a set of objects that might be referenced by getattr. + + if from_name == "__builtins__.getattr": + all_attributes = set(objtable.attribute_names()) + all_string_constants = set([const.get_value() for const in self.constants() if const.value_type_name() == "__builtins__.str"]) + all_attribute_constants = all_attributes.intersection(all_string_constants) + + # Get the types supporting each attribute and visit the referenced + # objects. + + all_objtypes = set() + + for attrname in all_attribute_constants: + objtypes = objtable.any_possible_objects_plus_status([attrname]) + all_objtypes.update(objtypes) + + # Attribute assignment does not take place, so an empty list of + # values is given. + + self._collect_attributes_for_types(from_name, objtable, all_objtypes, + [{attrname : []} for attrname in all_attribute_constants]) + # Get name references and find possible objects which support such # combinations of attribute names. @@ -600,48 +625,7 @@ user._attrtypes = {} user._attrtypes[name] = all_objtypes - - # For each suggested object type, consider each attribute given by - # the names. - - for objname, is_static in all_objtypes: - for attrnames in usage: - for attrname, attrvalues in attrnames.items(): - - # Test for the presence of an attribute on the suggested - # object type. - - try: - attr = objtable.access(objname, attrname) - except TableError: - #print "Warning: object type %r does not support attribute %r" % (objname, attrname) - continue - - # Get the real identity of the attribute in order to - # properly collect usage from it. - - parent = attr.parent - if isinstance(parent, micropython.data.Instance): - parentname = objname - else: - parentname = parent.full_name() - - # Test for assignment. - - if attrvalues: - for attrvalue in attrvalues: - parent.set(attrname, attrvalue, 0) - - # Visit attributes of objects known to be used. - - if parentname in self.attributes_used: - self.use_attribute(parentname, attrname) - self._collect_attributes_from(from_name, parentname, attrname, objtable) - - # Record attributes of other objects for potential visiting. - - else: - self.add_attribute_to_visit(parentname, attrname) + self._collect_attributes_for_types(from_name, objtable, all_objtypes, usage) # Get specific name references and visit the referenced objects. @@ -669,6 +653,54 @@ self.use_attribute(from_name, attrname) self._collect_attributes_from(from_name, from_name, attrname, objtable) + def _collect_attributes_for_types(self, from_name, objtable, objtypes, usage): + + """ + For the unit known as 'from_name' and using the 'objtable' to validate + each attribute, identify and attempt to visit attributes found for each + of the suggested object types given by 'objtypes' and the 'usage' + provided. + """ + + for objname, is_static in objtypes: + for attrnames in usage: + for attrname, attrvalues in attrnames.items(): + + # Test for the presence of an attribute on the suggested + # object type. + + try: + attr = objtable.access(objname, attrname) + except TableError: + #print "Warning: object type %r does not support attribute %r" % (objname, attrname) + continue + + # Get the real identity of the attribute in order to + # properly collect usage from it. + + parent = attr.parent + if isinstance(parent, micropython.data.Instance): + parentname = objname + else: + parentname = parent.full_name() + + # Test for assignment. + + if attrvalues: + for attrvalue in attrvalues: + parent.set(attrname, attrvalue, 0) + + # Visit attributes of objects known to be used. + + if parentname in self.attributes_used: + self.use_attribute(parentname, attrname) + self._collect_attributes_from(from_name, parentname, attrname, objtable) + + # Record attributes of other objects for potential visiting. + + else: + self.add_attribute_to_visit(parentname, attrname) + # Constant accounting. def init_predefined_constants(self): diff -r 932a3592c796 -r 0044fb55ab2b rsvplib.py --- a/rsvplib.py Sun May 08 20:31:23 2011 +0200 +++ b/rsvplib.py Sun May 08 22:15:28 2011 +0200 @@ -483,7 +483,7 @@ index = self.machine.load(name_value.ref + self.instance_data_offset + 1) - # NOTE: This is very much like LoadAttrIndex. + # NOTE: This is very much like LoadAttrIndexContextCond. data = self.machine.load(obj_value.ref) element = self.machine.objlist[data.classcode + index] @@ -492,7 +492,11 @@ attr_index, static_attr, offset = element if attr_index == index: if static_attr: - self.machine.result = self.machine.load(offset) # offset is address of class/module attribute + loaded_value = self.machine.load(offset) # offset is address of class/module attribute + if data.attrcode is None: # absent attrcode == class/module + self.machine.result = loaded_value + else: + self.machine.result = self.machine._LoadAddressContextCond(loaded_value.context, loaded_value.ref, obj_value.ref) else: self.machine.result = self.machine.load(obj_value.ref + offset) return