1.1 --- a/importer.py Mon Sep 05 00:12:56 2016 +0200
1.2 +++ b/importer.py Mon Sep 05 19:50:21 2016 +0200
1.3 @@ -169,6 +169,14 @@
1.4
1.5 self.objects[name] = ref
1.6
1.7 + # Identification of both stored object names and name references.
1.8 +
1.9 + def identify(self, name):
1.10 +
1.11 + "Identify 'name' using stored object and external name records."
1.12 +
1.13 + return self.objects.get(name) or self.all_name_references.get(name)
1.14 +
1.15 # Indirect object retrieval.
1.16
1.17 def get_attributes(self, ref, attrname):
1.18 @@ -328,24 +336,25 @@
1.19
1.20 "Resolve dependencies between modules."
1.21
1.22 - resolved = {}
1.23 + for d in [self.objects, self.all_name_references]:
1.24 + resolved = {}
1.25
1.26 - for name, ref in self.objects.items():
1.27 - if ref.has_kind("<depends>"):
1.28 - found = self.find_dependency(ref)
1.29 - if found:
1.30 - resolved[name] = found
1.31 - else:
1.32 - print >>sys.stderr, "Name %s references an unknown object: %s" % (name, ref.get_origin())
1.33 + for name, ref in d.items():
1.34 + if ref.has_kind("<depends>"):
1.35 + found = self.find_dependency(ref)
1.36 + if found:
1.37 + resolved[name] = found
1.38 + else:
1.39 + print >>sys.stderr, "Name %s references an unknown object: %s" % (name, ref.get_origin())
1.40
1.41 - # Record the resolved names and identify required modules.
1.42 + # Record the resolved names and identify required modules.
1.43
1.44 - for name, ref in resolved.items():
1.45 - self.objects[name] = ref
1.46 + for name, ref in resolved.items():
1.47 + d[name] = ref
1.48
1.49 - module_name = self.get_module_provider(ref)
1.50 - if module_name:
1.51 - self.required.add(module_name)
1.52 + module_name = self.get_module_provider(ref)
1.53 + if module_name:
1.54 + self.required.add(module_name)
1.55
1.56 def find_dependency(self, ref):
1.57
2.1 --- a/inspector.py Mon Sep 05 00:12:56 2016 +0200
2.2 +++ b/inspector.py Mon Sep 05 19:50:21 2016 +0200
2.3 @@ -57,6 +57,8 @@
2.4 def __repr__(self):
2.5 return "InspectedModule(%r, %r)" % (self.name, self.importer)
2.6
2.7 + # Principal methods.
2.8 +
2.9 def parse(self, filename):
2.10
2.11 "Parse the file having the given 'filename'."
2.12 @@ -82,6 +84,10 @@
2.13
2.14 self.stop_tracking_in_module()
2.15
2.16 + # Collect external name references.
2.17 +
2.18 + self.collect_names()
2.19 +
2.20 def complete(self):
2.21
2.22 "Complete the module inspection."
2.23 @@ -98,6 +104,54 @@
2.24
2.25 self.propagate()
2.26
2.27 + # Accessory methods.
2.28 +
2.29 + def collect_names(self):
2.30 +
2.31 + "Collect the names used by each scope."
2.32 +
2.33 + for path in self.names_used.keys():
2.34 + self.collect_names_for_path(path)
2.35 +
2.36 + def collect_names_for_path(self, path):
2.37 +
2.38 + "Collect the names used by the given 'path'."
2.39 +
2.40 + names = self.names_used.get(path)
2.41 + if not names:
2.42 + return
2.43 +
2.44 + in_function = self.function_locals.has_key(path)
2.45 +
2.46 + for name in names:
2.47 + if name in predefined_constants or in_function and name in self.function_locals[path]:
2.48 + continue
2.49 +
2.50 + # Find local definitions (within static namespaces).
2.51 +
2.52 + key = "%s.%s" % (path, name)
2.53 + ref = self.get_resolved_object(key)
2.54 + if ref:
2.55 + self.importer.all_name_references[key] = self.name_references[key] = ref.alias(key)
2.56 + continue
2.57 +
2.58 + # Find global or built-in definitions.
2.59 +
2.60 + ref = self.get_resolved_global_or_builtin(name)
2.61 + if ref:
2.62 + self.importer.all_name_references[key] = self.name_references[key] = ref
2.63 + continue
2.64 +
2.65 + print >>sys.stderr, "Name not recognised: %s in %s" % (name, path)
2.66 + init_item(self.names_missing, path, set)
2.67 + self.names_missing[path].add(name)
2.68 +
2.69 + def get_resolved_global_or_builtin(self, name):
2.70 +
2.71 + "Return the resolved global or built-in object with the given 'name'."
2.72 +
2.73 + return self.get_global(name) or self.importer.get_object("__builtins__.%s" % name)
2.74 +
2.75 def set_invocation_usage(self):
2.76
2.77 """
2.78 @@ -734,7 +788,6 @@
2.79 ref = self.import_name_from_module(op, "operator")
2.80
2.81 # Record the imported name and provide the resolved name reference.
2.82 - # NOTE: Maybe use a different class.
2.83
2.84 value = ResolvedNameRef(n.name, ref)
2.85 self.set_special(n.name, value)
2.86 @@ -1198,7 +1251,7 @@
2.87 # name initialisers are resolved once a module has been inspected.
2.88
2.89 elif isinstance(value, InvocationRef):
2.90 - return None
2.91 + return value.reference()
2.92
2.93 else:
2.94 return value
3.1 --- a/modules.py Mon Sep 05 00:12:56 2016 +0200
3.2 +++ b/modules.py Mon Sep 05 19:50:21 2016 +0200
3.3 @@ -181,7 +181,6 @@
3.4
3.5 "Propagate name references for the module."
3.6
3.7 - self.importer.all_name_references.update(self.name_references)
3.8 self.importer.all_initialised_names.update(self.initialised_names)
3.9 self.importer.all_aliased_names.update(self.aliased_names)
3.10
4.1 --- a/resolving.py Mon Sep 05 00:12:56 2016 +0200
4.2 +++ b/resolving.py Mon Sep 05 19:50:21 2016 +0200
4.3 @@ -31,18 +31,6 @@
4.4
4.5 # Object resolution.
4.6
4.7 - def resolve_object(self, ref):
4.8 -
4.9 - """
4.10 - Return the given 'ref' in resolved form, given knowledge of the entire
4.11 - program.
4.12 - """
4.13 -
4.14 - if ref.has_kind("<depends>"):
4.15 - return self.importer.get_object(ref.get_origin())
4.16 - else:
4.17 - return ref
4.18 -
4.19 def get_resolved_object(self, path):
4.20
4.21 """
4.22 @@ -61,12 +49,6 @@
4.23 else:
4.24 return None
4.25
4.26 - def get_resolved_global_or_builtin(self, name):
4.27 -
4.28 - "Return the resolved global or built-in object with the given 'name'."
4.29 -
4.30 - return self.get_global(name) or self.importer.get_object("__builtins__.%s" % name)
4.31 -
4.32 # Post-inspection resolution activities.
4.33
4.34 def resolve(self):
4.35 @@ -77,22 +59,31 @@
4.36 self.resolve_class_bases()
4.37 self.check_special()
4.38 self.check_names_used()
4.39 + self.check_invocations()
4.40 self.resolve_initialisers()
4.41 self.resolve_literals()
4.42 self.remove_redundant_accessors()
4.43
4.44 def resolve_members(self):
4.45
4.46 - "Resolve any members referring to deferred references."
4.47 + """
4.48 + Resolve any members referring to deferred references, using information
4.49 + stored in the importer. This updates stored object and external name
4.50 + records in this module.
4.51 + """
4.52
4.53 - for name, ref in self.objects.items():
4.54 - if ref.has_kind("<depends>"):
4.55 - ref = self.importer.get_object(name)
4.56 + for impd, d in [
4.57 + (self.importer.objects, self.objects),
4.58 + (self.importer.all_name_references, self.name_references)
4.59 + ]:
4.60
4.61 - # Alias the member and write back to the importer.
4.62 + for name, ref in d.items():
4.63 +
4.64 + # Obtain resolved names from the importer.
4.65
4.66 - ref = ref.alias(name)
4.67 - self.importer.objects[name] = self.objects[name] = ref
4.68 + if ref.has_kind("<depends>"):
4.69 + ref = self.importer.identify(name)
4.70 + d[name] = ref
4.71
4.72 def resolve_class_bases(self):
4.73
4.74 @@ -103,7 +94,7 @@
4.75 bad = []
4.76
4.77 for base in bases:
4.78 - ref = self.resolve_object(base)
4.79 + ref = self.importer.identify(base.get_origin())
4.80
4.81 # Obtain the origin of the base class reference.
4.82
4.83 @@ -127,46 +118,44 @@
4.84
4.85 def check_names_used(self):
4.86
4.87 - "Check the names used by each function."
4.88 + "Check the external names used by each scope."
4.89
4.90 - for path in self.names_used.keys():
4.91 - self.check_names_used_for_path(path)
4.92 + for key, ref in self.name_references.items():
4.93 + path, name = key.rsplit(".", 1)
4.94 + self.resolve_accesses(path, name, ref)
4.95
4.96 - def check_names_used_for_path(self, path):
4.97 -
4.98 - "Check the names used by the given 'path'."
4.99 + def check_invocations(self):
4.100
4.101 - names = self.names_used.get(path)
4.102 - if not names:
4.103 - return
4.104 + "Find invocations amongst module data and replace their results."
4.105
4.106 - in_function = self.function_locals.has_key(path)
4.107 + # Find members and replace invocation results with values. This is
4.108 + # effectively the same as is done for initialised names, but refers to
4.109 + # any unchanging value after initialisation.
4.110
4.111 - for name in names:
4.112 - if name in predefined_constants or in_function and name in self.function_locals[path]:
4.113 - continue
4.114 + for key, ref in self.objects.items():
4.115 + if ref.has_kind("<invoke>"):
4.116 + ref = self.convert_invocation(ref)
4.117 + self.importer.objects[key] = self.objects[key] = ref
4.118
4.119 - # Find local definitions (within static namespaces).
4.120 + # Rewrite function defaults, which are effectively extra members of the
4.121 + # module.
4.122
4.123 - key = "%s.%s" % (path, name)
4.124 - ref = self.get_resolved_object(key)
4.125 - if ref:
4.126 - self.name_references[key] = ref.final() or key
4.127 - self.resolve_accesses(path, name, ref)
4.128 - continue
4.129 -
4.130 - # Find global or built-in definitions.
4.131 + defaults = self.function_defaults.items()
4.132
4.133 - ref = self.get_resolved_global_or_builtin(name)
4.134 - objpath = ref and (ref.final() or ref.get_name())
4.135 - if objpath:
4.136 - self.name_references[key] = objpath
4.137 - self.resolve_accesses(path, name, ref)
4.138 - continue
4.139 + for fname, parameters in defaults:
4.140 + l = []
4.141 + for pname, ref in parameters:
4.142 + if ref.has_kind("<invoke>"):
4.143 + ref = self.convert_invocation(ref)
4.144 + l.append((pname, ref))
4.145 + self.function_defaults[fname] = l
4.146
4.147 - print >>sys.stderr, "Name not recognised: %s in %s" % (name, path)
4.148 - init_item(self.names_missing, path, set)
4.149 - self.names_missing[path].add(name)
4.150 + def convert_invocation(self, ref):
4.151 +
4.152 + "Convert the given invocation 'ref', handling instantiation."
4.153 +
4.154 + ref = self.importer.identify(ref.get_origin())
4.155 + return ref and ref.has_kind("<class>") and ref.instance_of() or Reference("<var>")
4.156
4.157 def resolve_accesses(self, path, name, ref):
4.158
4.159 @@ -237,6 +226,9 @@
4.160 objpath = ".".join(attrs)
4.161 if objpath != path:
4.162
4.163 + if last_ref.has_kind("<invoke>"):
4.164 + last_ref = self.convert_invocation(last_ref)
4.165 +
4.166 # Establish a constant access.
4.167
4.168 init_item(self.const_accesses, path, dict)
4.169 @@ -362,15 +354,14 @@
4.170 # or unresolved names referring to globals or built-ins.
4.171
4.172 if ref.has_kind("<depends>"):
4.173 - ref = self.importer.get_object(ref.get_origin()) or \
4.174 - self.importer.get_object(self.name_references.get(ref.get_origin()))
4.175 + ref = self.importer.identify(ref.get_origin())
4.176
4.177 # Convert class invocations to instances.
4.178
4.179 if invocation:
4.180 - ref = ref.has_kind("<class>") and ref.instance_of() or None
4.181 + ref = self.convert_invocation(ref)
4.182
4.183 - if ref:
4.184 + if ref and not ref.has_kind("<var>"):
4.185 initialised_names[i] = ref
4.186
4.187 if initialised_names:
5.1 --- a/results.py Mon Sep 05 00:12:56 2016 +0200
5.2 +++ b/results.py Mon Sep 05 19:50:21 2016 +0200
5.3 @@ -19,6 +19,8 @@
5.4 this program. If not, see <http://www.gnu.org/licenses/>.
5.5 """
5.6
5.7 +from referencing import Reference
5.8 +
5.9 # Classes representing inspection and translation observations.
5.10
5.11 class Result:
5.12 @@ -55,6 +57,13 @@
5.13 def __init__(self, name_ref):
5.14 self.name_ref = name_ref
5.15
5.16 + def reference(self):
5.17 + origin = self.name_ref.get_origin()
5.18 + if origin:
5.19 + return Reference("<invoke>", origin)
5.20 + else:
5.21 + return Reference("<var>")
5.22 +
5.23 def __repr__(self):
5.24 return "InvocationRef(%r)" % self.name_ref
5.25