1.1 --- a/resolving.py Sat Mar 11 16:46:36 2017 +0100
1.2 +++ b/resolving.py Sat Mar 11 22:27:45 2017 +0100
1.3 @@ -40,6 +40,7 @@
1.4 self.check_names_used()
1.5 self.check_invocations()
1.6 self.resolve_initialisers()
1.7 + self.resolve_return_values()
1.8 self.resolve_literals()
1.9
1.10 def resolve_class_bases(self):
1.11 @@ -235,7 +236,6 @@
1.12 # Get the initialisers in each namespace.
1.13
1.14 for path, name_initialisers in self.name_initialisers.items():
1.15 - const_accesses = self.const_accesses.get(path)
1.16
1.17 # Resolve values for each name in a scope.
1.18
1.19 @@ -244,109 +244,154 @@
1.20 aliased_names = {}
1.21
1.22 for i, name_ref in enumerate(values):
1.23 -
1.24 - # Unwrap invocations.
1.25 -
1.26 - if isinstance(name_ref, InvocationRef):
1.27 - invocation = True
1.28 - name_ref = name_ref.name_ref
1.29 - else:
1.30 - invocation = False
1.31 -
1.32 - # Obtain a usable reference from names or constants.
1.33 -
1.34 - if isinstance(name_ref, ResolvedNameRef):
1.35 - if not name_ref.reference():
1.36 - continue
1.37 - ref = name_ref.reference()
1.38 -
1.39 - # Obtain a reference from instances.
1.40 -
1.41 - elif isinstance(name_ref, InstanceRef):
1.42 - if not name_ref.reference():
1.43 - continue
1.44 - ref = name_ref.reference()
1.45 -
1.46 - # Resolve accesses that employ constants.
1.47 -
1.48 - elif isinstance(name_ref, AccessRef):
1.49 - ref = None
1.50 -
1.51 - if const_accesses:
1.52 - resolved_access = const_accesses.get((name_ref.original_name, name_ref.attrnames))
1.53 - if resolved_access:
1.54 - objpath, ref, remaining_attrnames = resolved_access
1.55 - if remaining_attrnames:
1.56 - ref = None
1.57 -
1.58 - # Accesses that do not employ constants cannot be resolved,
1.59 - # but they may be resolvable later.
1.60 -
1.61 - if not ref:
1.62 - if not invocation:
1.63 -
1.64 - # Record the path used for tracking purposes
1.65 - # alongside original name, attribute and access
1.66 - # number details.
1.67 -
1.68 - aliased_names[i] = path, name_ref.original_name, name_ref.attrnames, name_ref.number
1.69 -
1.70 - continue
1.71 -
1.72 - # Attempt to resolve a plain name reference.
1.73 -
1.74 - elif isinstance(name_ref, LocalNameRef):
1.75 - key = "%s.%s" % (path, name_ref.name)
1.76 - ref = self.name_references.get(key)
1.77 -
1.78 - # Accesses that do not refer to known static objects
1.79 - # cannot be resolved, but they may be resolvable later.
1.80 -
1.81 - if not ref:
1.82 - if not invocation:
1.83 -
1.84 - # Record the path used for tracking purposes
1.85 - # alongside original name, attribute and access
1.86 - # number details.
1.87 -
1.88 - aliased_names[i] = path, name_ref.name, None, name_ref.number
1.89 -
1.90 - continue
1.91 -
1.92 - ref = self.get_resolved_object(ref.get_origin())
1.93 - if not ref:
1.94 - continue
1.95 -
1.96 - elif isinstance(name_ref, NameRef):
1.97 - key = "%s.%s" % (path, name_ref.name)
1.98 - ref = self.name_references.get(key)
1.99 -
1.100 - ref = ref and self.get_resolved_object(ref.get_origin())
1.101 - if not ref:
1.102 - continue
1.103 -
1.104 - else:
1.105 - continue
1.106 -
1.107 - # Resolve any hidden dependencies involving external objects
1.108 - # or unresolved names referring to globals or built-ins.
1.109 -
1.110 - if ref.has_kind("<depends>"):
1.111 - ref = self.importer.identify(ref.get_origin())
1.112 -
1.113 - # Convert class invocations to instances.
1.114 -
1.115 - if ref and invocation:
1.116 - ref = self.convert_invocation(ref)
1.117 -
1.118 - if ref and not ref.has_kind("<var>"):
1.119 - initialised_names[i] = ref
1.120 + initialised_ref, aliased_name = self.resolve_reference(path, name_ref)
1.121 + if initialised_ref:
1.122 + initialised_names[i] = initialised_ref
1.123 + if aliased_name:
1.124 + aliased_names[i] = aliased_name
1.125
1.126 if initialised_names:
1.127 self.initialised_names[(path, name)] = initialised_names
1.128 if aliased_names:
1.129 self.aliased_names[(path, name)] = aliased_names
1.130
1.131 + def resolve_return_values(self):
1.132 +
1.133 + "Resolve return values using name references."
1.134 +
1.135 + return_values = {}
1.136 +
1.137 + # Get the return values from each namespace.
1.138 +
1.139 + for path, values in self.return_values.items():
1.140 + l = set()
1.141 +
1.142 + for value in values:
1.143 + if not value:
1.144 + ref = None
1.145 + else:
1.146 + ref, aliased_name = self.resolve_reference(path, value)
1.147 +
1.148 + l.add(ref or Reference("<var>"))
1.149 +
1.150 + return_values[path] = l
1.151 +
1.152 + # Replace the original values.
1.153 +
1.154 + self.return_values = return_values
1.155 +
1.156 + def resolve_reference(self, path, name_ref):
1.157 +
1.158 + """
1.159 + Within the namespace 'path', resolve the given 'name_ref', returning any
1.160 + initialised reference, along with any aliased name information.
1.161 + """
1.162 +
1.163 + const_accesses = self.const_accesses.get(path)
1.164 +
1.165 + initialised_ref = None
1.166 + aliased_name = None
1.167 + no_reference = None, None
1.168 +
1.169 + # Unwrap invocations.
1.170 +
1.171 + if isinstance(name_ref, InvocationRef):
1.172 + invocation = True
1.173 + name_ref = name_ref.name_ref
1.174 + else:
1.175 + invocation = False
1.176 +
1.177 + # Obtain a usable reference from names or constants.
1.178 +
1.179 + if isinstance(name_ref, ResolvedNameRef):
1.180 + if not name_ref.reference():
1.181 + return no_reference
1.182 + ref = name_ref.reference()
1.183 +
1.184 + # Obtain a reference from instances.
1.185 +
1.186 + elif isinstance(name_ref, InstanceRef):
1.187 + if not name_ref.reference():
1.188 + return no_reference
1.189 + ref = name_ref.reference()
1.190 +
1.191 + # Resolve accesses that employ constants.
1.192 +
1.193 + elif isinstance(name_ref, AccessRef):
1.194 + ref = None
1.195 +
1.196 + if const_accesses:
1.197 + resolved_access = const_accesses.get((name_ref.original_name, name_ref.attrnames))
1.198 + if resolved_access:
1.199 + objpath, ref, remaining_attrnames = resolved_access
1.200 + if remaining_attrnames:
1.201 + ref = None
1.202 +
1.203 + # Accesses that do not employ constants cannot be resolved,
1.204 + # but they may be resolvable later.
1.205 +
1.206 + if not ref:
1.207 + if not invocation:
1.208 +
1.209 + # Record the path used for tracking purposes
1.210 + # alongside original name, attribute and access
1.211 + # number details.
1.212 +
1.213 + aliased_name = path, name_ref.original_name, name_ref.attrnames, name_ref.number
1.214 +
1.215 + return no_reference
1.216 +
1.217 + # Attempt to resolve a plain name reference.
1.218 +
1.219 + elif isinstance(name_ref, LocalNameRef):
1.220 + key = "%s.%s" % (path, name_ref.name)
1.221 + ref = self.name_references.get(key)
1.222 +
1.223 + # Accesses that do not refer to known static objects
1.224 + # cannot be resolved, but they may be resolvable later.
1.225 +
1.226 + if not ref:
1.227 + if not invocation:
1.228 +
1.229 + # Record the path used for tracking purposes
1.230 + # alongside original name, attribute and access
1.231 + # number details.
1.232 +
1.233 + aliased_name = path, name_ref.name, None, name_ref.number
1.234 +
1.235 + return no_reference
1.236 +
1.237 + ref = self.get_resolved_object(ref.get_origin())
1.238 + if not ref:
1.239 + return no_reference
1.240 +
1.241 + elif isinstance(name_ref, NameRef):
1.242 + key = "%s.%s" % (path, name_ref.name)
1.243 + ref = self.name_references.get(key)
1.244 +
1.245 + ref = ref and self.get_resolved_object(ref.get_origin())
1.246 + if not ref:
1.247 + return no_reference
1.248 +
1.249 + else:
1.250 + return no_reference
1.251 +
1.252 + # Resolve any hidden dependencies involving external objects
1.253 + # or unresolved names referring to globals or built-ins.
1.254 +
1.255 + if ref.has_kind("<depends>"):
1.256 + ref = self.importer.identify(ref.get_origin())
1.257 +
1.258 + # Convert class invocations to instances.
1.259 +
1.260 + if ref and invocation:
1.261 + ref = self.convert_invocation(ref)
1.262 +
1.263 + if ref and not ref.has_kind("<var>"):
1.264 + initialised_ref = ref
1.265 +
1.266 + return initialised_ref, aliased_name
1.267 +
1.268 def resolve_literals(self):
1.269
1.270 "Resolve constant value types."