1.1 --- a/micropython/data.py Sun Jun 13 02:24:35 2010 +0200
1.2 +++ b/micropython/data.py Mon Jun 14 01:46:42 2010 +0200
1.3 @@ -53,6 +53,7 @@
1.4 """
1.5
1.6 from micropython.program import DataObject, DataValue, ReplaceableContext, PlaceholderContext
1.7 +from micropython.common import AtLeast, InspectError
1.8
1.9 def shortrepr(obj):
1.10 if obj is None:
1.11 @@ -60,51 +61,6 @@
1.12 else:
1.13 return obj.__shortrepr__()
1.14
1.15 -# Special representations.
1.16 -
1.17 -class AtLeast:
1.18 -
1.19 - "A special representation for numbers of a given value or greater."
1.20 -
1.21 - def __init__(self, count):
1.22 - self.count = count
1.23 -
1.24 - def __eq__(self, other):
1.25 - return 0
1.26 -
1.27 - __lt__ = __le__ = __eq__
1.28 -
1.29 - def __ne__(self, other):
1.30 - return 1
1.31 -
1.32 - def __gt__(self, other):
1.33 - if isinstance(other, AtLeast):
1.34 - return 0
1.35 - else:
1.36 - return self.count > other
1.37 -
1.38 - def __ge__(self, other):
1.39 - if isinstance(other, AtLeast):
1.40 - return 0
1.41 - else:
1.42 - return self.count >= other
1.43 -
1.44 - def __iadd__(self, other):
1.45 - if isinstance(other, AtLeast):
1.46 - self.count += other.count
1.47 - else:
1.48 - self.count += other
1.49 - return self
1.50 -
1.51 - def __radd__(self, other):
1.52 - if isinstance(other, AtLeast):
1.53 - return AtLeast(self.count + other.count)
1.54 - else:
1.55 - return AtLeast(self.count + other)
1.56 -
1.57 - def __repr__(self):
1.58 - return "AtLeast(%r)" % self.count
1.59 -
1.60 # Mix-ins and abstract classes.
1.61
1.62 class Naming:
1.63 @@ -122,10 +78,9 @@
1.64 "A mix-in providing dictionary methods."
1.65
1.66 def __init__(self, module=None):
1.67 + self.module = module
1.68 self.namespace = {}
1.69 self.globals = set()
1.70 - self.scope_usage = {}
1.71 - self.module = module
1.72 self.finalised = 0
1.73
1.74 # Attributes accessed on objects, potentially narrowing their types.
1.75 @@ -138,7 +93,13 @@
1.76 self.user_shelves = []
1.77 self.loop_users = [{}] # stack of loop nodes
1.78
1.79 + # Scope usage, indicating the origin of names.
1.80 +
1.81 + self.scope_usage = [{}] # stack of scope usage
1.82 + self.scope_shelves = []
1.83 +
1.84 # Define attribute usage to identify active program sections.
1.85 + # Attribute users are AST nodes defining names.
1.86
1.87 self.all_attribute_users = set()
1.88
1.89 @@ -162,6 +123,56 @@
1.90 def __getitem__(self, name):
1.91 return self.namespace[name]
1.92
1.93 + def get_using_node(self, name, node):
1.94 +
1.95 + """
1.96 + Access the given 'name' through this namespace, making use of the module
1.97 + and builtins namespaces if necessary, annotating the given 'node' with
1.98 + the scope involved.
1.99 + """
1.100 +
1.101 + attr, scope, full_name = self._get_with_scope(name)
1.102 +
1.103 + if scope is not None:
1.104 + node._scope = scope
1.105 + self.note_scope(name, scope)
1.106 +
1.107 + if full_name is not None:
1.108 + self.use_specific_attribute(full_name, name)
1.109 +
1.110 + return attr
1.111 +
1.112 + def _get_with_scope(self, name, external=0):
1.113 +
1.114 + module = self.module
1.115 + builtins = module and module.builtins or None
1.116 + importer = module and module.importer or None
1.117 +
1.118 + # Constants.
1.119 +
1.120 + if importer is not None and importer.predefined_constants.has_key(name):
1.121 + return importer.get_predefined_constant(name), "constant", None
1.122 +
1.123 + # Locals.
1.124 +
1.125 + elif not external and self.has_key(name):
1.126 + return self[name], "local", self.full_name()
1.127 +
1.128 + # Globals.
1.129 +
1.130 + elif module is not None and module.has_key(name):
1.131 + return module[name], "global", module.full_name()
1.132 +
1.133 + # Builtins.
1.134 +
1.135 + elif builtins is not None and builtins.has_key(name):
1.136 + return builtins[name], "builtins", builtins.full_name()
1.137 +
1.138 + # Unknown.
1.139 +
1.140 + else:
1.141 + return None, None, None
1.142 +
1.143 def get(self, name, default=None):
1.144 return self.namespace.get(name, default)
1.145
1.146 @@ -181,6 +192,7 @@
1.147 self.module.set(name, value, 0)
1.148 else:
1.149 self._set(name, value, single_assignment)
1.150 + self.note_scope(name, "local")
1.151
1.152 def set_module(self, name, value):
1.153
1.154 @@ -268,31 +280,11 @@
1.155
1.156 if not self.namespace.has_key(name):
1.157 self.globals.add(name)
1.158 + self.note_scope(name, "global")
1.159 return 1
1.160 else:
1.161 return 0
1.162
1.163 - def note_scope(self, name, scope):
1.164 -
1.165 - "Note usage of 'name' from the given 'scope' in the current namespace."
1.166 -
1.167 - if not self.scope_usage.has_key(name):
1.168 - self.scope_usage[name] = scope
1.169 - return 1
1.170 - elif self.scope_usage[name] == scope:
1.171 - return 1
1.172 - else:
1.173 - return 0
1.174 -
1.175 - def used_in_scope(self, name, scope):
1.176 -
1.177 - """
1.178 - Return whether 'name' is used from the given 'scope' in the current
1.179 - namespace.
1.180 - """
1.181 -
1.182 - return self.scope_usage.get(name) == scope
1.183 -
1.184 # Attribute positioning.
1.185
1.186 def attributes_as_list(self):
1.187 @@ -346,6 +338,24 @@
1.188
1.189 return self._use_attribute(name, attrname)
1.190
1.191 + def use_specific_attribute(self, objname, attrname):
1.192 +
1.193 + """
1.194 + Note attribute usage specifically on 'objname' - an object which is
1.195 + known at inspection time - or in the current unit if 'objname' is None,
1.196 + nominating a specific attribute 'attrname'.
1.197 +
1.198 + This bypasses attribute user mechanisms.
1.199 + """
1.200 +
1.201 + from_name = self.full_name()
1.202 + objname = objname or from_name
1.203 + module = self.module
1.204 + importer = module and module.importer
1.205 +
1.206 + if importer is not None:
1.207 + importer.use_specific_name(objname, attrname, from_name)
1.208 +
1.209 # These shadow various methods in the InspectedModule class, and provide
1.210 # implementations generally.
1.211
1.212 @@ -417,6 +427,8 @@
1.213
1.214 node._attrnames[name] = set()
1.215
1.216 + # Branch management methods.
1.217 +
1.218 def _new_branchpoint(self):
1.219
1.220 """
1.221 @@ -425,6 +437,7 @@
1.222 """
1.223
1.224 self.user_shelves.append([])
1.225 + self.scope_shelves.append([])
1.226
1.227 def _new_branch(self, loop_node=None):
1.228
1.229 @@ -438,24 +451,31 @@
1.230
1.231 # Retain a record of active users.
1.232
1.233 - d = {}
1.234 - d.update(self.attribute_users[-1])
1.235 - self.attribute_users.append(d)
1.236 + new_users = {}
1.237 + new_users.update(self.attribute_users[-1])
1.238 + self.attribute_users.append(new_users)
1.239
1.240 - new_users = self.attribute_users[-1]
1.241 + # Where a loop is the cause of the branch, register the loop node as a
1.242 + # user of each name so that attribute usage is also recorded for the
1.243 + # loop.
1.244
1.245 - d = {}
1.246 - d.update(self.loop_users[-1])
1.247 + loop_users = {}
1.248 + loop_users.update(self.loop_users[-1])
1.249 + self.loop_users.append(loop_users)
1.250
1.251 if loop_node is not None:
1.252 for name in new_users.keys():
1.253 - if not d.has_key(name):
1.254 - d[name] = set([loop_node])
1.255 + if not loop_users.has_key(name):
1.256 + loop_users[name] = set([loop_node])
1.257 else:
1.258 - d[name] = d[name].union([loop_node])
1.259 + loop_users[name] = loop_users[name].union([loop_node])
1.260 self._init_attribute_user_for_name(loop_node, name)
1.261
1.262 - self.loop_users.append(d)
1.263 + # Retain a record of scope usage.
1.264 +
1.265 + scope_usage = {}
1.266 + scope_usage.update(self.scope_usage[-1])
1.267 + self.scope_usage.append(scope_usage)
1.268
1.269 def _abandon_branch(self):
1.270 pass
1.271 @@ -472,6 +492,9 @@
1.272 users = self.attribute_users.pop()
1.273 self.user_shelves[-1].append(users)
1.274
1.275 + scope_usage = self.scope_usage.pop()
1.276 + self.scope_shelves[-1].append(scope_usage)
1.277 +
1.278 def _merge_branches(self):
1.279
1.280 """
1.281 @@ -513,6 +536,60 @@
1.282
1.283 self.attribute_users[-1] = new_users
1.284
1.285 + # Combine the scope usage.
1.286 +
1.287 + scope_usage = self.scope_usage[-1]
1.288 + new_scope_usage = {}
1.289 +
1.290 + all_scope_usage = self.scope_shelves.pop()
1.291 + all_scope_names = set()
1.292 +
1.293 + # Find all the names for whom scope information has been defined.
1.294 +
1.295 + for shelved_usage in all_scope_usage:
1.296 + all_scope_names.update(shelved_usage.keys())
1.297 +
1.298 + for shelved_usage in all_scope_usage:
1.299 + for name in all_scope_names:
1.300 +
1.301 + # Find the recorded scope for the name.
1.302 +
1.303 + if shelved_usage.has_key(name):
1.304 + scope = shelved_usage[name]
1.305 + elif scope_usage.has_key(name):
1.306 + scope = scope_usage[name]
1.307 +
1.308 + # If no scope is recorded, find a suitable external source.
1.309 +
1.310 + else:
1.311 + attr, scope, full_name = self._get_with_scope(name, external=1)
1.312 +
1.313 + # Attempt to record the scope, testing for conflicts.
1.314 +
1.315 + if scope:
1.316 + if not new_scope_usage.has_key(name):
1.317 + new_scope_usage[name] = scope
1.318 + elif new_scope_usage[name] != scope:
1.319 + raise InspectError("Scope conflict for %r." % name)
1.320 +
1.321 + # Scope usage methods.
1.322 +
1.323 + def note_scope(self, name, scope):
1.324 +
1.325 + "Note usage of 'name' from the given 'scope' in the current namespace."
1.326 +
1.327 + self.scope_usage[-1][name] = scope
1.328 +
1.329 + def used_in_scope(self, name, scope):
1.330 +
1.331 + """
1.332 + Return whether 'name' is used from the given 'scope' in the current
1.333 + namespace.
1.334 + """
1.335 +
1.336 + scope_usage = self.scope_usage[-1]
1.337 + return scope_usage.get(name) == scope
1.338 +
1.339 # Program data structures.
1.340
1.341 class Attr:
1.342 @@ -1409,9 +1486,10 @@
1.343
1.344 "An inspected module's core details."
1.345
1.346 - def __init__(self, name):
1.347 + def __init__(self, name, importer):
1.348 NamespaceDict.__init__(self, self)
1.349 self.name = name
1.350 + self.importer = importer
1.351 self.parent = None
1.352
1.353 # Original location details.