1.1 --- a/simplified.py Sun Jan 21 17:56:01 2007 +0100
1.2 +++ b/simplified.py Mon Jan 22 01:29:15 2007 +0100
1.3 @@ -5,7 +5,7 @@
1.4 contains nodes representing program instructions or operations, program
1.5 structure or organisation, and abstract program data.
1.6
1.7 -Copyright (C) 2006 Paul Boddie <paul@boddie.org.uk>
1.8 +Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This software is free software; you can redistribute it and/or
1.11 modify it under the terms of the GNU General Public License as
1.12 @@ -151,6 +151,11 @@
1.13 choices Any choices which may be included in the final program.
1.14 """
1.15
1.16 + common_attributes = "name", "index", "value", "nstype", "internal", "returns_value", "is_method", "ref", "module", "structures", "original_def"
1.17 + expression_attributes = "expr", "lvalue", "test", "star", "dstar"
1.18 + invocation_attributes = "params", # not "args" - see "pos_args", "kw_args"
1.19 + grouping_attributes = "code", "body", "else_", "handler", "finally_", "choices"
1.20 +
1.21 def __init__(self, original=None, defining=0, **kw):
1.22
1.23 """
1.24 @@ -258,7 +263,7 @@
1.25
1.26 if hasattr(self, "test"):
1.27 self.test.pprint(indent + 2, "? ", stream=stream)
1.28 - for attr in "code", "body", "else_", "handler", "finally_", "choices":
1.29 + for attr in self.grouping_attributes:
1.30 if hasattr(self, attr) and getattr(self, attr):
1.31 self._pprint(indent, "", "%s {" % attr, stream=stream)
1.32 for node in getattr(self, attr):
1.33 @@ -278,6 +283,87 @@
1.34 self._pprint(indent + 2, "| ", "when %s: %s" % (ref, attribute), stream=stream)
1.35 self._pprint(indent, "", "--------", stream=stream)
1.36
1.37 + # Node manipulation functions.
1.38 +
1.39 + def copy(self, new_name=None, original_def=None):
1.40 +
1.41 + """
1.42 + Perform a deep copy of the node, optionally specifying a 'new_name',
1.43 + returning a new unannotated copy.
1.44 +
1.45 + The 'original_def' parameter is used to assign a particular AST node to
1.46 + copied regions of the simplified node tree.
1.47 + """
1.48 +
1.49 + # Obtain an AST node to be assigned to the copied nodes.
1.50 +
1.51 + original_def = getattr(self, "original", None) or original_def or getattr(self, "original_def", None)
1.52 +
1.53 + # Copy the common attributes of this node.
1.54 +
1.55 + common = {}
1.56 + for attr in self.common_attributes:
1.57 + if hasattr(self, attr):
1.58 + common[attr] = getattr(self, attr)
1.59 +
1.60 + if new_name is not None:
1.61 + common["name"] = new_name
1.62 +
1.63 + if original_def is not None:
1.64 + common["original_def"] = original_def
1.65 +
1.66 + # Instantiate the copy, avoiding side-effects with original and defining.
1.67 +
1.68 + node = self.__class__(**common)
1.69 + node.original = self.original
1.70 + node.defining = self.defining
1.71 +
1.72 + # Add links to copied nodes from original AST nodes.
1.73 +
1.74 + if node.original is not None:
1.75 + if not hasattr(node.original, "_nodes"):
1.76 + node.original._nodes = []
1.77 + node.original._nodes.append(node)
1.78 +
1.79 + # Copy attributes of different types.
1.80 +
1.81 + for attr in self.expression_attributes:
1.82 + if hasattr(self, attr):
1.83 + n = getattr(self, attr)
1.84 + if n is None:
1.85 + n2 = n
1.86 + else:
1.87 + n2 = n.copy(original_def=original_def)
1.88 + setattr(node, attr, n2)
1.89 +
1.90 + for attr in self.invocation_attributes:
1.91 + if hasattr(self, attr):
1.92 + l = getattr(self, attr)
1.93 + l2 = []
1.94 + for name, n in l:
1.95 + if n is None:
1.96 + l2.append((name, n))
1.97 + else:
1.98 + l2.append((name, n.copy(original_def=original_def)))
1.99 + setattr(node, attr, l2)
1.100 +
1.101 + for attr in self.grouping_attributes:
1.102 + if hasattr(self, attr):
1.103 + l = getattr(self, attr)
1.104 + setattr(node, attr, [n.copy(original_def=original_def) for n in l])
1.105 +
1.106 + # Arguments are usually processed further - "args" is useless.
1.107 +
1.108 + if hasattr(self, "pos_args"):
1.109 + node.pos_args = [n.copy(original_def=original_def) for n in self.pos_args]
1.110 +
1.111 + if hasattr(self, "kw_args"):
1.112 + node.kw_args = {}
1.113 + for name, n in self.kw_args.items():
1.114 + node.kw_args[name] = n.copy(original_def=original_def)
1.115 +
1.116 + return node
1.117 +
1.118 # These are the supported "operations" described by simplified program nodes.
1.119
1.120 class Pass(Node): "A placeholder node corresponding to pass."
1.121 @@ -436,6 +522,11 @@
1.122 def get_instance_name(self, instance):
1.123 return self._full_name
1.124
1.125 + # Attribute propagation.
1.126 +
1.127 + def get_attribute_for_instance(self, attribute, instance):
1.128 + return attribute
1.129 +
1.130 class MultipleInstanceClass(_Class):
1.131
1.132 "A Python class."
1.133 @@ -443,22 +534,35 @@
1.134 def __init__(self, *args, **kw):
1.135 _Class.__init__(self, *args, **kw)
1.136 self.instances = {}
1.137 + self.attributes_for_instances = {}
1.138 +
1.139 + def _get_key(self, node):
1.140 + return getattr(node, "original_def", node)
1.141
1.142 def has_instance(self, node):
1.143 - key = id(node)
1.144 - return self.instances.has_key(key)
1.145 + return self.instances.has_key(self._get_key(node))
1.146
1.147 def add_instance(self, node, instance):
1.148 - key = id(node)
1.149 - self.instances[key] = instance
1.150 + self.instances[self._get_key(node)] = instance
1.151
1.152 def get_instance(self, node):
1.153 - key = id(node)
1.154 - return self.instances[key]
1.155 + return self.instances[self._get_key(node)]
1.156
1.157 def get_instance_name(self, instance):
1.158 return name(instance, self._full_name)
1.159
1.160 + # Attribute propagation.
1.161 +
1.162 + def get_attribute_for_instance(self, attribute, instance):
1.163 + if isinstance(attribute.type, Subprogram):
1.164 + subprogram = attribute.type
1.165 + key = (subprogram, instance)
1.166 + if not self.attributes_for_instances.has_key(key):
1.167 + self.attributes_for_instances[key] = Attribute(attribute.context, subprogram.copy(subprogram.full_name()))
1.168 + return self.attributes_for_instances[key]
1.169 + else:
1.170 + return attribute
1.171 +
1.172 class Instance(Structure):
1.173
1.174 "An instance."
1.175 @@ -488,6 +592,34 @@
1.176 Instance.__init__(self, *args, **kw)
1.177 self.typename = self.value.__class__.__name__
1.178
1.179 +class Attribute:
1.180 +
1.181 + """
1.182 + An attribute abstraction, indicating the type of the attribute along with
1.183 + its context or origin.
1.184 + """
1.185 +
1.186 + def __init__(self, context, type):
1.187 + self.context = context
1.188 + self.type = type
1.189 +
1.190 + def __eq__(self, other):
1.191 + return hasattr(other, "type") and other.type == self.type or other == self.type
1.192 +
1.193 + def __repr__(self):
1.194 + return "Attribute(%s, %s)" % (repr(self.context), repr(self.type))
1.195 +
1.196 +class Self:
1.197 +
1.198 + """
1.199 + A program node encapsulating object/context information in an argument list.
1.200 + This is not particularly like Attribute, Class, Instance or other such
1.201 + things, since it actually appears in the program representation.
1.202 + """
1.203 +
1.204 + def __init__(self, attribute):
1.205 + self.types = [attribute]
1.206 +
1.207 # Configuration setting.
1.208
1.209 Class = SingleInstanceClass