# HG changeset patch # User Paul Boddie # Date 1474836244 -7200 # Node ID 760d93c5c2e9f8b7ecde62d0109da5c62cc84640 # Parent 43f1d3df67a0fd5e38af24f367079f112c2aa7b6 Attempt to define attribute access plans. diff -r 43f1d3df67a0 -r 760d93c5c2e9 deducer.py --- a/deducer.py Sat Sep 24 22:44:45 2016 +0200 +++ b/deducer.py Sun Sep 25 22:44:04 2016 +0200 @@ -19,7 +19,7 @@ this program. If not, see . """ -from common import get_attrname_from_location, get_attrnames, \ +from common import first, get_attrname_from_location, get_attrnames, \ init_item, make_key, sorted_output, \ CommonOutput from encoders import encode_attrnames, encode_access_location, \ @@ -136,6 +136,7 @@ self.write_mutations() self.write_accessors() self.write_accesses() + self.write_access_plans() def write_mutations(self): @@ -437,6 +438,26 @@ # Otherwise, no convenient guard can be defined. + def write_access_plans(self): + + "Each attribute access is written out as a plan." + + f_attrs = open(join(self.output, "attribute_plans"), "w") + + try: + locations = self.referenced_attrs.keys() + locations.sort() + + for location in locations: + base, traversed, attrnames, attr = self.get_access(location) + print >>f_attrs, encode_access_location(location), base, \ + ".".join(traversed) or "{}", \ + ".".join(attrnames) or "{}", \ + attr or "{}" + + finally: + f_attrs.close() + def classify_accesses(self): "For each program location, classify accesses." @@ -1615,4 +1636,59 @@ return attrs + def get_access(self, location): + + "Return details of the access at the given 'location'." + + const_access = self.const_accesses.has_key(location) + if const_access: + location = self.const_accesses[location] + + path, name, attrname_str, version = location + attrnames = attrname_str.split(".") + attrname = attrnames[0] + + # Obtain only reference information. + + attrs = [] + objtypes = [] + for attrtype, objtype, attr in self.referenced_attrs[location]: + attrs.append(attr) + objtypes.append(objtype) + + # Identify the last static attribute. + + if const_access: + base = len(objtypes) == 1 and first(objtypes) + else: + ref = self.importer.identify("%s.%s" % (path, name)) + if not ref: + base = name + else: + base = ref.get_origin() + + traversed = [] + + # Traverse remaining attributes. + + while len(attrs) == 1: + attr = first(attrs) + + traversed.append(attrname) + del attrnames[0] + + if not attrnames: + break + + if attr.static(): + base = attr.get_origin() + traversed = [] + + attrname = attrnames[0] + attrs = self.importer.get_attributes(attr, attrname) + else: + attr = None + + return base, traversed, attrnames, attr and attr.get_name() + # vim: tabstop=4 expandtab shiftwidth=4 diff -r 43f1d3df67a0 -r 760d93c5c2e9 tests/chain.py --- a/tests/chain.py Sat Sep 24 22:44:45 2016 +0200 +++ b/tests/chain.py Sun Sep 25 22:44:04 2016 +0200 @@ -2,7 +2,8 @@ class D: class E: def m(self, x): - return x + self.x = x + return self.x.__len__ n = 123 p = "456" @@ -16,7 +17,7 @@ i = C.D.p.__len__ inst = e() method = inst.m - return method(5) + return method("5") result1 = main() c = C @@ -28,4 +29,4 @@ i = C.D.p.__len__ inst = e() method = inst.m -result2 = method(5) +result2 = method("5")