# HG changeset patch # User paulb@jeremy # Date 1155500634 -7200 # Node ID e7be892b6222d8601d399c18ec26e2d25ef06e8b # Parent 5603104f1d0db6263eece1675331b1069fb0d2b4 Moved return values/locals to instances of the Namespace class. Removed methods for eliminated nodes. Introduced Attribute objects as the main form of type value throughout the module. diff -r 5603104f1d0d -r e7be892b6222 annotate.py --- a/annotate.py Sun Aug 13 19:31:12 2006 +0200 +++ b/annotate.py Sun Aug 13 22:23:54 2006 +0200 @@ -41,7 +41,6 @@ if type not in node.types: node.types.append(type) self.count += 1 - print self.count system = System() @@ -75,10 +74,6 @@ self.subprograms = [] self.current_subprograms = [] self.current_namespaces = [] - self.current_returns = [] - self.current_return_locals = [] - self.current_temps = [] - self.current_types = [] # Give constants their own namespace. @@ -113,22 +108,6 @@ self.current_subprograms.append(node) self.current_namespaces.append(self.namespace) - self.current_returns.append([]) - self.current_return_locals.append([]) - self.current_temps.append({}) - self.current_types.append([]) - - # Record the namespace on the node. - # NOTE: This may eventually be a specialisation node. - - node.namespace = self.namespace - - # Remember return values and locals snapshots. - - self.return_locals = [] - self.returns = self.current_returns[-1] - self.temp = self.current_temps[-1] - self.types = self.current_types[-1] # Add namespace details to any structure involved. @@ -141,12 +120,19 @@ base_refs = [] for base in node.structure.bases: self.dispatch(base) - base_refs.append(self.types) + base_refs.append(self.namespace.types) node.structure.base_refs = base_refs # Dispatch to the code itself. + node.namespace = self.namespace result = self.dispatch(node) + result.namespace = self.namespace + + # Obtain the return values. + + self.last_returns = self.namespace.returns + self.returned_locals = self.namespace.return_locals # Restore the previous subprogram and namespace. @@ -154,22 +140,6 @@ if self.current_namespaces: self.namespace = self.current_namespaces[-1] - self.current_types.pop() - if self.current_types: - self.types = self.current_types[-1] - - self.current_temps.pop() - if self.current_temps: - self.temp = self.current_temps[-1] - - self.last_returns = self.current_returns.pop() - if self.current_returns: - self.returns = self.current_returns[-1] - - self.returned_locals = self.current_return_locals.pop() - if self.current_return_locals: - self.return_locals = self.current_return_locals[-1] - self.current_subprograms.pop() return result @@ -178,15 +148,7 @@ "Annotate the given 'node' in the system." - self.system.annotate(node, self.types) - - def add_locals_snapshot(self): - - "Make a snapshot of the locals and remember them." - - namespace = Namespace() - namespace.merge_namespace(self.namespace) - self.return_locals.append(namespace) + self.system.annotate(node, self.namespace.types) # Visitor methods. @@ -215,79 +177,69 @@ raise def visitLoadRef(self, loadref): - self.types = [loadref.ref] + self.namespace.set_types([Attribute(None, loadref.ref)]) self.annotate(loadref) return loadref def visitLoadName(self, loadname): - self.types = self.namespace.load(loadname.name) + self.namespace.set_types(self.namespace.load(loadname.name)) result = loadname self.annotate(result) return result def visitStoreName(self, storename): storename.expr = self.dispatch(storename.expr) - self.namespace.store(storename.name, self.types) + self.namespace.store(storename.name, self.namespace.types) return storename - def visitLoadGlobal(self, loadglobal): - self.types = self.global_namespace.load(loadglobal.name) - self.annotate(loadglobal) - return loadglobal - - def visitLoadBuiltin(self, loadbuiltin): - self.types = self.builtins_namespace.load(loadbuiltin.name) - self.annotate(loadbuiltin) - return loadbuiltin - - def visitStoreGlobal(self, storeglobal): - storeglobal.expr = self.dispatch(storeglobal.expr) - self.global_namespace.merge(storeglobal.name, self.types) - return storeglobal - def visitLoadTemp(self, loadtemp): index = getattr(loadtemp, "index", None) - self.types = self.temp[index][-1] + self.namespace.set_types(self.namespace.temp[index][-1]) self.annotate(loadtemp) return loadtemp def visitStoreTemp(self, storetemp): storetemp.expr = self.dispatch(storetemp.expr) index = getattr(storetemp, "index", None) - if not self.temp.has_key(index): - self.temp[index] = [] - self.temp[index].append(self.types) + if not self.namespace.temp.has_key(index): + self.namespace.temp[index] = [] + self.namespace.temp[index].append(self.namespace.types) return storetemp def visitReleaseTemp(self, releasetemp): index = getattr(releasetemp, "index", None) - self.temp[index].pop() + self.namespace.temp[index].pop() return releasetemp def visitLoadAttr(self, loadattr): loadattr.expr = self.dispatch(loadattr.expr) types = [] accesses = {} - for ref in self.types: - if not accesses.has_key(ref): - accesses[ref] = [] - for attribute, accessor in get_attributes(ref, loadattr.name): - if attribute.type is not None: - types.append(type) - accesses[ref].append((attribute, accessor)) - self.types = types + for attr in self.namespace.types: + if not accesses.has_key(attr.type): + accesses[attr.type] = [] + for attribute, accessor in get_attributes(attr.type, loadattr.name): + if attribute is not None: + types.append(attribute) + else: + print "Empty attribute via accessor", accessor + accesses[attr.type].append((attribute, accessor)) + self.namespace.set_types(types) loadattr.accesses = accesses self.annotate(loadattr) return loadattr def visitStoreAttr(self, storeattr): storeattr.expr = self.dispatch(storeattr.expr) - expr = self.types + expr = self.namespace.types storeattr.lvalue = self.dispatch(storeattr.lvalue) accesses = {} - for ref in self.types: - ref.namespace.store(storeattr.name, expr) - accesses[ref] = ref.namespace.load(storeattr.name) + for attr in self.namespace.types: + if attr is None: + print "Empty attribute storage attempt" + continue + attr.type.namespace.store(storeattr.name, expr) + accesses[attr.type] = attr.type.namespace.load(storeattr.name) storeattr.accesses = accesses return storeattr @@ -318,13 +270,13 @@ def visitReturn(self, return_): if hasattr(return_, "expr"): return_.expr = self.dispatch(return_.expr) - self.returns += self.types - self.add_locals_snapshot() + self.namespace.returns += self.namespace.types + self.namespace.snapshot() return return_ def visitInvoke(self, invoke): invoke.expr = self.dispatch(invoke.expr) - expr = self.types + invocation_types = self.namespace.types # NOTE: Consider initialiser invocation for classes. @@ -335,7 +287,7 @@ for arg in invoke.args: args.append(self.dispatch(arg)) - types.append(self.types) + types.append(self.namespace.types) # Get type information for star and dstar arguments. @@ -361,44 +313,47 @@ # Visit each callable in turn, finding subprograms. - for callable in expr: + for attr in invocation_types: # Deal with class invocations by providing instance objects. # Here, each class is queried for the __init__ method, which may # exist for some combinations of classes in a hierarchy but not for # others. - if isinstance(callable, Class): - attributes = get_attributes(callable, "__init__") + if isinstance(attr.type, Class): + attributes = get_attributes(attr.type, "__init__") # Deal with object invocations by using __call__ methods. - elif isinstance(callable, Instance): - attributes = get_attributes(callable, "__call__") + elif isinstance(attr.type, Instance): + attributes = get_attributes(attr.type, "__call__") # Normal functions or methods are more straightforward. # Here, we model them using an attribute with no context and with # no associated accessor. else: - attributes = [(Attribute(None, callable), None)] + attributes = [(attr, None)] # Inspect each attribute and extract the subprogram. for attribute, accessor in attributes: + if attribute is None: + print "Invocation type is None" + continue + subprogram = attribute.type # If a subprogram is defined, invoke it. - if subprogram is not None: - self.invoke_subprogram(invoke, subprogram) - invocations[callable] = subprogram + self.invoke_subprogram(invoke, subprogram) + invocations[callable] = subprogram # If a class is involved, presume that it must create a new # object. - if isinstance(callable, Class): - self.types = [attribute.context] + if isinstance(attr.type, Class): + self.namespace.set_types([Attribute(None, attribute.context)]) self.annotate(invoke) invoke.invocations = invocations @@ -443,7 +398,7 @@ # NOTE: Improve and verify this. if getattr(subprogram, "returns_value", 0): - self.types = self.last_returns + self.namespace.set_types(self.last_returns) self.annotate(invoke) if getattr(invoke, "same_frame", 0): @@ -536,6 +491,14 @@ def __init__(self): self.names = {} + self.returns = [] + self.return_locals = [] + self.temp = {} + self.types = [] + + def set_types(self, types): + print "Setting", types + self.types = types def store(self, name, types): self.names[name] = types @@ -559,6 +522,14 @@ for name, types in items: self.merge(name, types) + def snapshot(self): + + "Make a snapshot of the locals and remember them." + + namespace = Namespace() + namespace.merge_namespace(self) + self.return_locals.append(namespace) + def __repr__(self): return repr(self.names) @@ -638,7 +609,7 @@ attributes += base_attributes - return attributes + return attributes def get_attributes(structure, name): @@ -653,9 +624,6 @@ if isinstance(structure, Attribute): structure = structure.type - attributes = find_attributes(structure, name) - for i, (attribute, accessor) in enumerate(attributes): - attributes[i] = Attribute(structure, attribute), accessor - return attributes + return find_attributes(structure, name) # vim: tabstop=4 expandtab shiftwidth=4