1 #!/usr/bin/env python 2 3 """ 4 Simplified program data. 5 6 Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk> 7 8 This software is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License as 10 published by the Free Software Foundation; either version 2 of 11 the License, or (at your option) any later version. 12 13 This software is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public 19 License along with this library; see the file LICENCE.txt 20 If not, write to the Free Software Foundation, Inc., 21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 22 """ 23 24 from simplified.utils import Structure, WithName, name 25 26 # Special non-program nodes. 27 28 class _Class(Structure, WithName): 29 30 "A Python class." 31 32 def __init__(self, *args, **kw): 33 Structure.__init__(self, *args, **kw) 34 WithName.__init__(self) 35 36 def full_name(self): 37 return "class %s" % self._full_name 38 39 class SingleInstanceClass(_Class): 40 41 "A Python class." 42 43 def __init__(self, *args, **kw): 44 _Class.__init__(self, *args, **kw) 45 self.instance = None 46 47 def has_instance(self, node): 48 return self.instance is not None 49 50 def add_instance(self, node, instance): 51 self.instance = instance 52 53 def get_instance(self, node): 54 return self.instance 55 56 def get_instance_name(self, instance): 57 return self._full_name 58 59 # Attribute propagation. 60 61 def get_attribute_for_instance(self, attribute, instance): 62 return attribute 63 64 class MultipleInstanceClass(_Class): 65 66 "A Python class." 67 68 def __init__(self, *args, **kw): 69 _Class.__init__(self, *args, **kw) 70 self.instances = {} 71 self.attributes_for_instances = {} 72 73 def _get_key(self, node): 74 return id(getattr(node, "original", None)) # self.module.original 75 76 def has_instance(self, node): 77 return self.instances.has_key(self._get_key(node)) 78 79 def add_instance(self, node, instance): 80 self.instances[self._get_key(node)] = instance 81 82 def get_instance(self, node): 83 return self.instances[self._get_key(node)] 84 85 def get_instance_name(self, instance): 86 return name(instance, self._full_name) 87 88 # Attribute propagation. 89 90 def get_attribute_for_instance(self, attribute, instance): 91 92 # Create specialised methods. 93 94 if isinstance(attribute.type, Subprogram): 95 subprogram = attribute.type 96 97 # Each instance may have its own version of the subprogram. 98 99 key = (subprogram, instance) 100 if not self.attributes_for_instances.has_key(key): 101 new_subprogram = subprogram.copy(instance, subprogram.full_name()) 102 subprogram.module.simplifier.subnames[new_subprogram.full_name()] = new_subprogram 103 self.attributes_for_instances[key] = Attribute(attribute.context, new_subprogram) 104 print "New subprogram", new_subprogram, "for", key 105 106 return self.attributes_for_instances[key] 107 108 # The original nodes are returned for other attributes. 109 110 else: 111 return attribute 112 113 class SelectiveMultipleInstanceClass(MultipleInstanceClass): 114 115 "A Python class which provides multiple instances depending on the class." 116 117 def _get_key(self, node): 118 if self.namespace.has_key("__atomic__"): 119 return id(self) 120 else: 121 return MultipleInstanceClass._get_key(self, node) 122 123 class ProlificMultipleInstanceClass(MultipleInstanceClass): 124 125 """ 126 A Python class which provides multiple instances for different versions of 127 methods. In order to avoid unbounded instance production (since new 128 instances cause new copies of methods which in turn would cause new 129 instances), a relations dictionary is maintained which attempts to map 130 "requesting instances" to existing instances, suggesting such instances in 131 preference to new ones. 132 """ 133 134 def __init__(self, *args, **kw): 135 MultipleInstanceClass.__init__(self, *args, **kw) 136 self.instance_relations = {} 137 138 def _get_key(self, node): 139 if self.namespace.has_key("__atomic__"): 140 return id(self) 141 else: 142 return id(node) 143 144 def has_instance(self, node): 145 requesting_instance = getattr(node, "instance", None) 146 #return requesting_instance is not None and requesting_instance.get_class() is self or \ 147 return self.instance_relations.has_key(requesting_instance) or self.instances.has_key(self._get_key(node)) 148 149 def add_instance(self, node, instance): 150 requesting_instance = getattr(node, "instance", None) 151 print "New instance", instance, "for", id(node), requesting_instance 152 self.instances[self._get_key(node)] = instance 153 if requesting_instance is not None: 154 self.instance_relations[requesting_instance] = instance 155 requesting_instance.get_class().instance_relations[instance] = requesting_instance 156 157 def get_instance(self, node): 158 requesting_instance = getattr(node, "instance", None) 159 #if requesting_instance is not None and requesting_instance.get_class() is self: 160 # return requesting_instance 161 return self.instance_relations.get(requesting_instance) or self.instances[self._get_key(node)] 162 163 class Instance(Structure): 164 165 "An instance." 166 167 def full_name(self): 168 return self.get_class().get_instance_name(self) 169 170 def get_class(self): 171 for n in self.namespace.load("__class__"): 172 return n.type 173 else: 174 raise ValueError, "__class__" 175 176 def __repr__(self): 177 return "Instance of type '%s'" % self.full_name() 178 179 def __eq__(self, other): 180 # NOTE: Single instance: all instances are the same 181 # NOTE: Multiple instances: all instances are different 182 return self.full_name() == other.full_name() 183 184 def __hash__(self): 185 return id(self) 186 187 class Constant: 188 189 "A constant initialised with a type name for future processing." 190 191 def __init__(self, name, value): 192 self.name = name 193 self.value = value 194 self.typename = self.value.__class__.__name__ 195 196 class Attribute: 197 198 """ 199 An attribute abstraction, indicating the type of the attribute along with 200 its context or origin. 201 """ 202 203 def __init__(self, context, type): 204 self.context = context 205 self.type = type 206 207 def __eq__(self, other): 208 return hasattr(other, "type") and other.type == self.type or other == self.type 209 210 def __repr__(self): 211 return "Attribute(%s, %s)" % (repr(self.context), repr(self.type)) 212 213 def __hash__(self): 214 return id(self.type) 215 216 # Configuration setting. 217 218 Class = SingleInstanceClass 219 #Class = MultipleInstanceClass 220 221 def set_single_instance_mode(): 222 global Class 223 Class = SingleInstanceClass 224 225 def set_multiple_instance_mode(): 226 global Class 227 Class = MultipleInstanceClass 228 229 def set_selective_multiple_instance_mode(): 230 global Class 231 Class = SelectiveMultipleInstanceClass 232 233 def set_prolific_multiple_instance_mode(): 234 global Class 235 Class = ProlificMultipleInstanceClass 236 237 # vim: tabstop=4 expandtab shiftwidth=4