1.1 --- a/micropython/data.py Sat Feb 28 19:40:15 2009 +0100
1.2 +++ b/micropython/data.py Mon Mar 02 00:04:55 2009 +0100
1.3 @@ -100,8 +100,7 @@
1.4 if name in self.globals:
1.5 self.module.set(name, value, 0)
1.6 else:
1.7 - attr = self._set(name, value)
1.8 - attr.update(value, single_assignment)
1.9 + self._set(name, value, single_assignment)
1.10
1.11 def set_module(self, name, value):
1.12
1.13 @@ -112,52 +111,56 @@
1.14 module.
1.15 """
1.16
1.17 - attr = self._set(name, value)
1.18 - if attr.assignments is None:
1.19 - attr.assignments = 1
1.20 - attr.assignment_values.add(attr.value)
1.21 + self._set(name, value, 1)
1.22
1.23 - def _set(self, name, value):
1.24 + def _set(self, name, attr_or_value, single_assignment=1):
1.25
1.26 """
1.27 - The underlying set operation associating 'name' with 'value'.
1.28 + The underlying set operation associating 'name' with the given
1.29 + 'attr_or_value'.
1.30 See: docs/assignment.txt
1.31 """
1.32
1.33 - if not self.namespace.has_key(name):
1.34 + # Add and/or obtain the namespace entry.
1.35
1.36 - # Either accept the attribute as specified.
1.37 + if not self.namespace.has_key(name):
1.38 + self.namespace[name] = Attr(None, self, name)
1.39
1.40 - if isinstance(value, Attr):
1.41 - if value.context is not None:
1.42 - self.namespace[name] = Attr(None, self, value.context, name, value.value)
1.43 - return self.namespace[name]
1.44 + attr = self.namespace[name]
1.45
1.46 - # Or accept the value of the attribute.
1.47 + # Handle attribute assignment as well as assignment of basic objects.
1.48 +
1.49 + if isinstance(attr_or_value, Attr):
1.50
1.51 - else:
1.52 - value = value.value
1.53 + # Attempt to fix the context if not explicitly defined.
1.54
1.55 - # Then/or attempt to fix the context.
1.56 + context_values = self.get_updated_context_values(attr_or_value.context_values)
1.57
1.58 - context = self._context(value)
1.59 - self.namespace[name] = Attr(None, self, context, name, value)
1.60 + else:
1.61 + context_values = self.get_updated_context_values([(None, attr_or_value)])
1.62
1.63 - return self.namespace[name]
1.64 + attr.update(context_values, single_assignment)
1.65
1.66 - def _context(self, value):
1.67 + def get_updated_context_values(self, context_values):
1.68
1.69 """
1.70 - Return the context to be used when storing the given 'value'.
1.71 + Adapt the contexts found in the given 'context_values', returning a new
1.72 + set.
1.73 See: docs/assignment.txt
1.74 """
1.75
1.76 - # Set the context of instances to themselves.
1.77 + results = set()
1.78 +
1.79 + for context, value in context_values:
1.80 +
1.81 + # Set the context of instances to themselves.
1.82
1.83 - if isinstance(value, Instance):
1.84 - return value
1.85 - else:
1.86 - return None
1.87 + if isinstance(value, Instance):
1.88 + results.add((value, value))
1.89 + else:
1.90 + results.add((context, value))
1.91 +
1.92 + return results
1.93
1.94 def make_global(self, name):
1.95 if not self.namespace.has_key(name):
1.96 @@ -166,12 +169,6 @@
1.97 else:
1.98 return 0
1.99
1.100 - def get_assignments(self, name):
1.101 - if self.assignments.has_key(name):
1.102 - return max(self.assignments[name], len(self.assignment_values[name]))
1.103 - else:
1.104 - return None
1.105 -
1.106 def attributes_as_list(self):
1.107
1.108 "Return the attributes in a list."
1.109 @@ -206,45 +203,52 @@
1.110
1.111 "An attribute entry having a context."
1.112
1.113 - def __init__(self, position, parent, context, name, value=None, assignments=None):
1.114 + def __init__(self, position, parent, name):
1.115
1.116 """
1.117 Initialise the attribute with the given 'position' within the collection
1.118 - of attributes of its 'parent', indicating the 'context' or origin of the
1.119 - attribute (where it was first defined), along with its 'name'.
1.120 -
1.121 - An optional 'value' indicates the typical contents of the attribute, and
1.122 - the optional number of 'assignments' may be used to determine whether
1.123 - the attribute is effectively constant.
1.124 + of attributes of its 'parent', indicating its 'name'.
1.125 """
1.126
1.127 self.position = position
1.128 self.parent = parent
1.129 - self.context = context
1.130 self.name = name
1.131 - self.value = value
1.132 +
1.133 + self.context_values = set()
1.134
1.135 # Number of assignments per name.
1.136
1.137 - self.assignments = assignments
1.138 - self.assignment_values = set()
1.139 + self.assignments = None
1.140
1.141 def set_referenced(self):
1.142
1.143 "Indicate that the contents are referenced via a namespace."
1.144
1.145 - for value in self.assignment_values:
1.146 - value.set_referenced()
1.147 + for value in self.get_values():
1.148 + if value is not None:
1.149 + value.set_referenced()
1.150 +
1.151 + def get_contexts(self):
1.152 + return [c for (c, v) in self.context_values]
1.153
1.154 - def update(self, value, single_assignment):
1.155 + def get_values(self):
1.156 + return [v for (c, v) in self.context_values]
1.157 +
1.158 + def get_context(self):
1.159 + return len(self.context_values) == 1 and self.get_contexts()[0] or None
1.160 +
1.161 + def get_value(self):
1.162 + return len(self.context_values) == 1 and self.get_values()[0] or None
1.163 +
1.164 + def update(self, context_values, single_assignment):
1.165
1.166 """
1.167 - Update the attribute, adding the 'value' provided to the known values
1.168 - associated with the attribute, changing the number of assignments
1.169 - according to the 'single_assignment' status of the operation, where
1.170 - a true value indicates that only one assignment is associated with the
1.171 - update, and a false value indicates that potentially many assignments
1.172 - may be involved.
1.173 + Update the attribute, adding the 'context_values' provided to the
1.174 + known details associated with the attribute, changing the number of
1.175 + assignments according to the 'single_assignment' status of the
1.176 + operation, where a true value indicates that only one assignment is
1.177 + associated with the update, and a false value indicates that potentially
1.178 + many assignments may be involved.
1.179 """
1.180
1.181 if self.assignments is None:
1.182 @@ -258,36 +262,7 @@
1.183 else:
1.184 self.assignments += AtLeast(1)
1.185
1.186 - if value is not None:
1.187 - self.assignment_values.add(value)
1.188 -
1.189 - def via_instance(self):
1.190 -
1.191 - """
1.192 - Return either this attribute or a replacement where it is being accessed
1.193 - via an instance.
1.194 - """
1.195 -
1.196 - if self.context is not None:
1.197 -
1.198 - # Check compatibility of the context with the parent.
1.199 - # Where the attribute originates within the same hierarchy, use an
1.200 - # instance as the context.
1.201 -
1.202 - if self.defined_within_hierarchy():
1.203 - context = Instance()
1.204 -
1.205 - # Otherwise, preserve the existing context.
1.206 -
1.207 - else:
1.208 - context = self.context
1.209 -
1.210 - return Attr(self.position, self.parent, context, self.name, self.value, self.assignments)
1.211 -
1.212 - # Unknown contexts remain in use.
1.213 -
1.214 - else:
1.215 - return self
1.216 + self.context_values.update(context_values)
1.217
1.218 def is_class_attribute(self):
1.219 return isinstance(self.parent, Class)
1.220 @@ -299,22 +274,47 @@
1.221 same class hierarchy.
1.222 """
1.223
1.224 - return isinstance(self.parent, Class) and isinstance(self.context, Class) and (
1.225 - self.context is self.parent or
1.226 - self.context.has_subclass(self.parent) or
1.227 - self.parent.has_subclass(self.context))
1.228 + # Must be defined within a class.
1.229 +
1.230 + if isinstance(self.parent, Class):
1.231 +
1.232 + # To be sure, all contexts must be classes and be the same as the
1.233 + # parent, or be a superclass of the parent, or be a subclass of the
1.234 + # parent.
1.235 +
1.236 + for context in self.get_contexts():
1.237 + if not (
1.238 + isinstance(context, Class) and (
1.239 + context is self.parent or
1.240 + context.has_subclass(self.parent) or
1.241 + self.parent.has_subclass(context))
1.242 + ):
1.243 + return 0
1.244 +
1.245 + return 1
1.246 +
1.247 + # Instance attributes are not defined within a hierarchy.
1.248 +
1.249 + else:
1.250 + return 0
1.251
1.252 def __repr__(self):
1.253 - return "Attr(%r, %s, %s, %r, %s, %r)" % (
1.254 - self.position, shortrepr(self.parent), shortrepr(self.context),
1.255 - self.name, shortrepr(self.value), self.assignments
1.256 + return "Attr(%r, %s, %r) # [%s], %r" % (
1.257 + self.position, shortrepr(self.parent), self.name,
1.258 + self._context_values_str(), self.assignments
1.259 )
1.260
1.261 + def _context_values_str(self):
1.262 + l = []
1.263 + for (c, v) in self.context_values:
1.264 + l.append("(c=%s, v=%s)" % (shortrepr(c), shortrepr(v)))
1.265 + return ", ".join(l)
1.266 +
1.267 def as_raw(self, objtable, paramtable):
1.268 return [
1.269 (
1.270 - self.context and self.context.location,
1.271 - self.value and self.value.location
1.272 + self.get_context() and self.get_context().location,
1.273 + self.get_value() and self.get_value().location
1.274 )
1.275 ]
1.276
1.277 @@ -357,6 +357,9 @@
1.278 Instance.__init__(self)
1.279 self.value = value
1.280
1.281 + def get_value(self):
1.282 + return value
1.283 +
1.284 def __repr__(self):
1.285 if self.location is not None:
1.286 return "Const(%r, location=%r)" % (self.value, self.location)
1.287 @@ -388,7 +391,7 @@
1.288 # Support constants as dictionary keys in order to build constant tables.
1.289
1.290 def __eq__(self, other):
1.291 - return self.value == other.value and self.value.__class__ is other.value.__class__
1.292 + return other is not None and self.value == other.value and self.value.__class__ is other.value.__class__
1.293
1.294 def __hash__(self):
1.295 return hash(self.value)
1.296 @@ -431,10 +434,6 @@
1.297 self.allattr = None # cache for all_attributes
1.298 self.allattr_names = None # from allattr
1.299
1.300 - # Add this class to its attributes.
1.301 -
1.302 - self.set("__class__", self)
1.303 -
1.304 # Image generation details.
1.305
1.306 self.location = None
1.307 @@ -449,6 +448,10 @@
1.308 self.local_usage = 0
1.309 self.all_local_usage = 0
1.310
1.311 + # Add this class to its attributes.
1.312 +
1.313 + self.set("__class__", self)
1.314 +
1.315 def set_referenced(self):
1.316 self.referenced = 1
1.317
1.318 @@ -468,7 +471,8 @@
1.319 # Append a template of an instance for use when instantiating classes.
1.320
1.321 call_method = self.get("__call__")
1.322 - call_method_code_location = call_method and call_method.value.code_location
1.323 + call_method_value = call_method and call_method.get_value()
1.324 + call_method_code_location = call_method_value and call_method_value.code_location
1.325
1.326 # NOTE: The instantiator code is the first block of the class.
1.327
1.328 @@ -478,8 +482,8 @@
1.329 DataObject(
1.330 classcode, attrcode, call_method_code_location,
1.331 (
1.332 - call_method and len(call_method.value.positional_names),
1.333 - call_method and len(call_method.value.defaults)
1.334 + call_method_value and len(call_method_value.positional_names),
1.335 + call_method_value and len(call_method_value.defaults)
1.336 ),
1.337 1,
1.338 self.full_name()
1.339 @@ -497,26 +501,26 @@
1.340
1.341 # Namespace-related methods.
1.342
1.343 - def _context(self, value):
1.344 + def get_updated_context_values(self, context_values):
1.345
1.346 """
1.347 - Return the context to be used when storing the given 'value'.
1.348 + Adapt the contexts found in the given 'context_values', returning a new
1.349 + set.
1.350 See: docs/assignment.txt
1.351 """
1.352
1.353 - if value is not None:
1.354 + results = set()
1.355 +
1.356 + for context, value in context_values:
1.357
1.358 # Change the ownership of functions.
1.359
1.360 - if isinstance(value, Function):
1.361 - context = value.parent
1.362 + if context is None and value is not None and isinstance(value, Function):
1.363 + results.add((self, value))
1.364 + else:
1.365 + results.add((context, value))
1.366
1.367 - if isinstance(context, Module):
1.368 - return self
1.369 - else:
1.370 - return context
1.371 -
1.372 - return NamespaceDict._context(self, value)
1.373 + return NamespaceDict.get_updated_context_values(self, results)
1.374
1.375 def finalise_attributes(self):
1.376
1.377 @@ -540,7 +544,7 @@
1.378 return self.instantiator
1.379
1.380 def get_init_method(self):
1.381 - return self.all_class_attributes()["__init__"].value
1.382 + return self.all_class_attributes()["__init__"].get_value()
1.383
1.384 # Class-specific methods.
1.385
1.386 @@ -734,7 +738,7 @@
1.387
1.388 d = {}
1.389 for i, name in enumerate(self._get_position_list(positions)):
1.390 - d[name] = Attr(i, Instance(), None, name, None)
1.391 + d[name] = Attr(i, Instance(), name)
1.392 return d
1.393
1.394 def _cmp_positions(self, a, b):
1.395 @@ -881,8 +885,8 @@
1.396 # Namespace-related methods.
1.397
1.398 def store_default(self, value):
1.399 - attr = Attr(None, self, None, None, value)
1.400 - attr.update(value, 1)
1.401 + attr = Attr(None, self, None)
1.402 + attr.update([(None, value)], 1)
1.403 self.default_attrs.append(attr)
1.404
1.405 def make_global(self, name):