1.1 --- a/micropython/inspect.py Tue Oct 28 01:08:06 2008 +0100
1.2 +++ b/micropython/inspect.py Sat Nov 08 21:15:11 2008 +0100
1.3 @@ -85,6 +85,14 @@
1.4 capable of being used as an AST visitor.
1.5 """
1.6
1.7 + predefined_constants = {
1.8 + "None" : None,
1.9 + "True" : True,
1.10 + "False" : False,
1.11 + "Ellipsis" : Ellipsis,
1.12 + "NotImplemented" : NotImplemented
1.13 + }
1.14 +
1.15 def __init__(self, name, importer):
1.16
1.17 """
1.18 @@ -99,6 +107,7 @@
1.19 # Import machinery links.
1.20
1.21 self.importer = importer
1.22 + self.optimisations = importer.optimisations
1.23 self.builtins = self.importer.modules.get("__builtins__")
1.24 self.loaded = 0
1.25
1.26 @@ -106,6 +115,11 @@
1.27
1.28 self.constant_values = importer.constant_values
1.29
1.30 + # Ensure the predefined constants.
1.31 +
1.32 + for name, value in self.predefined_constants.items():
1.33 + self._make_constant(value)
1.34 +
1.35 # Current expression state.
1.36
1.37 self.expr = None
1.38 @@ -135,7 +149,7 @@
1.39 all = self["__all__"]
1.40 if isinstance(all, compiler.ast.List):
1.41 for n in all.nodes:
1.42 - self[n.value] = self.importer.add_module(self.name + "." + n.value)
1.43 + self.store(n.value, self.importer.add_module(self.name + "." + n.value))
1.44 return processed
1.45
1.46 def vacuum(self):
1.47 @@ -143,14 +157,63 @@
1.48 "Vacuum the module namespace, removing unloaded module references."
1.49
1.50 for name, value in self.items():
1.51 - if isinstance(value, Module) and not value.loaded:
1.52 - del self[name]
1.53 +
1.54 + if isinstance(value, Attr):
1.55 + attr_value = value.value
1.56 +
1.57 + # Remove non-loaded modules.
1.58 +
1.59 + if isinstance(attr_value, Module) and not attr_value.loaded:
1.60 + del self[name]
1.61 +
1.62 + # Remove unreferenced names.
1.63 + # NOTE: This, due to the nature of the referenced attribute, assumes
1.64 + # NOTE: that only explicitly mentioned classes and functions are
1.65 + # NOTE: employed in the final program.
1.66 +
1.67 + elif self.should_optimise_unused_objects():
1.68 +
1.69 + # Only remove entries for classes and functions, not methods.
1.70 +
1.71 + for attr_value in value.assignment_values:
1.72 + if (isinstance(attr_value, Function) and not attr_value.is_method() or
1.73 + isinstance(attr_value, Class)) and not attr_value.referenced:
1.74 + pass
1.75 + else:
1.76 + break
1.77 + else:
1.78 + del self[name]
1.79
1.80 # Complain about globals not initialised at the module level.
1.81
1.82 - if isinstance(value, Global):
1.83 + elif isinstance(value, Global):
1.84 print "Warning: global %r in module %r not initialised at the module level." % (name, self.name)
1.85
1.86 + # Remove unreferenced objects.
1.87 +
1.88 + if self.should_optimise_unused_objects():
1.89 +
1.90 + all_objects = list(self.all_objects)
1.91 +
1.92 + for obj in all_objects:
1.93 + if not obj.referenced:
1.94 + self.all_objects.remove(obj)
1.95 +
1.96 + def add_object(self, obj, any_scope=0):
1.97 +
1.98 + """
1.99 + Record 'obj' if non-local or if the optional 'any_scope' is set to a
1.100 + true value.
1.101 + """
1.102 +
1.103 + if any_scope or not (self.namespaces and isinstance(self.namespaces[-1], Function)):
1.104 + self.all_objects.add(obj)
1.105 +
1.106 + # Optimisation tests.
1.107 +
1.108 + def should_optimise_unused_objects(self):
1.109 + return "unused_objects" in self.optimisations
1.110 +
1.111 # Namespace methods.
1.112
1.113 def store(self, name, obj):
1.114 @@ -162,16 +225,11 @@
1.115 else:
1.116 self.namespaces[-1].set(name, obj, not self.in_loop)
1.117
1.118 - # Record all non-local objects.
1.119 -
1.120 - if not (self.namespaces and isinstance(self.namespaces[-1], Function)):
1.121 - self.all_objects.add(obj)
1.122 -
1.123 def store_lambda(self, obj):
1.124
1.125 "Store a lambda function 'obj'."
1.126
1.127 - self.all_objects.add(obj)
1.128 + self.add_object(obj)
1.129
1.130 def store_module_attr(self, name, module):
1.131
1.132 @@ -300,9 +358,21 @@
1.133 self.store(name, function)
1.134 else:
1.135 self.store_lambda(function)
1.136 +
1.137 + # Lambda functions are always assumed to be referenced. This is
1.138 + # because other means of discovering the referencing of objects rely
1.139 + # on the original names inherent in the definition of those objects.
1.140 +
1.141 + function.set_referenced()
1.142 +
1.143 + # Where defaults exist, an instance needs creating. Thus, it makes
1.144 + # no sense to return a reference to the function here, since the
1.145 + # recipient will not be referencing the function itself.
1.146 +
1.147 if node.defaults:
1.148 - return None # NOTE: See lambda code in the ast module.
1.149 + return Instance() # indicates no known target
1.150
1.151 + self.add_object(function, any_scope=1)
1.152 return function
1.153
1.154 visitAdd = OP
1.155 @@ -396,6 +466,7 @@
1.156 # Make an entry for the class.
1.157
1.158 self.store(node.name, cls)
1.159 + self.add_object(cls)
1.160
1.161 # Process the class body.
1.162
1.163 @@ -437,6 +508,9 @@
1.164 def visitFrom(self, node):
1.165 module = self.importer.load(node.modname, 1)
1.166
1.167 + if module is not None:
1.168 + module.set_referenced()
1.169 +
1.170 #if module is None:
1.171 # print "Warning:", node.modname, "not imported."
1.172
1.173 @@ -445,8 +519,8 @@
1.174 if module is not None and module.namespace.has_key(name):
1.175 attr = module[name]
1.176 self.store(alias or name, attr.value)
1.177 - if isinstance(attr, Module) and not attr.loaded:
1.178 - self.importer.load(attr.name)
1.179 + if isinstance(attr.value, Module) and not attr.value.loaded:
1.180 + self.importer.load(attr.value.name)
1.181
1.182 # Support the import of names from missing modules.
1.183
1.184 @@ -457,8 +531,8 @@
1.185 for n in module.namespace.keys():
1.186 attr = module[n]
1.187 self.store(n, attr.value)
1.188 - if isinstance(attr, Module) and not attr.loaded:
1.189 - self.importer.load(attr.name)
1.190 + if isinstance(attr.value, Module) and not attr.value.loaded:
1.191 + self.importer.load(attr.value.name)
1.192
1.193 return None
1.194
1.195 @@ -478,15 +552,20 @@
1.196 if isinstance(expr, Attr):
1.197 value = expr.value
1.198 if isinstance(value, (Class, Module)):
1.199 - return value.namespace.get(node.attrname)
1.200 + attr = value.namespace.get(node.attrname)
1.201 elif isinstance(value, UnresolvedName):
1.202 - return UnresolvedName(node.attrname, value.full_name(), self)
1.203 + attr = UnresolvedName(node.attrname, value.full_name(), self)
1.204 else:
1.205 - return None
1.206 - if self.builtins is not None:
1.207 - return self.builtins.get(node.attrname)
1.208 + attr = None
1.209 + elif self.builtins is not None:
1.210 + attr = self.builtins.get(node.attrname)
1.211 else:
1.212 - return UnresolvedName(node.attrname, value.full_name(), self)
1.213 + attr = UnresolvedName(node.attrname, value.full_name(), self)
1.214 +
1.215 + if attr is not None:
1.216 + attr.set_referenced()
1.217 +
1.218 + return attr
1.219
1.220 def visitGlobal(self, node):
1.221 if self.namespaces:
1.222 @@ -510,9 +589,12 @@
1.223 def visitImport(self, node):
1.224 for name, alias in node.names:
1.225 if alias is not None:
1.226 - self.store(alias, self.importer.load(name, 1) or UnresolvedName(None, name, self))
1.227 + module = self.importer.load(name, 1) or UnresolvedName(None, name, self)
1.228 + self.store(alias, module)
1.229 else:
1.230 - self.store(name.split(".")[0], self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self))
1.231 + module = self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self)
1.232 + self.store(name.split(".")[0], module)
1.233 + module.set_referenced()
1.234
1.235 return None
1.236
1.237 @@ -550,16 +632,21 @@
1.238
1.239 def visitName(self, node):
1.240 name = node.name
1.241 - if name == "None":
1.242 - return self._make_constant(None)
1.243 + if self.predefined_constants.has_key(name):
1.244 + attr = self._make_constant(self.predefined_constants[name])
1.245 elif self.namespaces and self.namespaces[-1].has_key(name):
1.246 - return self.namespaces[-1][name]
1.247 + attr = self.namespaces[-1][name]
1.248 elif self.has_key(name):
1.249 - return self[name]
1.250 + attr = self[name]
1.251 elif self.builtins is not None and self.builtins.has_key(name):
1.252 - return self.builtins[name]
1.253 + attr = self.builtins[name]
1.254 else:
1.255 - return None
1.256 + attr = None
1.257 +
1.258 + if attr is not None:
1.259 + attr.set_referenced()
1.260 +
1.261 + return attr
1.262
1.263 visitNot = OP
1.264