2.1 --- a/micropython/data.py Sat Feb 28 19:40:15 2009 +0100
2.2 +++ b/micropython/data.py Mon Mar 02 00:04:55 2009 +0100
2.3 @@ -100,8 +100,7 @@
2.4 if name in self.globals:
2.5 self.module.set(name, value, 0)
2.6 else:
2.7 - attr = self._set(name, value)
2.8 - attr.update(value, single_assignment)
2.9 + self._set(name, value, single_assignment)
2.10
2.11 def set_module(self, name, value):
2.12
2.13 @@ -112,52 +111,56 @@
2.14 module.
2.15 """
2.16
2.17 - attr = self._set(name, value)
2.18 - if attr.assignments is None:
2.19 - attr.assignments = 1
2.20 - attr.assignment_values.add(attr.value)
2.21 + self._set(name, value, 1)
2.22
2.23 - def _set(self, name, value):
2.24 + def _set(self, name, attr_or_value, single_assignment=1):
2.25
2.26 """
2.27 - The underlying set operation associating 'name' with 'value'.
2.28 + The underlying set operation associating 'name' with the given
2.29 + 'attr_or_value'.
2.30 See: docs/assignment.txt
2.31 """
2.32
2.33 - if not self.namespace.has_key(name):
2.34 + # Add and/or obtain the namespace entry.
2.35
2.36 - # Either accept the attribute as specified.
2.37 + if not self.namespace.has_key(name):
2.38 + self.namespace[name] = Attr(None, self, name)
2.39
2.40 - if isinstance(value, Attr):
2.41 - if value.context is not None:
2.42 - self.namespace[name] = Attr(None, self, value.context, name, value.value)
2.43 - return self.namespace[name]
2.44 + attr = self.namespace[name]
2.45
2.46 - # Or accept the value of the attribute.
2.47 + # Handle attribute assignment as well as assignment of basic objects.
2.48 +
2.49 + if isinstance(attr_or_value, Attr):
2.50
2.51 - else:
2.52 - value = value.value
2.53 + # Attempt to fix the context if not explicitly defined.
2.54
2.55 - # Then/or attempt to fix the context.
2.56 + context_values = self.get_updated_context_values(attr_or_value.context_values)
2.57
2.58 - context = self._context(value)
2.59 - self.namespace[name] = Attr(None, self, context, name, value)
2.60 + else:
2.61 + context_values = self.get_updated_context_values([(None, attr_or_value)])
2.62
2.63 - return self.namespace[name]
2.64 + attr.update(context_values, single_assignment)
2.65
2.66 - def _context(self, value):
2.67 + def get_updated_context_values(self, context_values):
2.68
2.69 """
2.70 - Return the context to be used when storing the given 'value'.
2.71 + Adapt the contexts found in the given 'context_values', returning a new
2.72 + set.
2.73 See: docs/assignment.txt
2.74 """
2.75
2.76 - # Set the context of instances to themselves.
2.77 + results = set()
2.78 +
2.79 + for context, value in context_values:
2.80 +
2.81 + # Set the context of instances to themselves.
2.82
2.83 - if isinstance(value, Instance):
2.84 - return value
2.85 - else:
2.86 - return None
2.87 + if isinstance(value, Instance):
2.88 + results.add((value, value))
2.89 + else:
2.90 + results.add((context, value))
2.91 +
2.92 + return results
2.93
2.94 def make_global(self, name):
2.95 if not self.namespace.has_key(name):
2.96 @@ -166,12 +169,6 @@
2.97 else:
2.98 return 0
2.99
2.100 - def get_assignments(self, name):
2.101 - if self.assignments.has_key(name):
2.102 - return max(self.assignments[name], len(self.assignment_values[name]))
2.103 - else:
2.104 - return None
2.105 -
2.106 def attributes_as_list(self):
2.107
2.108 "Return the attributes in a list."
2.109 @@ -206,45 +203,52 @@
2.110
2.111 "An attribute entry having a context."
2.112
2.113 - def __init__(self, position, parent, context, name, value=None, assignments=None):
2.114 + def __init__(self, position, parent, name):
2.115
2.116 """
2.117 Initialise the attribute with the given 'position' within the collection
2.118 - of attributes of its 'parent', indicating the 'context' or origin of the
2.119 - attribute (where it was first defined), along with its 'name'.
2.120 -
2.121 - An optional 'value' indicates the typical contents of the attribute, and
2.122 - the optional number of 'assignments' may be used to determine whether
2.123 - the attribute is effectively constant.
2.124 + of attributes of its 'parent', indicating its 'name'.
2.125 """
2.126
2.127 self.position = position
2.128 self.parent = parent
2.129 - self.context = context
2.130 self.name = name
2.131 - self.value = value
2.132 +
2.133 + self.context_values = set()
2.134
2.135 # Number of assignments per name.
2.136
2.137 - self.assignments = assignments
2.138 - self.assignment_values = set()
2.139 + self.assignments = None
2.140
2.141 def set_referenced(self):
2.142
2.143 "Indicate that the contents are referenced via a namespace."
2.144
2.145 - for value in self.assignment_values:
2.146 - value.set_referenced()
2.147 + for value in self.get_values():
2.148 + if value is not None:
2.149 + value.set_referenced()
2.150 +
2.151 + def get_contexts(self):
2.152 + return [c for (c, v) in self.context_values]
2.153
2.154 - def update(self, value, single_assignment):
2.155 + def get_values(self):
2.156 + return [v for (c, v) in self.context_values]
2.157 +
2.158 + def get_context(self):
2.159 + return len(self.context_values) == 1 and self.get_contexts()[0] or None
2.160 +
2.161 + def get_value(self):
2.162 + return len(self.context_values) == 1 and self.get_values()[0] or None
2.163 +
2.164 + def update(self, context_values, single_assignment):
2.165
2.166 """
2.167 - Update the attribute, adding the 'value' provided to the known values
2.168 - associated with the attribute, changing the number of assignments
2.169 - according to the 'single_assignment' status of the operation, where
2.170 - a true value indicates that only one assignment is associated with the
2.171 - update, and a false value indicates that potentially many assignments
2.172 - may be involved.
2.173 + Update the attribute, adding the 'context_values' provided to the
2.174 + known details associated with the attribute, changing the number of
2.175 + assignments according to the 'single_assignment' status of the
2.176 + operation, where a true value indicates that only one assignment is
2.177 + associated with the update, and a false value indicates that potentially
2.178 + many assignments may be involved.
2.179 """
2.180
2.181 if self.assignments is None:
2.182 @@ -258,36 +262,7 @@
2.183 else:
2.184 self.assignments += AtLeast(1)
2.185
2.186 - if value is not None:
2.187 - self.assignment_values.add(value)
2.188 -
2.189 - def via_instance(self):
2.190 -
2.191 - """
2.192 - Return either this attribute or a replacement where it is being accessed
2.193 - via an instance.
2.194 - """
2.195 -
2.196 - if self.context is not None:
2.197 -
2.198 - # Check compatibility of the context with the parent.
2.199 - # Where the attribute originates within the same hierarchy, use an
2.200 - # instance as the context.
2.201 -
2.202 - if self.defined_within_hierarchy():
2.203 - context = Instance()
2.204 -
2.205 - # Otherwise, preserve the existing context.
2.206 -
2.207 - else:
2.208 - context = self.context
2.209 -
2.210 - return Attr(self.position, self.parent, context, self.name, self.value, self.assignments)
2.211 -
2.212 - # Unknown contexts remain in use.
2.213 -
2.214 - else:
2.215 - return self
2.216 + self.context_values.update(context_values)
2.217
2.218 def is_class_attribute(self):
2.219 return isinstance(self.parent, Class)
2.220 @@ -299,22 +274,47 @@
2.221 same class hierarchy.
2.222 """
2.223
2.224 - return isinstance(self.parent, Class) and isinstance(self.context, Class) and (
2.225 - self.context is self.parent or
2.226 - self.context.has_subclass(self.parent) or
2.227 - self.parent.has_subclass(self.context))
2.228 + # Must be defined within a class.
2.229 +
2.230 + if isinstance(self.parent, Class):
2.231 +
2.232 + # To be sure, all contexts must be classes and be the same as the
2.233 + # parent, or be a superclass of the parent, or be a subclass of the
2.234 + # parent.
2.235 +
2.236 + for context in self.get_contexts():
2.237 + if not (
2.238 + isinstance(context, Class) and (
2.239 + context is self.parent or
2.240 + context.has_subclass(self.parent) or
2.241 + self.parent.has_subclass(context))
2.242 + ):
2.243 + return 0
2.244 +
2.245 + return 1
2.246 +
2.247 + # Instance attributes are not defined within a hierarchy.
2.248 +
2.249 + else:
2.250 + return 0
2.251
2.252 def __repr__(self):
2.253 - return "Attr(%r, %s, %s, %r, %s, %r)" % (
2.254 - self.position, shortrepr(self.parent), shortrepr(self.context),
2.255 - self.name, shortrepr(self.value), self.assignments
2.256 + return "Attr(%r, %s, %r) # [%s], %r" % (
2.257 + self.position, shortrepr(self.parent), self.name,
2.258 + self._context_values_str(), self.assignments
2.259 )
2.260
2.261 + def _context_values_str(self):
2.262 + l = []
2.263 + for (c, v) in self.context_values:
2.264 + l.append("(c=%s, v=%s)" % (shortrepr(c), shortrepr(v)))
2.265 + return ", ".join(l)
2.266 +
2.267 def as_raw(self, objtable, paramtable):
2.268 return [
2.269 (
2.270 - self.context and self.context.location,
2.271 - self.value and self.value.location
2.272 + self.get_context() and self.get_context().location,
2.273 + self.get_value() and self.get_value().location
2.274 )
2.275 ]
2.276
2.277 @@ -357,6 +357,9 @@
2.278 Instance.__init__(self)
2.279 self.value = value
2.280
2.281 + def get_value(self):
2.282 + return value
2.283 +
2.284 def __repr__(self):
2.285 if self.location is not None:
2.286 return "Const(%r, location=%r)" % (self.value, self.location)
2.287 @@ -388,7 +391,7 @@
2.288 # Support constants as dictionary keys in order to build constant tables.
2.289
2.290 def __eq__(self, other):
2.291 - return self.value == other.value and self.value.__class__ is other.value.__class__
2.292 + return other is not None and self.value == other.value and self.value.__class__ is other.value.__class__
2.293
2.294 def __hash__(self):
2.295 return hash(self.value)
2.296 @@ -431,10 +434,6 @@
2.297 self.allattr = None # cache for all_attributes
2.298 self.allattr_names = None # from allattr
2.299
2.300 - # Add this class to its attributes.
2.301 -
2.302 - self.set("__class__", self)
2.303 -
2.304 # Image generation details.
2.305
2.306 self.location = None
2.307 @@ -449,6 +448,10 @@
2.308 self.local_usage = 0
2.309 self.all_local_usage = 0
2.310
2.311 + # Add this class to its attributes.
2.312 +
2.313 + self.set("__class__", self)
2.314 +
2.315 def set_referenced(self):
2.316 self.referenced = 1
2.317
2.318 @@ -468,7 +471,8 @@
2.319 # Append a template of an instance for use when instantiating classes.
2.320
2.321 call_method = self.get("__call__")
2.322 - call_method_code_location = call_method and call_method.value.code_location
2.323 + call_method_value = call_method and call_method.get_value()
2.324 + call_method_code_location = call_method_value and call_method_value.code_location
2.325
2.326 # NOTE: The instantiator code is the first block of the class.
2.327
2.328 @@ -478,8 +482,8 @@
2.329 DataObject(
2.330 classcode, attrcode, call_method_code_location,
2.331 (
2.332 - call_method and len(call_method.value.positional_names),
2.333 - call_method and len(call_method.value.defaults)
2.334 + call_method_value and len(call_method_value.positional_names),
2.335 + call_method_value and len(call_method_value.defaults)
2.336 ),
2.337 1,
2.338 self.full_name()
2.339 @@ -497,26 +501,26 @@
2.340
2.341 # Namespace-related methods.
2.342
2.343 - def _context(self, value):
2.344 + def get_updated_context_values(self, context_values):
2.345
2.346 """
2.347 - Return the context to be used when storing the given 'value'.
2.348 + Adapt the contexts found in the given 'context_values', returning a new
2.349 + set.
2.350 See: docs/assignment.txt
2.351 """
2.352
2.353 - if value is not None:
2.354 + results = set()
2.355 +
2.356 + for context, value in context_values:
2.357
2.358 # Change the ownership of functions.
2.359
2.360 - if isinstance(value, Function):
2.361 - context = value.parent
2.362 + if context is None and value is not None and isinstance(value, Function):
2.363 + results.add((self, value))
2.364 + else:
2.365 + results.add((context, value))
2.366
2.367 - if isinstance(context, Module):
2.368 - return self
2.369 - else:
2.370 - return context
2.371 -
2.372 - return NamespaceDict._context(self, value)
2.373 + return NamespaceDict.get_updated_context_values(self, results)
2.374
2.375 def finalise_attributes(self):
2.376
2.377 @@ -540,7 +544,7 @@
2.378 return self.instantiator
2.379
2.380 def get_init_method(self):
2.381 - return self.all_class_attributes()["__init__"].value
2.382 + return self.all_class_attributes()["__init__"].get_value()
2.383
2.384 # Class-specific methods.
2.385
2.386 @@ -734,7 +738,7 @@
2.387
2.388 d = {}
2.389 for i, name in enumerate(self._get_position_list(positions)):
2.390 - d[name] = Attr(i, Instance(), None, name, None)
2.391 + d[name] = Attr(i, Instance(), name)
2.392 return d
2.393
2.394 def _cmp_positions(self, a, b):
2.395 @@ -881,8 +885,8 @@
2.396 # Namespace-related methods.
2.397
2.398 def store_default(self, value):
2.399 - attr = Attr(None, self, None, None, value)
2.400 - attr.update(value, 1)
2.401 + attr = Attr(None, self, None)
2.402 + attr.update([(None, value)], 1)
2.403 self.default_attrs.append(attr)
2.404
2.405 def make_global(self, name):
3.1 --- a/micropython/inspect.py Sat Feb 28 19:40:15 2009 +0100
3.2 +++ b/micropython/inspect.py Mon Mar 02 00:04:55 2009 +0100
3.3 @@ -152,19 +152,17 @@
3.4 # employed in the final program.
3.5
3.6 if isinstance(value, Attr):
3.7 - attr_value = value.value
3.8
3.9 # Only remove entries for classes and functions, not methods.
3.10
3.11 - if attr_value is not None:
3.12 - for attr_value in value.assignment_values:
3.13 - if (isinstance(attr_value, Function) and not attr_value.is_method() or
3.14 - isinstance(attr_value, Class)) and not attr_value.referenced:
3.15 - pass
3.16 - else:
3.17 - break
3.18 + for attr_value in value.get_values():
3.19 + if (isinstance(attr_value, Function) and not attr_value.is_method() or
3.20 + isinstance(attr_value, Class)) and not attr_value.referenced:
3.21 + pass
3.22 else:
3.23 - del self[name]
3.24 + break
3.25 + else:
3.26 + del self[name]
3.27
3.28 # Complain about globals not initialised at the module level.
3.29
3.30 @@ -195,10 +193,10 @@
3.31 # assigned object to the class and are unreferenced.
3.32
3.33 if name not in self.importer.names_used and \
3.34 - attr.assignments == 1 and isinstance(attr.value, Function) and \
3.35 - attr.value.is_method() and not attr.value.referenced:
3.36 + attr.assignments == 1 and isinstance(attr.get_value(), Function) and \
3.37 + attr.get_value().is_method() and not attr.get_value().referenced:
3.38
3.39 - self.all_objects.remove(attr.value)
3.40 + self.all_objects.remove(attr.get_value())
3.41 del obj[name]
3.42
3.43 def finalise(self):
3.44 @@ -248,12 +246,7 @@
3.45 expression.
3.46 """
3.47
3.48 - if isinstance(self.expr, Attr):
3.49 - assigned_value = self.expr.value
3.50 - else:
3.51 - assigned_value = self.expr
3.52 -
3.53 - module.set(name, assigned_value, 0)
3.54 + module.set(name, self.expr, 0)
3.55
3.56 def store_class_attr(self, name):
3.57
3.58 @@ -263,13 +256,7 @@
3.59 """
3.60
3.61 if self.in_method and self.namespaces[-2].has_key(name):
3.62 -
3.63 - if isinstance(self.expr, Attr):
3.64 - assigned_value = self.expr.value
3.65 - else:
3.66 - assigned_value = self.expr
3.67 -
3.68 - self.namespaces[-2].set(name, assigned_value, 0)
3.69 + self.namespaces[-2].set(name, self.expr, 0)
3.70 return 1
3.71
3.72 return 0
3.73 @@ -353,10 +340,7 @@
3.74
3.75 for n in node.defaults:
3.76 self.expr = self.dispatch(n)
3.77 - if isinstance(self.expr, Attr):
3.78 - function.store_default(self.expr.value)
3.79 - else:
3.80 - function.store_default(self.expr)
3.81 + function.store_default(self.expr)
3.82
3.83 # Enter the function.
3.84
3.85 @@ -416,9 +400,9 @@
3.86 if expr.name == "self":
3.87 if not self.store_class_attr(node.attrname):
3.88 self.store_instance_attr(node.attrname)
3.89 - elif isinstance(expr.value, Module):
3.90 - self.store_module_attr(node.attrname, expr.value)
3.91 - print "Warning: attribute %r of module %r set outside the module." % (node.attrname, expr.value.name)
3.92 + elif isinstance(expr.get_value(), Module):
3.93 + self.store_module_attr(node.attrname, expr.get_value())
3.94 + print "Warning: attribute %r of module %r set outside the module." % (node.attrname, expr.get_value().name)
3.95 return None
3.96
3.97 def visitAssList(self, node):
3.98 @@ -478,7 +462,7 @@
3.99 raise InspectError(self.full_name(), node,
3.100 "Base class %r for %r is not constant." % (base, cls.full_name()))
3.101 else:
3.102 - cls.add_base(expr.value)
3.103 + cls.add_base(expr.get_value())
3.104 else: # if expr is None:
3.105 raise InspectError(self.full_name(), node,
3.106 "Base class %r for %r is not found: it may be hidden in some way." % (base, cls.full_name()))
3.107 @@ -488,7 +472,7 @@
3.108
3.109 if not node.bases and not (self.name == "__builtins__" and node.name == "object") :
3.110 expr = self.dispatch(compiler.ast.Name("object"))
3.111 - cls.add_base(expr.value)
3.112 + cls.add_base(expr.get_value())
3.113
3.114 # Make a back reference from the node for code generation.
3.115
3.116 @@ -573,9 +557,9 @@
3.117 if name != "*":
3.118 if module is not None and module.namespace.has_key(name):
3.119 attr = module[name]
3.120 - self.store(alias or name, attr.value)
3.121 - if isinstance(attr.value, Module) and not attr.value.loaded:
3.122 - self.importer.load(attr.value.name)
3.123 + self.store(alias or name, attr)
3.124 + if isinstance(attr.get_value(), Module) and not attr.get_value().loaded:
3.125 + self.importer.load(attr.get_value().name)
3.126
3.127 # Support the import of names from missing modules.
3.128
3.129 @@ -585,9 +569,9 @@
3.130 if module is not None:
3.131 for n in module.namespace.keys():
3.132 attr = module[n]
3.133 - self.store(n, attr.value)
3.134 - if isinstance(attr.value, Module) and not attr.value.loaded:
3.135 - self.importer.load(attr.value.name)
3.136 + self.store(n, attr)
3.137 + if isinstance(attr.get_value(), Module) and not attr.get_value().loaded:
3.138 + self.importer.load(attr.get_value().name)
3.139
3.140 return None
3.141
3.142 @@ -607,7 +591,7 @@
3.143 attrname = node.attrname
3.144
3.145 if isinstance(expr, Attr):
3.146 - value = expr.value
3.147 + value = expr.get_value()
3.148 if isinstance(value, (Class, Module)):
3.149 attr = value.namespace.get(attrname)
3.150 elif isinstance(value, UnresolvedName):