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