1.1 --- a/simplified.py Fri Feb 23 01:29:50 2007 +0100
1.2 +++ b/simplified.py Sun Feb 25 01:50:23 2007 +0100
1.3 @@ -163,7 +163,8 @@
1.4 """
1.5
1.6 common_attributes = "name", "index", "value", "nstype", "internal", "returns_value", "is_method", "ref", "module", "structures", "original"
1.7 - expression_attributes = "expr", "lvalue", "test", "star", "dstar"
1.8 + expression_attributes = "expr", "lvalue", "test"
1.9 + argument_attributes = "star", "dstar"
1.10 invocation_attributes = "params", # not "args" - see "pos_args", "kw_args"
1.11 grouping_attributes = "code", "body", "else_", "handler", "finally_", "choices"
1.12
1.13 @@ -177,7 +178,7 @@
1.14
1.15 self.original = original
1.16 self.defining = defining
1.17 - self.copies = []
1.18 + self.copies = {}
1.19
1.20 if self.original is not None and defining:
1.21 self.original._node = self
1.22 @@ -301,15 +302,16 @@
1.23
1.24 "Return the active copies of this node or a list containing this node."
1.25
1.26 - return self.copies or [self]
1.27 + return self.copies.values() or [self]
1.28
1.29 # Node manipulation functions.
1.30
1.31 - def copy(self, new_name=None):
1.32 + def copy(self, instance=None, new_name=None):
1.33
1.34 """
1.35 - Perform a deep copy of the node, optionally specifying a 'new_name',
1.36 - returning a new unannotated copy.
1.37 + Perform a deep copy of the node, optionally specifying the 'instance'
1.38 + for whom the copy has been requested and a 'new_name' for the copied
1.39 + node. Return new unannotated copies of the node and its descendants.
1.40 """
1.41
1.42 # Copy the common attributes of this node.
1.43 @@ -319,6 +321,10 @@
1.44 if hasattr(self, attr):
1.45 common[attr] = getattr(self, attr)
1.46
1.47 + # Add new attributes specially for copies.
1.48 +
1.49 + common["instance"] = instance
1.50 +
1.51 if new_name is not None:
1.52 common["copy_of"] = self
1.53 common["name"] = new_name
1.54 @@ -330,7 +336,7 @@
1.55
1.56 # Add links to copies from originals.
1.57
1.58 - self.copies.append(node)
1.59 + self.copies[instance] = node
1.60
1.61 # Copy attributes of different types.
1.62
1.63 @@ -340,9 +346,20 @@
1.64 if n is None:
1.65 n2 = n
1.66 else:
1.67 - n2 = n.copy()
1.68 + n2 = n.copy(instance)
1.69 setattr(node, attr, n2)
1.70
1.71 + for attr in self.argument_attributes:
1.72 + if hasattr(self, attr):
1.73 + t = getattr(self, attr)
1.74 + if t is None:
1.75 + t2 = t
1.76 + else:
1.77 + name, n = t
1.78 + n2 = n.copy(instance)
1.79 + t2 = name, n2
1.80 + setattr(node, attr, t2)
1.81 +
1.82 for attr in self.invocation_attributes:
1.83 if hasattr(self, attr):
1.84 l = getattr(self, attr)
1.85 @@ -351,23 +368,23 @@
1.86 if n is None:
1.87 l2.append((name, n))
1.88 else:
1.89 - l2.append((name, n.copy()))
1.90 + l2.append((name, n.copy(instance)))
1.91 setattr(node, attr, l2)
1.92
1.93 for attr in self.grouping_attributes:
1.94 if hasattr(self, attr):
1.95 l = getattr(self, attr)
1.96 - setattr(node, attr, [n.copy() for n in l])
1.97 + setattr(node, attr, [n.copy(instance) for n in l])
1.98
1.99 # Arguments are usually processed further - "args" is useless.
1.100
1.101 if hasattr(self, "pos_args"):
1.102 - node.pos_args = [n.copy() for n in self.pos_args]
1.103 + node.pos_args = [n.copy(instance) for n in self.pos_args]
1.104
1.105 if hasattr(self, "kw_args"):
1.106 node.kw_args = {}
1.107 for name, n in self.kw_args.items():
1.108 - node.kw_args[name] = n.copy()
1.109 + node.kw_args[name] = n.copy(instance)
1.110
1.111 return node
1.112
1.113 @@ -482,7 +499,7 @@
1.114 else:
1.115 raise TypeError, "Positional argument appears after keyword arguments in '%s'." % self
1.116
1.117 -class InvokeBlock(Invoke):
1.118 +class InvokeRef(Invoke):
1.119
1.120 "A block or loop invocation."
1.121
1.122 @@ -574,12 +591,23 @@
1.123 # Attribute propagation.
1.124
1.125 def get_attribute_for_instance(self, attribute, instance):
1.126 +
1.127 + # Create specialised methods.
1.128 +
1.129 if isinstance(attribute.type, Subprogram):
1.130 subprogram = attribute.type
1.131 +
1.132 + # Each instance may have its own version of the subprogram.
1.133 +
1.134 key = (subprogram, instance)
1.135 if not self.attributes_for_instances.has_key(key):
1.136 - self.attributes_for_instances[key] = Attribute(attribute.context, subprogram.copy(subprogram.full_name()))
1.137 + self.attributes_for_instances[key] = Attribute(attribute.context, subprogram.copy(instance, subprogram.full_name()))
1.138 + print "New subprogram", self.attributes_for_instances[key].type, "for", key
1.139 +
1.140 return self.attributes_for_instances[key]
1.141 +
1.142 + # The original nodes are returned for other attributes.
1.143 +
1.144 else:
1.145 return attribute
1.146
1.147 @@ -593,6 +621,44 @@
1.148 else:
1.149 return MultipleInstanceClass._get_key(self, node)
1.150
1.151 +class ProlificMultipleInstanceClass(MultipleInstanceClass):
1.152 +
1.153 + """
1.154 + A Python class which provides multiple instances for different versions of
1.155 + methods. In order to avoid unbounded instance production (since new
1.156 + instances cause new copies of methods which in turn would cause new
1.157 + instances),
1.158 + """
1.159 +
1.160 + def __init__(self, *args, **kw):
1.161 + MultipleInstanceClass.__init__(self, *args, **kw)
1.162 + self.instance_relations = {}
1.163 +
1.164 + def _get_key(self, node):
1.165 + if self.namespace.has_key("__atomic__"):
1.166 + return id(self)
1.167 + else:
1.168 + return id(node)
1.169 +
1.170 + def has_instance(self, node):
1.171 + requesting_instance = getattr(node, "instance", None)
1.172 + return requesting_instance is not None and requesting_instance.get_class() is self or \
1.173 + self.instance_relations.has_key(requesting_instance) or self.instances.has_key(self._get_key(node))
1.174 +
1.175 + def add_instance(self, node, instance):
1.176 + requesting_instance = getattr(node, "instance", None)
1.177 + print "New instance", instance, "for", id(node), requesting_instance
1.178 + self.instances[self._get_key(node)] = instance
1.179 + if requesting_instance is not None:
1.180 + self.instance_relations[requesting_instance] = instance
1.181 + requesting_instance.get_class().instance_relations[instance] = requesting_instance
1.182 +
1.183 + def get_instance(self, node):
1.184 + requesting_instance = getattr(node, "instance", None)
1.185 + if requesting_instance is not None and requesting_instance.get_class() is self:
1.186 + return requesting_instance
1.187 + return self.instance_relations.get(requesting_instance) or self.instances[self._get_key(node)]
1.188 +
1.189 class Instance(Structure):
1.190
1.191 "An instance."
1.192 @@ -686,4 +752,8 @@
1.193 global Class
1.194 Class = SelectiveMultipleInstanceClass
1.195
1.196 +def set_prolific_multiple_instance_mode():
1.197 + global Class
1.198 + Class = ProlificMultipleInstanceClass
1.199 +
1.200 # vim: tabstop=4 expandtab shiftwidth=4