1.1 --- a/resolving.py Mon Sep 05 00:12:56 2016 +0200
1.2 +++ b/resolving.py Mon Sep 05 19:50:21 2016 +0200
1.3 @@ -31,18 +31,6 @@
1.4
1.5 # Object resolution.
1.6
1.7 - def resolve_object(self, ref):
1.8 -
1.9 - """
1.10 - Return the given 'ref' in resolved form, given knowledge of the entire
1.11 - program.
1.12 - """
1.13 -
1.14 - if ref.has_kind("<depends>"):
1.15 - return self.importer.get_object(ref.get_origin())
1.16 - else:
1.17 - return ref
1.18 -
1.19 def get_resolved_object(self, path):
1.20
1.21 """
1.22 @@ -61,12 +49,6 @@
1.23 else:
1.24 return None
1.25
1.26 - def get_resolved_global_or_builtin(self, name):
1.27 -
1.28 - "Return the resolved global or built-in object with the given 'name'."
1.29 -
1.30 - return self.get_global(name) or self.importer.get_object("__builtins__.%s" % name)
1.31 -
1.32 # Post-inspection resolution activities.
1.33
1.34 def resolve(self):
1.35 @@ -77,22 +59,31 @@
1.36 self.resolve_class_bases()
1.37 self.check_special()
1.38 self.check_names_used()
1.39 + self.check_invocations()
1.40 self.resolve_initialisers()
1.41 self.resolve_literals()
1.42 self.remove_redundant_accessors()
1.43
1.44 def resolve_members(self):
1.45
1.46 - "Resolve any members referring to deferred references."
1.47 + """
1.48 + Resolve any members referring to deferred references, using information
1.49 + stored in the importer. This updates stored object and external name
1.50 + records in this module.
1.51 + """
1.52
1.53 - for name, ref in self.objects.items():
1.54 - if ref.has_kind("<depends>"):
1.55 - ref = self.importer.get_object(name)
1.56 + for impd, d in [
1.57 + (self.importer.objects, self.objects),
1.58 + (self.importer.all_name_references, self.name_references)
1.59 + ]:
1.60
1.61 - # Alias the member and write back to the importer.
1.62 + for name, ref in d.items():
1.63 +
1.64 + # Obtain resolved names from the importer.
1.65
1.66 - ref = ref.alias(name)
1.67 - self.importer.objects[name] = self.objects[name] = ref
1.68 + if ref.has_kind("<depends>"):
1.69 + ref = self.importer.identify(name)
1.70 + d[name] = ref
1.71
1.72 def resolve_class_bases(self):
1.73
1.74 @@ -103,7 +94,7 @@
1.75 bad = []
1.76
1.77 for base in bases:
1.78 - ref = self.resolve_object(base)
1.79 + ref = self.importer.identify(base.get_origin())
1.80
1.81 # Obtain the origin of the base class reference.
1.82
1.83 @@ -127,46 +118,44 @@
1.84
1.85 def check_names_used(self):
1.86
1.87 - "Check the names used by each function."
1.88 + "Check the external names used by each scope."
1.89
1.90 - for path in self.names_used.keys():
1.91 - self.check_names_used_for_path(path)
1.92 + for key, ref in self.name_references.items():
1.93 + path, name = key.rsplit(".", 1)
1.94 + self.resolve_accesses(path, name, ref)
1.95
1.96 - def check_names_used_for_path(self, path):
1.97 -
1.98 - "Check the names used by the given 'path'."
1.99 + def check_invocations(self):
1.100
1.101 - names = self.names_used.get(path)
1.102 - if not names:
1.103 - return
1.104 + "Find invocations amongst module data and replace their results."
1.105
1.106 - in_function = self.function_locals.has_key(path)
1.107 + # Find members and replace invocation results with values. This is
1.108 + # effectively the same as is done for initialised names, but refers to
1.109 + # any unchanging value after initialisation.
1.110
1.111 - for name in names:
1.112 - if name in predefined_constants or in_function and name in self.function_locals[path]:
1.113 - continue
1.114 + for key, ref in self.objects.items():
1.115 + if ref.has_kind("<invoke>"):
1.116 + ref = self.convert_invocation(ref)
1.117 + self.importer.objects[key] = self.objects[key] = ref
1.118
1.119 - # Find local definitions (within static namespaces).
1.120 + # Rewrite function defaults, which are effectively extra members of the
1.121 + # module.
1.122
1.123 - key = "%s.%s" % (path, name)
1.124 - ref = self.get_resolved_object(key)
1.125 - if ref:
1.126 - self.name_references[key] = ref.final() or key
1.127 - self.resolve_accesses(path, name, ref)
1.128 - continue
1.129 -
1.130 - # Find global or built-in definitions.
1.131 + defaults = self.function_defaults.items()
1.132
1.133 - ref = self.get_resolved_global_or_builtin(name)
1.134 - objpath = ref and (ref.final() or ref.get_name())
1.135 - if objpath:
1.136 - self.name_references[key] = objpath
1.137 - self.resolve_accesses(path, name, ref)
1.138 - continue
1.139 + for fname, parameters in defaults:
1.140 + l = []
1.141 + for pname, ref in parameters:
1.142 + if ref.has_kind("<invoke>"):
1.143 + ref = self.convert_invocation(ref)
1.144 + l.append((pname, ref))
1.145 + self.function_defaults[fname] = l
1.146
1.147 - print >>sys.stderr, "Name not recognised: %s in %s" % (name, path)
1.148 - init_item(self.names_missing, path, set)
1.149 - self.names_missing[path].add(name)
1.150 + def convert_invocation(self, ref):
1.151 +
1.152 + "Convert the given invocation 'ref', handling instantiation."
1.153 +
1.154 + ref = self.importer.identify(ref.get_origin())
1.155 + return ref and ref.has_kind("<class>") and ref.instance_of() or Reference("<var>")
1.156
1.157 def resolve_accesses(self, path, name, ref):
1.158
1.159 @@ -237,6 +226,9 @@
1.160 objpath = ".".join(attrs)
1.161 if objpath != path:
1.162
1.163 + if last_ref.has_kind("<invoke>"):
1.164 + last_ref = self.convert_invocation(last_ref)
1.165 +
1.166 # Establish a constant access.
1.167
1.168 init_item(self.const_accesses, path, dict)
1.169 @@ -362,15 +354,14 @@
1.170 # or unresolved names referring to globals or built-ins.
1.171
1.172 if ref.has_kind("<depends>"):
1.173 - ref = self.importer.get_object(ref.get_origin()) or \
1.174 - self.importer.get_object(self.name_references.get(ref.get_origin()))
1.175 + ref = self.importer.identify(ref.get_origin())
1.176
1.177 # Convert class invocations to instances.
1.178
1.179 if invocation:
1.180 - ref = ref.has_kind("<class>") and ref.instance_of() or None
1.181 + ref = self.convert_invocation(ref)
1.182
1.183 - if ref:
1.184 + if ref and not ref.has_kind("<var>"):
1.185 initialised_names[i] = ref
1.186
1.187 if initialised_names: