# HG changeset patch # User Paul Boddie # Date 1473197885 -7200 # Node ID 88a6b749a72a7aebecfc6a2ddebf723716d808ab # Parent a509aedea16b52bed3ae28389375edd2b600d7c2 Adopted mutable references in order to propagate resolution consequences without needing to perform explicit updates of many different structures. Refined the identification of required modules providing resolved deferred references. diff -r a509aedea16b -r 88a6b749a72a importer.py --- a/importer.py Tue Sep 06 17:18:11 2016 +0200 +++ b/importer.py Tue Sep 06 23:38:05 2016 +0200 @@ -336,32 +336,51 @@ "Resolve dependencies between modules." - for d in [self.objects, self.all_name_references]: - resolved = {} + self.waiting = {} + + for module in self.modules.values(): + + # Resolve all deferred references in each module. - for name, ref in d.items(): - if ref.has_kind(""): - found = self.find_dependency(ref) - if found: - resolved[name] = found - else: - print >>sys.stderr, "Name %s references an unknown object: %s" % (name, ref.get_origin()) + for ref in module.deferred: + found = self.find_dependency(ref) + if not found: + print >>sys.stderr, "Module %s references an unknown object: %s" % (module.name, ref.get_origin()) + + # Record the resolved names and identify required modules. - # Record the resolved names and identify required modules. + else: + ref.mutate(found) + + # Find the providing module of this reference. + + provider = self.get_module_provider(ref) + if provider: - for name, ref in resolved.items(): - d[name] = ref + module.required.add(provider) + self.accessing_modules[provider].add(module.name) + + # Postpone any inclusion of the provider until this + # module becomes required. - # Find the providing module of this reference. + if module.name not in self.required: + init_item(self.waiting, module.name, set) + self.waiting[module.name].add(provider) + + # Make this module required in the accessing module. - module_name = self.get_module_provider(ref) - if module_name: - self.required.add(module_name) + else: + self.required.add(provider) + + for module_name in self.waiting.keys(): + self.require_providers(module_name) - # Make this module required in all accessing modules. - - for accessor_name in self.accessing_modules[module_name]: - self.modules[accessor_name].required.add(module_name) + def require_providers(self, module_name): + if module_name in self.required and self.waiting.has_key(module_name): + for provider in self.waiting[module_name]: + if provider not in self.required: + self.required.add(provider) + self.require_providers(provider) def find_dependency(self, ref): @@ -370,7 +389,7 @@ found = set() while ref and ref.has_kind("") and not ref in found: found.add(ref) - ref = self.objects.get(ref.get_origin()) + ref = self.identify(ref.get_origin()) return ref def get_module_provider(self, ref): diff -r a509aedea16b -r 88a6b749a72a inspector.py --- a/inspector.py Tue Sep 06 17:18:11 2016 +0200 +++ b/inspector.py Tue Sep 06 23:38:05 2016 +0200 @@ -130,12 +130,12 @@ if name in predefined_constants or in_function and name in self.function_locals[path]: continue - # Find local definitions (within static namespaces). + # Find local definitions (within dynamic namespaces). key = "%s.%s" % (path, name) ref = self.get_resolved_object(key) if ref: - self.importer.all_name_references[key] = self.name_references[key] = ref.alias(key) + self.importer.all_name_references[key] = self.name_references[key] = ref continue # Find global or built-in definitions. @@ -789,6 +789,7 @@ # Attempt to get a reference. ref = self.import_name_from_module(op, "operator") + self.add_deferred(ref) # Record the imported name and provide the resolved name reference. diff -r a509aedea16b -r 88a6b749a72a modules.py --- a/modules.py Tue Sep 06 17:18:11 2016 +0200 +++ b/modules.py Tue Sep 06 23:38:05 2016 +0200 @@ -37,6 +37,7 @@ self.imports = set() self.required = set() + self.deferred = [] # Global name information. @@ -207,7 +208,17 @@ "Set an object with the given 'name' and the given 'value'." + # Decode any string value, with a new reference being returned even + # given a provided reference. + ref = decode_reference(value, name) + self.add_deferred(ref) + self._set_object(name, ref) + + def _set_object(self, name, ref): + + # Determine how the object properties will be defined. + multiple = self.objects.has_key(name) and self.objects[name].get_kind() != ref.get_kind() self.importer.objects[name] = self.objects[name] = multiple and ref.as_var() or ref @@ -266,7 +277,9 @@ "Return a reference to the built-in with the given 'name'." self.queue_module("__builtins__") - return Reference("", "__builtins__.%s" % name) + ref = Reference("", "__builtins__.%s" % name) + self.deferred.append(ref) + return ref def get_builtin_class(self, name): @@ -289,7 +302,9 @@ if self.objects.has_key(path): return self.objects[path] else: - return Reference("", path) + ref = Reference("", path) + self.deferred.append(ref) + return ref def import_name_from_module(self, name, module_name): @@ -299,6 +314,13 @@ self.queue_module(module_name) return Reference("", "%s.%s" % (module_name, name)) + def add_deferred(self, ref): + + "Record 'ref' as a deferred reference." + + if ref.has_kind(""): + self.deferred.append(ref) + class CachedModule(BasicModule): "A cached module." @@ -306,6 +328,16 @@ def __repr__(self): return "CachedModule(%r, %r)" % (self.name, self.importer) + def set_object(self, name, value=None): + + "Set an object with the given 'name' and the given 'value'." + + # Decode any string value, with a new reference being returned even + # given a provided reference. + + ref = decode_reference(value, name) + self._set_object(name, ref) + def to_cache(self, filename): "Not actually writing the module back to 'filename'." diff -r a509aedea16b -r 88a6b749a72a referencing.py --- a/referencing.py Tue Sep 06 17:18:11 2016 +0200 +++ b/referencing.py Tue Sep 06 23:38:05 2016 +0200 @@ -137,6 +137,14 @@ return Reference(self.get_kind(), self.get_origin(), name) + def mutate(self, ref): + + "Mutate this reference to have the same details as 'ref'." + + self.kind = ref.kind + self.origin = ref.origin + self.name = ref.name + def ancestors(self): """ diff -r a509aedea16b -r 88a6b749a72a resolving.py --- a/resolving.py Tue Sep 06 17:18:11 2016 +0200 +++ b/resolving.py Tue Sep 06 23:38:05 2016 +0200 @@ -35,7 +35,6 @@ "Resolve dependencies and complete definitions." - self.resolve_members() self.resolve_class_bases() self.check_special() self.check_names_used() @@ -44,27 +43,6 @@ self.resolve_literals() self.remove_redundant_accessors() - def resolve_members(self): - - """ - Resolve any members referring to deferred references, using information - stored in the importer. This updates stored object and external name - records in this module. - """ - - for impd, d in [ - (self.importer.objects, self.objects), - (self.importer.all_name_references, self.name_references) - ]: - - for name, ref in d.items(): - - # Obtain resolved names from the importer. - - if ref.has_kind(""): - ref = self.importer.identify(name) - d[name] = ref - def resolve_class_bases(self): "Resolve all class bases since some of them may have been deferred."