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 simplify.simplified.utils import Structure, WithName, name 25 from simplify.simplified.program import Subprogram 26 27 # Special non-program nodes. 28 29 class _Class(Structure, WithName): 30 31 "A Python class." 32 33 def __init__(self, *args, **kw): 34 Structure.__init__(self, *args, **kw) 35 WithName.__init__(self) 36 37 def full_name(self): 38 return "class %s" % self._full_name 39 40 def get_instance_attribute_names(self): 41 42 "Return all attribute names used by the instances of this class." 43 44 names = set() 45 for instance in self.instances.values(): 46 for name in instance.namespace.keys(): 47 names.add(name) 48 return names 49 50 def get_names_to_instances(self): 51 52 """ 53 Return a tuple containing a mapping from names to instances, and a list 54 of sorted instance names. 55 """ 56 57 d = {} 58 names = [] 59 for instance in self.instances.values(): 60 name = instance.full_name() 61 names.append(name) 62 d[name] = instance 63 names.sort() 64 return d, names 65 66 class SingleInstanceClass(_Class): 67 68 "A Python class." 69 70 def __init__(self, *args, **kw): 71 _Class.__init__(self, *args, **kw) 72 self.instance = None 73 74 def has_instance(self, node): 75 return self.instance is not None 76 77 def add_instance(self, node, instance): 78 self.instance = instance 79 80 def get_instance(self, node): 81 return self.instance 82 83 def get_instance_name(self, instance): 84 return self._full_name 85 86 # Attribute propagation. 87 88 def get_attribute_for_instance(self, attribute, instance): 89 return attribute 90 91 class MultipleInstanceClass(_Class): 92 93 "A Python class." 94 95 def __init__(self, *args, **kw): 96 _Class.__init__(self, *args, **kw) 97 self.instances = {} 98 self.attributes_for_instances = {} 99 100 def _get_key(self, node): 101 return getattr(node, "original", None) # self.module.original 102 103 def has_instance(self, node): 104 return self.instances.has_key(self._get_key(node)) 105 106 def add_instance(self, node, instance): 107 self.instances[self._get_key(node)] = instance 108 109 def get_instance(self, node): 110 return self.instances[self._get_key(node)] 111 112 def get_instance_name(self, instance): 113 return name(instance, self._full_name) 114 115 # Attribute propagation. 116 117 def get_attribute_for_instance(self, attribute, instance): 118 119 # Create specialised methods. 120 121 if isinstance(attribute.type, Subprogram): 122 subprogram = attribute.type 123 124 # Each instance may have its own version of the subprogram. 125 126 key = (subprogram, instance) 127 if not self.attributes_for_instances.has_key(key): 128 new_subprogram = subprogram.copy(instance, subprogram.full_name()) 129 subprogram.module.simplifier.subnames[new_subprogram.full_name()] = new_subprogram 130 self.attributes_for_instances[key] = Attribute(attribute.context, new_subprogram) 131 print "New subprogram", new_subprogram, "for", key 132 133 return self.attributes_for_instances[key] 134 135 # The original nodes are returned for other attributes. 136 137 else: 138 return attribute 139 140 class SelectiveMultipleInstanceClass(MultipleInstanceClass): 141 142 "A Python class which provides multiple instances depending on the class." 143 144 def _get_key(self, node): 145 if self.namespace.has_key("__atomic__"): 146 return self 147 else: 148 return MultipleInstanceClass._get_key(self, node) 149 150 class ProlificMultipleInstanceClass(MultipleInstanceClass): 151 152 """ 153 A Python class which provides multiple instances for different versions of 154 methods. In order to avoid unbounded instance production (since new 155 instances cause new copies of methods which in turn would cause new 156 instances), a relations dictionary is maintained which attempts to map 157 "requesting instances" to existing instances, suggesting such instances in 158 preference to new ones. 159 """ 160 161 def __init__(self, *args, **kw): 162 MultipleInstanceClass.__init__(self, *args, **kw) 163 self.instance_relations = {} 164 165 def _get_key(self, node): 166 if self.namespace.has_key("__atomic__"): 167 return self 168 else: 169 return node 170 171 def has_instance(self, node): 172 requesting_instance = getattr(node, "instance", None) 173 #return requesting_instance is not None and requesting_instance.get_class() is self or \ 174 return self.instance_relations.has_key(requesting_instance) or self.instances.has_key(self._get_key(node)) 175 176 def add_instance(self, node, instance): 177 requesting_instance = getattr(node, "instance", None) 178 print "New instance", instance, "for", id(node), requesting_instance 179 self.instances[self._get_key(node)] = instance 180 if requesting_instance is not None: 181 self.instance_relations[requesting_instance] = instance 182 requesting_instance.get_class().instance_relations[instance] = requesting_instance 183 184 def get_instance(self, node): 185 requesting_instance = getattr(node, "instance", None) 186 #if requesting_instance is not None and requesting_instance.get_class() is self: 187 # return requesting_instance 188 return self.instance_relations.get(requesting_instance) or self.instances[self._get_key(node)] 189 190 class Instance(Structure): 191 192 "An instance." 193 194 def full_name(self): 195 return self.get_class().get_instance_name(self) 196 197 def get_class(self): 198 for n in self.namespace.load("__class__"): 199 return n.type 200 else: 201 raise ValueError, "__class__" 202 203 class Constant: 204 205 "A constant initialised with a type name for future processing." 206 207 def __init__(self, name, value): 208 self.name = name 209 self.value = value 210 self.typename = self.value.__class__.__name__ 211 212 class Attribute: 213 214 """ 215 An attribute abstraction, indicating the type of the attribute along with 216 its context or origin. 217 """ 218 219 def __init__(self, context, type): 220 self.context = context 221 self.type = type 222 223 def __repr__(self): 224 return "Attribute(%s, %s)" % (repr(self.context), repr(self.type)) 225 226 def __eq__(self, other): 227 return hasattr(other, "type") and other.type == self.type or other == self.type 228 229 def __hash__(self): 230 return id(self.type) 231 232 # vim: tabstop=4 expandtab shiftwidth=4