# HG changeset patch # User paulb@jeremy # Date 1160344496 -7200 # Node ID 3e9914b119fdc876ad938a9389b2286d7abcd439 # Parent 8e2424b0721d02894ef33ea4f29b78cd0df563f1 Wrapped __class__ attributes up properly, fixing the attribute traversal code to deal with this. Improved temporary variable error handling. Added a function to combine lists. diff -r 8e2424b0721d -r 3e9914b119fd annotate.py --- a/annotate.py Sun Oct 08 23:53:35 2006 +0200 +++ b/annotate.py Sun Oct 08 23:54:56 2006 +0200 @@ -253,7 +253,10 @@ def visitLoadTemp(self, loadtemp): index = getattr(loadtemp, "index", None) - self.namespace.set_types(self.namespace.temp[index][-1]) + try: + self.namespace.set_types(self.namespace.temp[index][-1]) + except KeyError: + raise AnnotationMessage, "Temporary store index '%s' not defined." % index self.annotate(loadtemp) return loadtemp @@ -267,7 +270,12 @@ def visitReleaseTemp(self, releasetemp): index = getattr(releasetemp, "index", None) - self.namespace.temp[index].pop() + try: + self.namespace.temp[index].pop() + except KeyError: + raise AnnotationMessage, "Temporary store index '%s' not defined." % index + except IndexError: + pass #raise AnnotationMessage, "Temporary store index '%s' is empty." % index return releasetemp def visitLoadAttr(self, loadattr): @@ -329,7 +337,7 @@ def visitReturn(self, return_): if hasattr(return_, "expr"): return_.expr = self.dispatch(return_.expr) - self.namespace.returns += self.namespace.types + combine(self.namespace.returns, self.namespace.types) self.annotate(return_) self.namespace.snapshot() return return_ @@ -385,7 +393,7 @@ instance = Instance() instance.namespace = Namespace() - instance.namespace.store("__class__", [attr.type]) + instance.namespace.store("__class__", [Attribute(None, attr.type)]) # For instantiations, switch the context. @@ -548,17 +556,45 @@ param, default = params[0] if kw_args.has_key(param): arg = kw_args[param] + del kw_args[param] elif default is None: raise AnnotationMessage, "No argument supplied in '%s' for parameter '%s'." % (subprogram, param) items.append((param, arg.types)) params = params[1:] + dstar_args = kw_args + + # Construct temporary objects. + + if star_args: + list_type = self.builtins_namespace.load("list")[0] # NOTE: Hack to get list type. + star = Instance() + star.namespace = Namespace() + star.namespace.store("__class__", [Attribute(None, list_type)]) + star_types = [Attribute(None, star)] + else: + star_types = None + + if dstar_args: + dict_type = self.builtins_namespace.load("dict")[0] # NOTE: Hack to get dict type. + dstar = Instance() + dstar.namespace = Namespace() + dstar.namespace.store("__class__", [Attribute(None, dict_type)]) + dstar_types = [Attribute(None, dstar)] + else: + dstar_types = None + + # NOTE: Merge the objects properly. + + star_types = star_types or invocation.star and invocation.star.types + dstar_types = dstar_types or invocation.dstar and invocation.dstar.types + # Add star and dstar. - if star_args or invocation.star is not None: + if star_types is not None: if subprogram.star is not None: param, default = subprogram.star - items.append((param, invocation.star.types)) + items.append((param, star_types)) else: raise AnnotationMessage, "Invocation provides unwanted *args." elif subprogram.star is not None: @@ -566,10 +602,10 @@ arg = self.dispatch(default) # NOTE: Review reprocessing. items.append((param, arg.types)) - if kw_args or invocation.dstar is not None: + if dstar_types is not None: if subprogram.dstar is not None: param, default = subprogram.dstar - items.append((param, invocation.dstar.types)) + items.append((param, dstar_types)) else: raise AnnotationMessage, "Invocation provides unwanted **args." elif subprogram.dstar is not None: @@ -619,7 +655,8 @@ def merge_namespace(self, namespace): self.merge_items(namespace.names.items()) - self.returns += namespace.returns + combine(self.returns, namespace.returns) + self.temp = namespace.temp def merge_items(self, items): for name, types in items: @@ -630,9 +667,7 @@ self.names[name] = types[:] else: existing = self.names[name] - for type in types: - if type not in existing: - existing.append(type) + combine(existing, types) def snapshot(self): @@ -666,6 +701,11 @@ def __init__(self, attribute): self.types = [attribute] +def combine(target, additions): + for addition in additions: + if addition not in target: + target.append(addition) + def find_attributes(structure, name): """ @@ -693,11 +733,10 @@ # Investigate any instance's implementing class. if isinstance(structure, Instance): - for cls in structure.namespace.load("__class__"): + for attr in structure.namespace.load("__class__"): + cls = attr.type l = get_attributes(cls, name) - for attribute in l: - if attribute not in attributes: - attributes.append(attribute) + combine(attributes, l) # Investigate any class's base classes. @@ -719,11 +758,9 @@ for base_ref in base_refs: l = get_attributes(base_ref, name) - for attribute in l: - if attribute not in base_attributes: - base_attributes.append(attribute) + combine(base_attributes, l) - attributes += base_attributes + combine(attributes, base_attributes) return attributes