1.1 --- a/micropython/inspect.py Mon May 19 00:22:00 2008 +0200
1.2 +++ b/micropython/inspect.py Sat Jun 07 21:55:24 2008 +0200
1.3 @@ -17,6 +17,58 @@
1.4
1.5 You should have received a copy of the GNU General Public License along with
1.6 this program. If not, see <http://www.gnu.org/licenses/>.
1.7 +
1.8 +--------
1.9 +
1.10 +The results of inspecting a module are as follows:
1.11 +
1.12 +Constants
1.13 +---------
1.14 +
1.15 +All constants identified within the code shall be registered.
1.16 +
1.17 +Classes
1.18 +-------
1.19 +
1.20 +All global classes shall be registered; local classes (within functions) or
1.21 +nested classes (within classes) are not currently registered.
1.22 +
1.23 +Base classes must be detected and constant.
1.24 +
1.25 +All classes without bases are made to inherit from __builtins__.object in order
1.26 +to support some standard methods.
1.27 +
1.28 +Functions
1.29 +---------
1.30 +
1.31 +All functions and lambda definitions shall be registered.
1.32 +
1.33 +Namespaces
1.34 +----------
1.35 +
1.36 +Modules define their own "global" namespace, within which classes, functions
1.37 +and lambda definitions establish a hierarchy of namespaces.
1.38 +
1.39 +Only local, global and built-in namespaces are recognised; closures are not
1.40 +supported.
1.41 +
1.42 +Assignments
1.43 +-----------
1.44 +
1.45 +Name assignment and attribute assignment involving modules and classes cause
1.46 +names to be associated with values within namespaces.
1.47 +
1.48 +Any assignments within loops are considered to cause the targets of such
1.49 +assignments to provide non-constant values.
1.50 +
1.51 +Assignments to names are only really considered to cause the targets of such
1.52 +assignments to provide constant values if the targets reside in the module
1.53 +namespace or in class namespaces, subject to the above conditions.
1.54 +
1.55 +Assignments to names within functions are not generally considered to cause the
1.56 +targets of such assignments to provide constant values since functions can be
1.57 +invoked many times with different inputs. However, there may be benefits in
1.58 +considering a local to be constant within a single invocation.
1.59 """
1.60
1.61 from micropython.common import *
1.62 @@ -44,6 +96,8 @@
1.63 Module.__init__(self, name)
1.64 self.visitor = self
1.65
1.66 + # Import machinery links.
1.67 +
1.68 self.importer = importer
1.69 self.builtins = self.importer.modules.get("__builtins__")
1.70 self.loaded = 0
1.71 @@ -59,6 +113,7 @@
1.72 # Namespace state.
1.73
1.74 self.in_init = 0 # Find instance attributes in __init__ methods.
1.75 + self.in_method = 0 # Find instance attributes in all methods.
1.76 self.in_loop = 0 # Note loop "membership", affecting assignments.
1.77 self.namespaces = []
1.78 self.module = None
1.79 @@ -74,7 +129,7 @@
1.80
1.81 "Process the given 'module'."
1.82
1.83 - self.node = self.module = module
1.84 + self.astnode = self.module = module
1.85 processed = self.dispatch(module)
1.86 if self.has_key("__all__"):
1.87 all = self["__all__"]
1.88 @@ -113,13 +168,32 @@
1.89 self.all_objects.add(obj)
1.90
1.91 def store_lambda(self, obj):
1.92 +
1.93 + "Store a lambda function 'obj'."
1.94 +
1.95 self.all_objects.add(obj)
1.96
1.97 + def store_class_attr(self, name):
1.98 +
1.99 + "Record class attribute 'name' in the current class."
1.100 +
1.101 + if self.in_method and self.namespaces[-2].has_key(name):
1.102 +
1.103 + if isinstance(self.expr, Attr):
1.104 + assigned_value = self.expr.value
1.105 + else:
1.106 + assigned_value = self.expr
1.107 +
1.108 + self.namespaces[-2].set(name, assigned_value, 0)
1.109 + return 1
1.110 +
1.111 + return 0
1.112 +
1.113 def store_instance_attr(self, name):
1.114
1.115 "Record instance attribute 'name' in the current class."
1.116
1.117 - if self.in_init:
1.118 + if self.in_method:
1.119
1.120 # Current namespace is the function.
1.121 # Previous namespace is the class.
1.122 @@ -150,6 +224,15 @@
1.123 self.dispatch(n)
1.124 return Instance()
1.125
1.126 + def _visitConst(self, node):
1.127 + return self._make_constant(node.value)
1.128 +
1.129 + def _make_constant(self, value):
1.130 + if not self.constant_values.has_key(value):
1.131 + const = Const(value)
1.132 + self.constant_values[value] = const
1.133 + return self.constant_values[value]
1.134 +
1.135 def _visitFunction(self, node, name):
1.136
1.137 """
1.138 @@ -189,11 +272,14 @@
1.139 # Current namespace is the function.
1.140 # Previous namespace is the class.
1.141
1.142 - if name == "__init__" and isinstance(self.namespaces[-2], Class):
1.143 - self.in_init = 1
1.144 + if len(self.namespaces) > 1 and isinstance(self.namespaces[-2], Class):
1.145 + if name == "__init__":
1.146 + self.in_init = 1
1.147 + self.in_method = 1
1.148
1.149 self.dispatch(node.code)
1.150 self.in_init = 0
1.151 + self.in_method = 0
1.152 self.namespaces.pop()
1.153
1.154 if name is not None:
1.155 @@ -218,7 +304,8 @@
1.156 def visitAssAttr(self, node):
1.157 expr = self.dispatch(node.expr)
1.158 if isinstance(expr, Attr) and expr.name == "self":
1.159 - self.store_instance_attr(node.attrname)
1.160 + if not self.store_class_attr(node.attrname):
1.161 + self.store_instance_attr(node.attrname)
1.162 return None
1.163
1.164 def visitAssList(self, node):
1.165 @@ -250,6 +337,12 @@
1.166 visitCallFunc = OP
1.167
1.168 def visitClass(self, node):
1.169 +
1.170 + """
1.171 + Register the class at the given 'node' subject to the restrictions
1.172 + mentioned in the module docstring.
1.173 + """
1.174 +
1.175 if self.namespaces:
1.176 print "Class %r in %r is not global: ignored." % (node.name, self.namespaces[-1].full_name())
1.177 return None
1.178 @@ -297,9 +390,7 @@
1.179 visitCompare = OP
1.180
1.181 def visitConst(self, node):
1.182 - const = Const(node.value)
1.183 - self.constant_values[node.value] = const
1.184 - return const
1.185 + return self._visitConst(node)
1.186
1.187 visitContinue = NOP
1.188
1.189 @@ -411,8 +502,7 @@
1.190
1.191 def visitKeyword(self, node):
1.192 self.dispatch(node.expr)
1.193 - const = Const(node.name)
1.194 - self.constant_values[node.name] = const
1.195 + self._visitConst(node)
1.196 self.keyword_names.add(node.name)
1.197 return None
1.198
1.199 @@ -439,9 +529,7 @@
1.200 def visitName(self, node):
1.201 name = node.name
1.202 if name == "None":
1.203 - const = Const(None)
1.204 - self.constant_values[None] = const
1.205 - return const
1.206 + return self._make_constant(None)
1.207 elif self.namespaces and self.namespaces[-1].has_key(name):
1.208 return self.namespaces[-1][name]
1.209 elif self.has_key(name):