1.1 --- a/micropython/inspect.py Sat Jul 07 20:40:09 2012 +0200
1.2 +++ b/micropython/inspect.py Sun Jul 08 02:26:27 2012 +0200
1.3 @@ -90,8 +90,9 @@
1.4 order:
1.5
1.6 1. parse
1.7 - 2. vacuum
1.8 - 3. finalise
1.9 + 2. process
1.10 + 3. vacuum
1.11 + 4. finalise
1.12
1.13 A module importer can be expected to perform these invocations.
1.14 """
1.15 @@ -111,6 +112,7 @@
1.16 self.optimisations = self.importer.optimisations
1.17 self.builtins = self.importer.modules.get("__builtins__")
1.18 self.loaded = 0
1.19 + self.completed = 0
1.20
1.21 # Current expression state.
1.22
1.23 @@ -129,28 +131,33 @@
1.24
1.25 "Parse the file having the given 'filename'."
1.26
1.27 - module = compiler.parseFile(filename)
1.28 - self.process(module)
1.29 + self.astnode = module = compiler.parseFile(filename)
1.30 +
1.31 + # Detect and record imports and globals declared in the module.
1.32 +
1.33 + self.process_structure(module)
1.34
1.35 - def process(self, module):
1.36 + def complete(self):
1.37 + if not self.completed:
1.38 + self.completed = 1
1.39 + self.process()
1.40 + if self.importer.verbose:
1.41 + print >>sys.stderr, "Completed import of", self.full_name()
1.42 +
1.43 + def process(self):
1.44 + return self.process_module(self.astnode)
1.45 +
1.46 + def process_module(self, module):
1.47
1.48 """
1.49 - Process the given 'module', visiting only module-level code and only
1.50 - extracting global declarations from functions. In order to support
1.51 - deferred imports, the function code is processed separately after all
1.52 - modules have been initially processed.
1.53 + Process the given 'module', visiting module-level code and function
1.54 + code.
1.55 """
1.56
1.57 - self.astnode = module
1.58 -
1.59 # Add __name__ to the namespace.
1.60
1.61 self.store("__name__", self._visitConst(self.full_name()))
1.62
1.63 - # Detect and record globals declared in the module.
1.64 -
1.65 - self.process_globals(module)
1.66 -
1.67 # Visit module-level code, also recording global names.
1.68
1.69 processed = self.dispatch(module)
1.70 @@ -187,14 +194,18 @@
1.71 self._visitFunctionBody(node, namespaces)
1.72 namespaces[-1].finalise_attribute_usage()
1.73
1.74 - def process_globals(self, node):
1.75 + def process_structure(self, node):
1.76
1.77 """
1.78 Within the given 'node', process global declarations, adjusting the
1.79 - module namespace.
1.80 + module namespace, and import statements, building a module dependency
1.81 + hierarchy.
1.82 """
1.83
1.84 for n in node.getChildNodes():
1.85 +
1.86 + # Module global detection.
1.87 +
1.88 if isinstance(n, compiler.ast.Global):
1.89 for name in n.names:
1.90
1.91 @@ -203,10 +214,95 @@
1.92 # just indicate that the name cannot be relied upon for
1.93 # various observations.
1.94
1.95 - module.modify_name(name)
1.96 + self.modify_name(name)
1.97 +
1.98 + # Module import declarations.
1.99 +
1.100 + elif isinstance(n, compiler.ast.From):
1.101 +
1.102 + # Load the mentioned module.
1.103 +
1.104 + module = self.importer.load(n.modname, 1, importer=n)
1.105 + self.record_import(n.modname, n)
1.106 +
1.107 + # Speculatively load modules for names beneath the module.
1.108 +
1.109 + for name, alias in n.names:
1.110 + modname = n.modname + "." + name
1.111 + self.record_import(modname, n)
1.112 +
1.113 + elif isinstance(n, compiler.ast.Import):
1.114 +
1.115 + # Load the mentioned module.
1.116 +
1.117 + for name, alias in n.names:
1.118 + self.record_import(name, n)
1.119 +
1.120 + # Nodes using operator module functions.
1.121 +
1.122 + elif operator_functions.has_key(n.__class__.__name__) or \
1.123 + isinstance(n, (compiler.ast.AugAssign, compiler.ast.Compare)):
1.124 +
1.125 + n._module = self.importer.load("operator")
1.126
1.127 else:
1.128 - self.process_globals(n)
1.129 + self.process_structure(n)
1.130 +
1.131 + def get_module_paths(self, name):
1.132 +
1.133 + """
1.134 + Return the paths of modules leading to the module having the given
1.135 + 'name'.
1.136 + """
1.137 +
1.138 + names = []
1.139 + parts = []
1.140 + for part in name.split("."):
1.141 + parts.append(part)
1.142 + names.append(".".join(parts))
1.143 + return names
1.144 +
1.145 + def record_import(self, name, node):
1.146 +
1.147 + """
1.148 + Record an import of a module with the given 'name' occurring at the
1.149 + given 'node'.
1.150 + """
1.151 +
1.152 + module = self.importer.load(name, 1, importer=node)
1.153 + if module and not module.loaded:
1.154 + self.importer.circular_imports.add(module)
1.155 +
1.156 + def complete_import(self, name, return_leaf):
1.157 +
1.158 + """
1.159 + Complete the import of the module with the given 'name', returning the
1.160 + module itself if 'return_leaf' is a true value, or returning the root of
1.161 + the module hierarchy if 'return_leaf' is a false value.
1.162 + """
1.163 +
1.164 + top = module = None
1.165 +
1.166 + for modname in self.get_module_paths(name):
1.167 +
1.168 + # Attempt to get the module, returning None for non-existent
1.169 + # modules.
1.170 +
1.171 + try:
1.172 + module = self.importer.get_module(modname)
1.173 + except KeyError:
1.174 + return None
1.175 +
1.176 + if module:
1.177 + module.complete()
1.178 +
1.179 + if top is None:
1.180 + top = module
1.181 +
1.182 + if return_leaf:
1.183 + return module
1.184 + else:
1.185 + return top
1.186
1.187 def vacuum(self):
1.188
1.189 @@ -531,10 +627,11 @@
1.190
1.191 # Generic support for classes of operations.
1.192
1.193 - def _ensureOperators(self):
1.194 + def _ensureOperators(self, node):
1.195 attr, scope, namespace = self._get_with_scope("$operator")
1.196 if attr is None:
1.197 - module = self.importer.load("operator")
1.198 + module = node._module
1.199 + module.complete()
1.200 self["$operator"] = module
1.201 else:
1.202 module = attr.get_value()
1.203 @@ -544,7 +641,7 @@
1.204
1.205 "Accounting method for the operator 'node'."
1.206
1.207 - operator_module = self._ensureOperators()
1.208 + operator_module = self._ensureOperators(node)
1.209 operator_fn = operator_functions[operator_name or node.__class__.__name__]
1.210 self.use_specific_attribute(operator_module.full_name(), operator_fn)
1.211 return self.OP(node)
1.212 @@ -795,7 +892,7 @@
1.213 # Accounting.
1.214
1.215 operator_fn = operator_functions.get(node.op)
1.216 - operator_module = self._ensureOperators()
1.217 + operator_module = self._ensureOperators(node)
1.218 self.use_specific_attribute(operator_module.full_name(), operator_fn)
1.219
1.220 # Process the assignment.
1.221 @@ -920,7 +1017,7 @@
1.222 # For operators, reference the specific function involved.
1.223
1.224 if operator_fn is not None:
1.225 - operator_module = self._ensureOperators()
1.226 + operator_module = self._ensureOperators(node)
1.227 self.use_specific_attribute(operator_module.full_name(), operator_fn)
1.228
1.229 # Define __contains__ usage on the next node.
1.230 @@ -1003,12 +1100,7 @@
1.231 self.resume_broken_branches()
1.232
1.233 def visitFrom(self, node):
1.234 - module = self.importer.load(node.modname, 1, importer=node)
1.235 - if module and not module.loaded:
1.236 - print >>sys.stderr, "Warning: a circular import of %s is being attempted in %s" % (node.modname, self.full_name())
1.237 -
1.238 - if module is None and self.importer.verbose:
1.239 - print >>sys.stderr, "Warning:", node.modname, "not imported."
1.240 + module = self.complete_import(node.modname, True)
1.241
1.242 for name, alias in node.names:
1.243
1.244 @@ -1020,13 +1112,9 @@
1.245
1.246 # Missing names may refer to submodules.
1.247
1.248 - if not module.has_key(name):
1.249 - submodule = self.importer.load(node.modname + "." + name, 1, importer=node)
1.250 - if submodule:
1.251 - if not submodule.loaded:
1.252 - print >>sys.stderr, "Warning: a circular import of %s.%s is being attempted in %s" % (
1.253 - node.modname, name, self.full_name())
1.254 -
1.255 + submodule = self.complete_import(node.modname + "." + name, True)
1.256 + if submodule:
1.257 + if not module.has_key(name):
1.258 module.store(name, submodule)
1.259
1.260 # Complete the import if the name was found.
1.261 @@ -1035,17 +1123,6 @@
1.262 attr = module[name]
1.263 self.store(alias or name, attr)
1.264 self.use_specific_attribute(module.full_name(), name)
1.265 - if isinstance(attr.get_value(), Module) and not attr.get_value().loaded:
1.266 - submodule = self.importer.load(attr.get_value().name, importer=node)
1.267 -
1.268 - # For circular imports, invalidate attribute usage for
1.269 - # all exported names of submodules whose names are
1.270 - # specified in the from statement.
1.271 -
1.272 - if submodule and not submodule.loaded:
1.273 - for n in submodule.keys():
1.274 - submodule.modify_name(n)
1.275 -
1.276 continue
1.277
1.278 # Support the import of names from missing modules.
1.279 @@ -1061,16 +1138,6 @@
1.280 attr = module[n]
1.281 self.store(n, attr)
1.282 self.use_specific_attribute(module.full_name(), n)
1.283 - if isinstance(attr.get_value(), Module) and not attr.get_value().loaded:
1.284 - submodule = self.importer.load(attr.get_value().name, importer=node)
1.285 -
1.286 - # For circular imports, invalidate attribute usage
1.287 - # for all exported names of submodules provided by
1.288 - # the module.
1.289 -
1.290 - if submodule and not submodule.loaded:
1.291 - for subn in submodule.keys():
1.292 - submodule.modify_name(subn)
1.293
1.294 def visitFunction(self, node):
1.295 return self._visitFunction(node, node.name)
1.296 @@ -1141,21 +1208,12 @@
1.297
1.298 def visitImport(self, node):
1.299 for name, alias in node.names:
1.300 + module = self.complete_import(name, alias)
1.301 if alias is not None:
1.302 - module = self.importer.load(name, 1, importer=node) or UnresolvedName(None, name, self)
1.303 - self.store(alias, module)
1.304 + self.store(alias, module or UnresolvedName(None, name, self))
1.305 else:
1.306 - module = self.importer.load(name, importer=node) or UnresolvedName(None, name.split(".")[0], self)
1.307 - self.store(name.split(".")[0], module)
1.308 -
1.309 - circular = module and not module.loaded
1.310 -
1.311 - # For circular imports, invalidate attribute usage for all exported
1.312 - # names of modules.
1.313 -
1.314 - if module and not module.loaded:
1.315 - for n in module.keys():
1.316 - module.modify_name(n)
1.317 + name_used = name.split(".")[0]
1.318 + self.store(name_used, module or UnresolvedName(None, name_used, self))
1.319
1.320 visitInvert = _visitOperator
1.321