1.1 --- a/annotate.py Sun Jan 21 17:56:01 2007 +0100
1.2 +++ b/annotate.py Mon Jan 22 01:29:15 2007 +0100
1.3 @@ -5,7 +5,7 @@
1.4 which are produced when simplifying AST node trees originating from the compiler
1.5 module.
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 @@ -1416,34 +1416,6 @@
1.13 def __repr__(self):
1.14 return repr(self.names)
1.15
1.16 -class Attribute:
1.17 -
1.18 - """
1.19 - An attribute abstraction, indicating the type of the attribute along with
1.20 - its context or origin.
1.21 - """
1.22 -
1.23 - def __init__(self, context, type):
1.24 - self.context = context
1.25 - self.type = type
1.26 -
1.27 - def __eq__(self, other):
1.28 - return hasattr(other, "type") and other.type == self.type or other == self.type
1.29 -
1.30 - def __repr__(self):
1.31 - return "Attribute(%s, %s)" % (repr(self.context), repr(self.type))
1.32 -
1.33 -class Self:
1.34 -
1.35 - """
1.36 - A program node encapsulating object/context information in an argument list.
1.37 - This is not particularly like Attribute, Class, Instance or other such
1.38 - things, since it actually appears in the program representation.
1.39 - """
1.40 -
1.41 - def __init__(self, attribute):
1.42 - self.types = [attribute]
1.43 -
1.44 class Importer:
1.45
1.46 "An import machine, searching for and loading modules."
1.47 @@ -1654,10 +1626,19 @@
1.48 structure = structure.type
1.49 results = []
1.50 for attribute, accessor in find_attributes(structure, name):
1.51 +
1.52 + # Detect class attribute access via instances.
1.53 +
1.54 + if attribute is not None and isinstance(structure, Instance) and isinstance(accessor, Class):
1.55 + attribute = accessor.get_attribute_for_instance(attribute, structure)
1.56 +
1.57 + # Produce an attribute with the appropriate context.
1.58 +
1.59 if attribute is not None and isinstance(structure, Structure):
1.60 results.append((Attribute(structure, attribute.type), accessor))
1.61 else:
1.62 results.append((attribute, accessor))
1.63 +
1.64 return results
1.65
1.66 # Convenience functions.
2.1 --- a/simplified.py Sun Jan 21 17:56:01 2007 +0100
2.2 +++ b/simplified.py Mon Jan 22 01:29:15 2007 +0100
2.3 @@ -5,7 +5,7 @@
2.4 contains nodes representing program instructions or operations, program
2.5 structure or organisation, and abstract program data.
2.6
2.7 -Copyright (C) 2006 Paul Boddie <paul@boddie.org.uk>
2.8 +Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk>
2.9
2.10 This software is free software; you can redistribute it and/or
2.11 modify it under the terms of the GNU General Public License as
2.12 @@ -151,6 +151,11 @@
2.13 choices Any choices which may be included in the final program.
2.14 """
2.15
2.16 + common_attributes = "name", "index", "value", "nstype", "internal", "returns_value", "is_method", "ref", "module", "structures", "original_def"
2.17 + expression_attributes = "expr", "lvalue", "test", "star", "dstar"
2.18 + invocation_attributes = "params", # not "args" - see "pos_args", "kw_args"
2.19 + grouping_attributes = "code", "body", "else_", "handler", "finally_", "choices"
2.20 +
2.21 def __init__(self, original=None, defining=0, **kw):
2.22
2.23 """
2.24 @@ -258,7 +263,7 @@
2.25
2.26 if hasattr(self, "test"):
2.27 self.test.pprint(indent + 2, "? ", stream=stream)
2.28 - for attr in "code", "body", "else_", "handler", "finally_", "choices":
2.29 + for attr in self.grouping_attributes:
2.30 if hasattr(self, attr) and getattr(self, attr):
2.31 self._pprint(indent, "", "%s {" % attr, stream=stream)
2.32 for node in getattr(self, attr):
2.33 @@ -278,6 +283,87 @@
2.34 self._pprint(indent + 2, "| ", "when %s: %s" % (ref, attribute), stream=stream)
2.35 self._pprint(indent, "", "--------", stream=stream)
2.36
2.37 + # Node manipulation functions.
2.38 +
2.39 + def copy(self, new_name=None, original_def=None):
2.40 +
2.41 + """
2.42 + Perform a deep copy of the node, optionally specifying a 'new_name',
2.43 + returning a new unannotated copy.
2.44 +
2.45 + The 'original_def' parameter is used to assign a particular AST node to
2.46 + copied regions of the simplified node tree.
2.47 + """
2.48 +
2.49 + # Obtain an AST node to be assigned to the copied nodes.
2.50 +
2.51 + original_def = getattr(self, "original", None) or original_def or getattr(self, "original_def", None)
2.52 +
2.53 + # Copy the common attributes of this node.
2.54 +
2.55 + common = {}
2.56 + for attr in self.common_attributes:
2.57 + if hasattr(self, attr):
2.58 + common[attr] = getattr(self, attr)
2.59 +
2.60 + if new_name is not None:
2.61 + common["name"] = new_name
2.62 +
2.63 + if original_def is not None:
2.64 + common["original_def"] = original_def
2.65 +
2.66 + # Instantiate the copy, avoiding side-effects with original and defining.
2.67 +
2.68 + node = self.__class__(**common)
2.69 + node.original = self.original
2.70 + node.defining = self.defining
2.71 +
2.72 + # Add links to copied nodes from original AST nodes.
2.73 +
2.74 + if node.original is not None:
2.75 + if not hasattr(node.original, "_nodes"):
2.76 + node.original._nodes = []
2.77 + node.original._nodes.append(node)
2.78 +
2.79 + # Copy attributes of different types.
2.80 +
2.81 + for attr in self.expression_attributes:
2.82 + if hasattr(self, attr):
2.83 + n = getattr(self, attr)
2.84 + if n is None:
2.85 + n2 = n
2.86 + else:
2.87 + n2 = n.copy(original_def=original_def)
2.88 + setattr(node, attr, n2)
2.89 +
2.90 + for attr in self.invocation_attributes:
2.91 + if hasattr(self, attr):
2.92 + l = getattr(self, attr)
2.93 + l2 = []
2.94 + for name, n in l:
2.95 + if n is None:
2.96 + l2.append((name, n))
2.97 + else:
2.98 + l2.append((name, n.copy(original_def=original_def)))
2.99 + setattr(node, attr, l2)
2.100 +
2.101 + for attr in self.grouping_attributes:
2.102 + if hasattr(self, attr):
2.103 + l = getattr(self, attr)
2.104 + setattr(node, attr, [n.copy(original_def=original_def) for n in l])
2.105 +
2.106 + # Arguments are usually processed further - "args" is useless.
2.107 +
2.108 + if hasattr(self, "pos_args"):
2.109 + node.pos_args = [n.copy(original_def=original_def) for n in self.pos_args]
2.110 +
2.111 + if hasattr(self, "kw_args"):
2.112 + node.kw_args = {}
2.113 + for name, n in self.kw_args.items():
2.114 + node.kw_args[name] = n.copy(original_def=original_def)
2.115 +
2.116 + return node
2.117 +
2.118 # These are the supported "operations" described by simplified program nodes.
2.119
2.120 class Pass(Node): "A placeholder node corresponding to pass."
2.121 @@ -436,6 +522,11 @@
2.122 def get_instance_name(self, instance):
2.123 return self._full_name
2.124
2.125 + # Attribute propagation.
2.126 +
2.127 + def get_attribute_for_instance(self, attribute, instance):
2.128 + return attribute
2.129 +
2.130 class MultipleInstanceClass(_Class):
2.131
2.132 "A Python class."
2.133 @@ -443,22 +534,35 @@
2.134 def __init__(self, *args, **kw):
2.135 _Class.__init__(self, *args, **kw)
2.136 self.instances = {}
2.137 + self.attributes_for_instances = {}
2.138 +
2.139 + def _get_key(self, node):
2.140 + return getattr(node, "original_def", node)
2.141
2.142 def has_instance(self, node):
2.143 - key = id(node)
2.144 - return self.instances.has_key(key)
2.145 + return self.instances.has_key(self._get_key(node))
2.146
2.147 def add_instance(self, node, instance):
2.148 - key = id(node)
2.149 - self.instances[key] = instance
2.150 + self.instances[self._get_key(node)] = instance
2.151
2.152 def get_instance(self, node):
2.153 - key = id(node)
2.154 - return self.instances[key]
2.155 + return self.instances[self._get_key(node)]
2.156
2.157 def get_instance_name(self, instance):
2.158 return name(instance, self._full_name)
2.159
2.160 + # Attribute propagation.
2.161 +
2.162 + def get_attribute_for_instance(self, attribute, instance):
2.163 + if isinstance(attribute.type, Subprogram):
2.164 + subprogram = attribute.type
2.165 + key = (subprogram, instance)
2.166 + if not self.attributes_for_instances.has_key(key):
2.167 + self.attributes_for_instances[key] = Attribute(attribute.context, subprogram.copy(subprogram.full_name()))
2.168 + return self.attributes_for_instances[key]
2.169 + else:
2.170 + return attribute
2.171 +
2.172 class Instance(Structure):
2.173
2.174 "An instance."
2.175 @@ -488,6 +592,34 @@
2.176 Instance.__init__(self, *args, **kw)
2.177 self.typename = self.value.__class__.__name__
2.178
2.179 +class Attribute:
2.180 +
2.181 + """
2.182 + An attribute abstraction, indicating the type of the attribute along with
2.183 + its context or origin.
2.184 + """
2.185 +
2.186 + def __init__(self, context, type):
2.187 + self.context = context
2.188 + self.type = type
2.189 +
2.190 + def __eq__(self, other):
2.191 + return hasattr(other, "type") and other.type == self.type or other == self.type
2.192 +
2.193 + def __repr__(self):
2.194 + return "Attribute(%s, %s)" % (repr(self.context), repr(self.type))
2.195 +
2.196 +class Self:
2.197 +
2.198 + """
2.199 + A program node encapsulating object/context information in an argument list.
2.200 + This is not particularly like Attribute, Class, Instance or other such
2.201 + things, since it actually appears in the program representation.
2.202 + """
2.203 +
2.204 + def __init__(self, attribute):
2.205 + self.types = [attribute]
2.206 +
2.207 # Configuration setting.
2.208
2.209 Class = SingleInstanceClass
3.1 --- a/simplify.py Sun Jan 21 17:56:01 2007 +0100
3.2 +++ b/simplify.py Mon Jan 22 01:29:15 2007 +0100
3.3 @@ -5,7 +5,7 @@
3.4 this module processes AST trees originating from the compiler module and
3.5 produces a result tree consisting of instruction-oriented program nodes.
3.6
3.7 -Copyright (C) 2006 Paul Boddie <paul@boddie.org.uk>
3.8 +Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk>
3.9
3.10 This software is free software; you can redistribute it and/or
3.11 modify it under the terms of the GNU General Public License as
3.12 @@ -823,7 +823,7 @@
3.13 """
3.14
3.15 subprogram = Subprogram(name=function.name, module=self.module, structures=self.current_structures[:],
3.16 - internal=0, returns_value=1, star=None, dstar=None, is_method=self.within_class)
3.17 + internal=0, returns_value=1, star=None, dstar=None, is_method=self.within_class, original_def=function)
3.18
3.19 self.current_subprograms.append(subprogram)
3.20 within_class = self.within_class
3.21 @@ -934,7 +934,7 @@
3.22 # Make a subprogram for the function and record it outside the main
3.23 # tree.
3.24
3.25 - subprogram = Subprogram(name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None)
3.26 + subprogram = Subprogram(name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None, original_def=lambda_)
3.27 self.current_subprograms.append(subprogram)
3.28 subprogram.code = [ReturnFromFunction(expr=self.dispatch(lambda_.code))]
3.29 self.current_subprograms.pop()