1.1 --- a/modules.py Sat Sep 03 22:38:21 2016 +0200
1.2 +++ b/modules.py Sat Sep 03 22:43:44 2016 +0200
1.3 @@ -20,9 +20,10 @@
1.4 this program. If not, see <http://www.gnu.org/licenses/>.
1.5 """
1.6
1.7 -from common import *
1.8 +from common import CommonModule
1.9 from encoders import decode_modifier_term, encode_modifiers, encode_usage
1.10 from referencing import decode_reference, Reference
1.11 +from results import ResolvedNameRef
1.12 import sys
1.13
1.14 class BasicModule(CommonModule):
1.15 @@ -32,18 +33,6 @@
1.16 def __init__(self, name, importer):
1.17 CommonModule.__init__(self, name, importer)
1.18
1.19 - # Import machinery links.
1.20 -
1.21 - self.loaded = False
1.22 -
1.23 - # Module dependencies.
1.24 -
1.25 - self.imported = set()
1.26 - self.imported_hidden = set()
1.27 - self.imported_names = {}
1.28 - self.revealed = set()
1.29 - self.accessing_modules = set()
1.30 -
1.31 # Global name information.
1.32
1.33 self.objects = {}
1.34 @@ -64,7 +53,6 @@
1.35
1.36 self.names_used = {}
1.37 self.names_missing = {}
1.38 - self.name_references = {} # references to globals
1.39
1.40 # Function details.
1.41
1.42 @@ -96,31 +84,9 @@
1.43
1.44 self.attr_access_modifiers = {}
1.45
1.46 - # Initialisation-related details.
1.47 -
1.48 - self.initialised_names = {}
1.49 - self.aliased_names = {}
1.50 -
1.51 def __repr__(self):
1.52 return "BasicModule(%r, %r)" % (self.name, self.importer)
1.53
1.54 - def resolve(self):
1.55 -
1.56 - "Resolve dependencies and complete definitions."
1.57 -
1.58 - self.resolve_class_bases()
1.59 - self.check_special()
1.60 - self.check_names_used()
1.61 - self.resolve_members()
1.62 - self.resolve_initialisers()
1.63 - self.resolve_literals()
1.64 - self.remove_redundant_accessors()
1.65 - self.set_invocation_usage()
1.66 -
1.67 - # Propagate to the importer information needed in subsequent activities.
1.68 -
1.69 - self.propagate()
1.70 -
1.71 # Derived information methods.
1.72
1.73 def propagate(self):
1.74 @@ -176,36 +142,6 @@
1.75 if ref.get_kind() != "<module>":
1.76 del self.importer.objects[name]
1.77
1.78 - def resolve_class_bases(self):
1.79 -
1.80 - "Resolve all class bases since some of them may have been deferred."
1.81 -
1.82 - for name, bases in self.classes.items():
1.83 - resolved = []
1.84 - bad = []
1.85 -
1.86 - for base in bases:
1.87 -
1.88 - # Resolve dependencies.
1.89 -
1.90 - if base.has_kind("<depends>"):
1.91 - ref = self.importer.get_object(base.get_origin())
1.92 - else:
1.93 - ref = base
1.94 -
1.95 - # Obtain the origin of the base class reference.
1.96 -
1.97 - if not ref or not ref.has_kind("<class>"):
1.98 - bad.append(base)
1.99 - break
1.100 -
1.101 - resolved.append(ref)
1.102 -
1.103 - if bad:
1.104 - print >>sys.stderr, "Bases of class %s were not classes." % (name, ", ".join(map(str, bad)))
1.105 - else:
1.106 - self.importer.classes[name] = self.classes[name] = resolved
1.107 -
1.108 def propagate_attrs(self):
1.109
1.110 "Derive attributes from the class and module member details."
1.111 @@ -268,20 +204,6 @@
1.112 path = self.get_namespace_path()
1.113 return name in self.scope_globals.get(path, [])
1.114
1.115 - def get_globals(self):
1.116 -
1.117 - """
1.118 - Get the globals from this module, returning a dictionary mapping names
1.119 - to references incorporating original definition details.
1.120 - """
1.121 -
1.122 - l = []
1.123 - for name, value in self.objects.items():
1.124 - parent, attrname = name.rsplit(".", 1)
1.125 - if parent == self.name:
1.126 - l.append((attrname, value))
1.127 - return dict(l)
1.128 -
1.129 def get_global(self, name):
1.130
1.131 """
1.132 @@ -297,57 +219,38 @@
1.133 def get_global_or_builtin(self, name):
1.134
1.135 """
1.136 - Return the object recorded the given 'name' from this module or from the
1.137 - __builtins__ module. If no object has yet been defined, perhaps due to
1.138 - circular module references, None is returned.
1.139 + Return a reference for the given 'name' found in this module or in the
1.140 + __builtins__.
1.141 """
1.142
1.143 return self.get_global(name) or self.get_builtin(name)
1.144
1.145 def get_builtin(self, name):
1.146
1.147 - "Return the object providing the given built-in 'name'."
1.148 -
1.149 - path = "__builtins__.%s" % name
1.150 -
1.151 - # Obtain __builtins__.
1.152 + "Return a reference to the built-in with the given 'name'."
1.153
1.154 - module = self.ensure_builtins(path)
1.155 -
1.156 - # Attempt to find the named object within __builtins__.
1.157 -
1.158 - if module:
1.159 - self.find_imported_name(name, module.name, module)
1.160 + self.importer.queue_module("__builtins__", self)
1.161 + return Reference("<depends>", "__builtins__.%s" % name)
1.162
1.163 - # Return the path and any reference for the named object.
1.164 + def get_builtin_class(self, name):
1.165
1.166 - return self.importer.get_object(path)
1.167 -
1.168 - def ensure_builtins(self, path):
1.169 + "Return a reference to the actual object providing 'name'."
1.170
1.171 - """
1.172 - If 'path' is a reference to an object within __builtins__, return the
1.173 - __builtins__ module.
1.174 - """
1.175 + # NOTE: This makes assumptions about the __builtins__ structure.
1.176
1.177 - if path.split(".", 1)[0] == "__builtins__":
1.178 - return self.importer.load("__builtins__", True, True)
1.179 - else:
1.180 - return None
1.181 + return Reference("<class>", "__builtins__.%s.%s" % (name, name))
1.182
1.183 def get_object(self, path):
1.184
1.185 """
1.186 - Get the details of an object with the given 'path', either from this
1.187 - module or from the whole program. Return a tuple containing the path and
1.188 - any object found.
1.189 + Get the details of an object with the given 'path'. Where the object
1.190 + cannot be resolved, an unresolved reference is returned.
1.191 """
1.192
1.193 if self.objects.has_key(path):
1.194 return self.objects[path]
1.195 else:
1.196 - self.ensure_builtins(path)
1.197 - return self.importer.get_object(path)
1.198 + return Reference("<depends>", path)
1.199
1.200 def set_object(self, name, value=None):
1.201
1.202 @@ -357,6 +260,14 @@
1.203 multiple = self.objects.has_key(name) and self.objects[name].get_kind() != ref.get_kind()
1.204 self.importer.objects[name] = self.objects[name] = multiple and ref.as_var() or ref
1.205
1.206 + def import_name_from_module(self, name, module_name):
1.207 +
1.208 + "Import 'name' from the module having the given 'module_name'."
1.209 +
1.210 + if module_name != self.name:
1.211 + self.importer.queue_module(module_name, self)
1.212 + return Reference("<depends>", "%s.%s" % (module_name, name))
1.213 +
1.214 # Special names.
1.215
1.216 def get_special(self, name):
1.217 @@ -385,160 +296,6 @@
1.218 value = ResolvedNameRef(literal_name, ref)
1.219 self.set_special(literal_name, value)
1.220
1.221 - # Revealing modules by tracking name imports across modules.
1.222 -
1.223 - def set_imported_name(self, name, module_name, alias=None, path=None):
1.224 -
1.225 - """
1.226 - Record 'name' as being imported from the given 'module_name', employing
1.227 - the given 'alias' in the local namespace if specified.
1.228 - """
1.229 -
1.230 - path = path or self.get_namespace_path()
1.231 - init_item(self.imported_names, path, dict)
1.232 - self.imported_names[path][alias or name] = (name, module_name)
1.233 -
1.234 - def get_imported_name(self, name, path):
1.235 -
1.236 - "Get details of any imported 'name' within the namespace at 'path'."
1.237 -
1.238 - if self.imported_names.has_key(path):
1.239 - return self.imported_names[path].get(name)
1.240 - else:
1.241 - return None
1.242 -
1.243 - def find_imported_name(self, name, path, module=None):
1.244 -
1.245 - """
1.246 - Find details of the imported 'name' within the namespace at 'path',
1.247 - starting within the given 'module' if indicated, or within this module
1.248 - otherwise.
1.249 - """
1.250 -
1.251 - module = module or self
1.252 -
1.253 - # Obtain any module required by the name.
1.254 -
1.255 - name_modname = module.get_imported_name(name, path)
1.256 -
1.257 - if name_modname:
1.258 - name, modname = name_modname
1.259 - module = self._find_imported_name(name, modname, module)
1.260 -
1.261 - # Obtain the name from the final module, revealing it if appropriate.
1.262 -
1.263 - if module:
1.264 - init_item(self.importer.revealing, module.name, set)
1.265 - self.importer.set_revealing(module, name, self)
1.266 -
1.267 - def _find_imported_name(self, name, modname, module):
1.268 -
1.269 - """
1.270 - Traverse details for 'name' via 'modname' to the module providing the
1.271 - name, tentatively revealing the module even if the module is not yet
1.272 - loaded and cannot provide the details of the object recorded for the
1.273 - name.
1.274 - """
1.275 -
1.276 - _name = name
1.277 -
1.278 - # Obtain any modules referenced by each required module.
1.279 -
1.280 - while True:
1.281 -
1.282 - # Get the module directly or traverse possibly-aliased names.
1.283 -
1.284 - module = self.get_module_direct(modname, True)
1.285 - if not module:
1.286 - top, module = self.get_module(modname, True)
1.287 - name_modname = module.get_imported_name(_name, module.name)
1.288 - if not name_modname:
1.289 - break
1.290 - else:
1.291 - _name, modname = name_modname
1.292 -
1.293 - return module
1.294 -
1.295 - def reveal_referenced(self):
1.296 -
1.297 - """
1.298 - Reveal modules referenced by this module.
1.299 - """
1.300 -
1.301 - for path, names in self.imported_names.items():
1.302 - for alias, (name, modname) in names.items():
1.303 - module = self._find_imported_name(name, modname, self)
1.304 - self.reveal_module(module)
1.305 -
1.306 - def reveal_module(self, module):
1.307 -
1.308 - """
1.309 - Reveal the given 'module', recording the revealed modules on this
1.310 - module.
1.311 - """
1.312 -
1.313 - if module is not self:
1.314 - self.importer.reveal_module(module)
1.315 - self.revealed.add(module)
1.316 - module.accessing_modules.add(self.name)
1.317 -
1.318 - # Module loading.
1.319 -
1.320 - def get_module_direct(self, modname, hidden=False):
1.321 -
1.322 - """
1.323 - Return 'modname' without traversing parent modules, keeping the module
1.324 - 'hidden' if set to a true value, loading the module if not already
1.325 - loaded.
1.326 - """
1.327 -
1.328 - return self.importer.get_module(modname, True) or self.importer.load(modname, hidden=hidden)
1.329 -
1.330 - def get_module(self, name, hidden=False):
1.331 -
1.332 - """
1.333 - Use the given 'name' to obtain the identity of a module. Return module
1.334 - objects or None if the module cannot be found. This method is required
1.335 - when aliases are used to refer to modules and where a module "path" does
1.336 - not correspond to the actual module path.
1.337 -
1.338 - A tuple is returned containing the top or base module and the deepest or
1.339 - leaf module involved.
1.340 - """
1.341 -
1.342 - path_so_far = []
1.343 - top = module = None
1.344 - parts = name.split(".")
1.345 -
1.346 - for i, part in enumerate(parts):
1.347 - path_so_far.append(part)
1.348 - module_name = ".".join(path_so_far)
1.349 - ref = self.get_object(module_name)
1.350 -
1.351 - # If no known object exists, attempt to load it.
1.352 -
1.353 - if not ref:
1.354 - module = self.importer.load(module_name, True, hidden)
1.355 - if not module:
1.356 - return None
1.357 -
1.358 - # Rewrite the path to use the actual module details.
1.359 -
1.360 - path_so_far = module.name.split(".")
1.361 -
1.362 - # If the object exists and is not a module, stop.
1.363 -
1.364 - elif ref.has_kind(["<class>", "<function>", "<var>"]):
1.365 - return None
1.366 -
1.367 - else:
1.368 - module = self.importer.get_module(ref.get_origin(), hidden)
1.369 -
1.370 - if not top:
1.371 - top = module
1.372 -
1.373 - return top, module
1.374 -
1.375 class CachedModule(BasicModule):
1.376
1.377 "A cached module."
1.378 @@ -546,9 +303,6 @@
1.379 def __repr__(self):
1.380 return "CachedModule(%r, %r)" % (self.name, self.importer)
1.381
1.382 - def resolve(self):
1.383 - pass
1.384 -
1.385 def to_cache(self, filename):
1.386
1.387 "Not actually writing the module back to 'filename'."
1.388 @@ -566,27 +320,8 @@
1.389 try:
1.390 self.filename = f.readline().rstrip()
1.391
1.392 - accessing_modules = f.readline().split(": ", 1)[-1].rstrip()
1.393 -
1.394 - module_names = f.readline().split(": ", 1)[-1].rstrip()
1.395 - if module_names:
1.396 - for module_name in module_names.split(", "):
1.397 - self.imported.add(self.importer.load(module_name))
1.398 -
1.399 - module_names = f.readline().split(": ", 1)[-1].rstrip()
1.400 - if module_names:
1.401 - for module_name in module_names.split(", "):
1.402 - self.imported_hidden.add(self.importer.load(module_name, hidden=True))
1.403 -
1.404 - module_names = f.readline().split(": ", 1)[-1].rstrip()
1.405 - if module_names:
1.406 - for module_name in module_names.split(", "):
1.407 - module = self.importer.load(module_name, True, True)
1.408 - self.reveal_module(module)
1.409 -
1.410 f.readline() # (empty line)
1.411
1.412 - self._get_imported_names(f)
1.413 self._get_members(f)
1.414 self._get_class_relationships(f)
1.415 self._get_instance_attrs(f)
1.416 @@ -613,20 +348,9 @@
1.417 finally:
1.418 f.close()
1.419
1.420 - self.loaded = True
1.421 -
1.422 - def resolve(self):
1.423 + def complete(self):
1.424 self.propagate()
1.425
1.426 - def _get_imported_names(self, f):
1.427 - f.readline() # "imported names:"
1.428 - line = f.readline().rstrip()
1.429 - while line:
1.430 - path, alias_or_name, name, module_name = self._get_fields(line, 4)
1.431 - init_item(self.imported_names, path, dict)
1.432 - self.imported_names[path][alias_or_name] = (name, module_name)
1.433 - line = f.readline().rstrip()
1.434 -
1.435 def _get_members(self, f):
1.436 f.readline() # "members:"
1.437 line = f.readline().rstrip()
1.438 @@ -885,13 +609,6 @@
1.439 format to the file having the given 'filename':
1.440
1.441 filename
1.442 - "accessed by:" accessing module names during this module's import
1.443 - "imports:" imported module names
1.444 - "hidden imports:" imported module names
1.445 - "reveals:" revealed module names
1.446 - (empty line)
1.447 - "imported names:"
1.448 - zero or more: qualified name " " name " " module name
1.449 (empty line)
1.450 "members:"
1.451 zero or more: qualified name " " reference
1.452 @@ -988,33 +705,6 @@
1.453 try:
1.454 print >>f, self.filename
1.455
1.456 - accessing_modules = list(self.accessing_modules)
1.457 - accessing_modules.sort()
1.458 - print >>f, "accessed by:", ", ".join(accessing_modules)
1.459 -
1.460 - module_names = [m.name for m in self.imported]
1.461 - module_names.sort()
1.462 - print >>f, "imports:", ", ".join(module_names)
1.463 -
1.464 - module_names = [m.name for m in self.imported_hidden]
1.465 - module_names.sort()
1.466 - print >>f, "hidden imports:", ", ".join(module_names)
1.467 -
1.468 - module_names = [m.name for m in self.revealed]
1.469 - module_names.sort()
1.470 - print >>f, "reveals:", ", ".join(module_names)
1.471 -
1.472 - print >>f
1.473 - print >>f, "imported names:"
1.474 - paths = self.imported_names.keys()
1.475 - paths.sort()
1.476 - for path in paths:
1.477 - names = self.imported_names[path].keys()
1.478 - names.sort()
1.479 - for alias_or_name in names:
1.480 - name, modname = self.imported_names[path][alias_or_name]
1.481 - print >>f, path, alias_or_name, name, modname
1.482 -
1.483 print >>f
1.484 print >>f, "members:"
1.485 objects = self.objects.keys()