1.1 --- a/annotate.py Thu Aug 03 01:02:47 2006 +0200
1.2 +++ b/annotate.py Fri Aug 04 00:13:47 2006 +0200
1.3 @@ -102,33 +102,61 @@
1.4
1.5 """
1.6 Find for the given 'structure' all attributes for the given 'name', visiting
1.7 - base classes where appropriate and returning the methods in order of
1.8 + base classes where appropriate and returning the attributes in order of
1.9 descending precedence for all possible base classes.
1.10 +
1.11 + The elements in the result list are 2-tuples which contain the attribute and
1.12 + the structure involved in accessing the attribute.
1.13 """
1.14
1.15 + # First attempt to search the instance/class namespace.
1.16 +
1.17 try:
1.18 - return structure.namespace.load(name)
1.19 + l = structure.namespace.load(name)
1.20 + attributes = []
1.21 + for attribute in l:
1.22 + attributes.append((attribute, structure))
1.23 +
1.24 + # If that does not work, attempt to investigate any class or base classes.
1.25 +
1.26 except KeyError:
1.27 attributes = []
1.28 +
1.29 + # Investigate any instance's implementing class.
1.30 +
1.31 if isinstance(structure, Instance):
1.32 for cls in structure.namespace.load("__class__"):
1.33 l = find_attributes(cls, name)
1.34 for attribute in l:
1.35 if attribute not in attributes:
1.36 attributes.append(attribute)
1.37 +
1.38 + # Investigate any class's base classes.
1.39 +
1.40 elif isinstance(structure, Class):
1.41 +
1.42 + # If no base classes exist, return an indicator that no attribute
1.43 + # exists.
1.44 +
1.45 + if not structure.base_refs:
1.46 + return [(None, structure)]
1.47 +
1.48 + # Otherwise, find all possible base classes.
1.49 +
1.50 for base_refs in structure.base_refs:
1.51 base_attributes = []
1.52 +
1.53 + # For each base class, find attributes either in the base
1.54 + # class or its own base classes.
1.55 +
1.56 for base_ref in base_refs:
1.57 l = find_attributes(base_ref, name)
1.58 - if l:
1.59 - for attribute in l:
1.60 - if attribute not in base_attributes:
1.61 - base_attributes.append(attribute)
1.62 - elif None not in base_attributes:
1.63 - base_attributes.append(None)
1.64 - if base_attributes != [None]:
1.65 - attributes += base_attributes
1.66 + for attribute in l:
1.67 + if attribute not in base_attributes:
1.68 + base_attributes.append(attribute)
1.69 +
1.70 + attributes += base_attributes
1.71 +
1.72 return attributes
1.73
1.74 def get_attributes(structure, name):
1.75 @@ -137,14 +165,16 @@
1.76 Return all possible attributes for the given 'structure' having the given
1.77 'name', wrapping each attribute in an Attribute object which includes
1.78 context information for the attribute access.
1.79 +
1.80 + The elements in the result list are 2-tuples which contain the attribute and
1.81 + the structure involved in accessing the attribute.
1.82 """
1.83
1.84 if isinstance(structure, Attribute):
1.85 structure = structure.type
1.86 attributes = find_attributes(structure, name)
1.87 - for i, attribute in enumerate(attributes):
1.88 - if attribute is not None:
1.89 - attributes[i] = Attribute(structure, attribute)
1.90 + for i, (attribute, accessor) in enumerate(attributes):
1.91 + attributes[i] = Attribute(structure, attribute), accessor
1.92 return attributes
1.93
1.94 # Annotation.
1.95 @@ -318,10 +348,16 @@
1.96 def visitLoadAttr(self, loadattr):
1.97 loadattr.expr = self.dispatch(loadattr.expr)
1.98 types = []
1.99 + accesses = {}
1.100 for ref in self.types:
1.101 - for type in get_attributes(ref, loadattr.name):
1.102 - types.append(type)
1.103 + if not accesses.has_key(ref):
1.104 + accesses[ref] = []
1.105 + for attribute, accessor in get_attributes(ref, loadattr.name):
1.106 + if attribute.type is not None:
1.107 + types.append(type)
1.108 + accesses[ref].append((attribute, accessor))
1.109 self.types = types
1.110 + loadattr.accesses = accesses
1.111 self.annotate(loadattr)
1.112 return loadattr
1.113
1.114 @@ -329,8 +365,11 @@
1.115 storeattr.expr = self.dispatch(storeattr.expr)
1.116 expr = self.types
1.117 storeattr.lvalue = self.dispatch(storeattr.lvalue)
1.118 + accesses = {}
1.119 for ref in self.types:
1.120 ref.namespace.store(storeattr.name, expr)
1.121 + accesses[ref] = ref.namespace.load(storeattr.name)
1.122 + storeattr.accesses = accesses
1.123 return storeattr
1.124
1.125 def visitConditional(self, conditional):
1.126 @@ -401,7 +440,7 @@
1.127
1.128 invocations = {}
1.129
1.130 - # Visit each callable in turn
1.131 + # Visit each callable in turn, finding subprograms.
1.132
1.133 for callable in expr:
1.134
1.135 @@ -411,23 +450,38 @@
1.136 # others.
1.137
1.138 if isinstance(callable, Class):
1.139 - subprograms = get_attributes(callable, "__init__")
1.140 + attributes = get_attributes(callable, "__init__")
1.141
1.142 # Deal with object invocations by using __call__ methods.
1.143
1.144 elif isinstance(callable, Instance):
1.145 - subprograms = get_attributes(callable, "__call__")
1.146 + attributes = get_attributes(callable, "__call__")
1.147
1.148 # Normal functions or methods are more straightforward.
1.149 + # Here, we model them using an attribute with no context and with
1.150 + # no associated accessor.
1.151
1.152 else:
1.153 - subprograms = [callable]
1.154 + attributes = [(Attribute(None, callable), None)]
1.155 +
1.156 + # Inspect each attribute and extract the subprogram.
1.157
1.158 - for subprogram in subprograms:
1.159 + for attribute, accessor in attributes:
1.160 + subprogram = attribute.type
1.161 +
1.162 + # If a subprogram is defined, invoke it.
1.163 +
1.164 if subprogram is not None:
1.165 self.invoke_subprogram(invoke, subprogram)
1.166 invocations[callable] = subprogram
1.167
1.168 + # If a class is involved, presume that it must create a new
1.169 + # object.
1.170 +
1.171 + if isinstance(callable, Class):
1.172 + self.types = [attribute.context]
1.173 + self.annotate(invoke)
1.174 +
1.175 invoke.invocations = invocations
1.176
1.177 return invoke
2.1 --- a/simplified.py Thu Aug 03 01:02:47 2006 +0200
2.2 +++ b/simplified.py Fri Aug 04 00:13:47 2006 +0200
2.3 @@ -144,6 +144,14 @@
2.4 if hasattr(self, "dstar") and self.dstar:
2.5 self.dstar.pprint(indent + 2, "( ")
2.6
2.7 + # Annotations.
2.8 +
2.9 + if hasattr(self, "accesses"):
2.10 + self._pprint(indent, "", "--------")
2.11 + for ref, attributes in self.accesses.items():
2.12 + self._pprint(indent + 2, "| ", "%s: %s" % (ref, attributes))
2.13 + self._pprint(indent, "", "--------")
2.14 +
2.15 class Module(Node): "A Python module."
2.16 class Subprogram(Node): "A subprogram: functions, methods and loops."
2.17 class Pass(Node): "A placeholder node corresponding to pass."