# HG changeset patch # User paulb@jeremy # Date 1154038857 -7200 # Node ID 33af8e19a3f86ee346f22263f419dee1b5155c73 # Parent f42f9f25d1120208b363e9c1904f074fa93c2f45 Introduced a fixnames module in order to separately define the scope for each name-related operation. Moved the Namespace class to the simplified module in order to support both the fixnames and annotate modules. Simplified the annotate module so that it focuses only on type propagation. Made sure in the fixnames module that class bases are processes and refer to the appropriate scope. Changed the order of definition and initialisation of classes. Modified the test to automatically fix the names, although this may not be desirable ultimately. diff -r f42f9f25d112 -r 33af8e19a3f8 annotate.py --- a/annotate.py Tue Jul 25 23:04:14 2006 +0200 +++ b/annotate.py Fri Jul 28 00:20:57 2006 +0200 @@ -46,63 +46,6 @@ # Namespaces and related abstractions. -class Namespace: - - """ - A local namespace which may either relate to a genuine set of function - locals or the initialisation of a structure. - """ - - def __init__(self, structure=None): - self.structure = structure - if structure is not None: - self.local = "structure" - else: - self.local = "local" - self.names = {} - self.not_local = [] - - def make_global(self, name): - if name not in self.not_local: - self.not_local.append(name) - - def find_for_store(self, name): - if name not in self.not_local: - return self.local - else: - return "global" - - def find_for_load(self, name): - if name not in self.not_local and self.names.has_key(name): - return self.local - else: - return "global" - - def store(self, name, types): - if name not in self.not_local: - self.names[name] = types - else: - raise KeyError, name - - def load(self, name): - if name in self.not_local or not self.names.has_key(name): - raise KeyError, name - else: - return self.names[name] - - def merge(self, namespace): - self.merge_items(namespace.names.items()) - - def merge_items(self, items): - for name, types in items: - if not self.names.has_key(name): - self.names[name] = types - else: - existing = self.names[name] - for type in types: - if type not in existing: - existing.append(type) - class Attribute: """ @@ -221,27 +164,15 @@ return loadref def visitLoadName(self, loadname): - scope = self.namespace.find_for_load(loadname.name) - if scope == "structure": - result = self.dispatch(LoadAttr(expr=LoadRef(ref=self.namespace.structure), name=loadname.name)) - elif scope == "global": - result = self.dispatch(LoadGlobal(name=loadname.name)) - else: - self.types = self.namespace.load(loadname.name) - result = loadname - self.annotate(result) + self.types = self.namespace.load(loadname.name) + result = loadname + self.annotate(result) return result def visitStoreName(self, storename): - scope = self.namespace.find_for_store(storename.name) - if scope == "structure": - return self.dispatch(StoreAttr(lvalue=LoadRef(ref=self.namespace.structure), name=storename.name, expr=storename.expr)) - elif scope == "global": - return self.dispatch(StoreGlobal(name=storename.name, expr=storename.expr)) - else: - storename.expr = self.dispatch(storename.expr) - self.namespace.store(storename.name, self.types) - return storename + storename.expr = self.dispatch(storename.expr) + self.namespace.store(storename.name, self.types) + return storename def visitLoadGlobal(self, loadglobal): self.types = self.global_namespace.load(loadglobal.name) diff -r f42f9f25d112 -r 33af8e19a3f8 fixnames.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fixnames.py Fri Jul 28 00:20:57 2006 +0200 @@ -0,0 +1,136 @@ +#!/usr/bin/env python + +""" +Fix name-related operations. The code in this module operates upon nodes which +are produced when simplifying AST node trees originating from the compiler +module. + +Copyright (C) 2006 Paul Boddie + +This software is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of +the License, or (at your option) any later version. + +This software is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public +License along with this library; see the file LICENCE.txt +If not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +""" + +from simplified import * +import compiler + +# Fixing of name-related operations. + +class Fixer(Visitor): + + """ + The name fixer which traverses the program nodes, typically depth-first, + and maintains a record of name usage in the different namespaces. As a + consequence of various observations, some parts of the program node tree are + modified with different operations employed to those originally defined. + """ + + def __init__(self): + Visitor.__init__(self) + + # Satisfy visitor issues. + + self.visitor = self + + def process_all(self, visitor): + subprograms = [] + for subprogram in visitor.subprograms: + subprograms.append(self.process(subprogram)) + visitor.subprograms = subprograms + visitor.result = self.process(visitor.result) + return visitor + + def process(self, node): + + """ + Process a subprogram or module 'node', indicating any initial 'locals' + and 'globals' if either are defined. Return an annotated subprogram or + module. Note that this method may mutate nodes in the original program. + """ + + # Obtain a namespace either based on locals or on a structure. + + self.namespace = Namespace(structure=getattr(node, "structure", None)) + + # Add namespace details to any structure involved. + + if hasattr(node, "structure") and node.structure is not None: + + # Initialise bases where appropriate. + + if hasattr(node.structure, "bases"): + bases = [] + for base in node.structure.bases: + bases.append(self.dispatch(base)) + node.structure.bases = bases + + # Dispatch to the code itself. + + result = self.dispatch(node) + return result + + # Visitor methods. + + def default(self, node): + + """ + Process the given 'node', given that it does not have a specific + handler. + """ + + for attr in ("args",): + value = getattr(node, attr, None) + if value is not None: + setattr(node, attr, self.dispatches(value)) + for attr in ("expr", "lvalue", "test", "handler", "star", "dstar"): + value = getattr(node, attr, None) + if value is not None: + setattr(node, attr, self.dispatch(value)) + for attr in ("body", "else_", "finally_", "code"): + value = getattr(node, attr, None) + if value is not None: + setattr(node, attr, self.dispatches(value)) + return node + + def dispatch(self, node, *args): + return Visitor.dispatch(self, node, *args) + + def visitGlobal(self, global_): + for name in global_.names: + self.namespace.make_global(name) + return global_ + + def visitLoadName(self, loadname): + scope = self.namespace.find_for_load(loadname.name) + if scope == "structure": + result = self.dispatch(LoadAttr(expr=LoadRef(ref=self.namespace.structure), name=loadname.name)) + elif scope == "global": + result = self.dispatch(LoadGlobal(name=loadname.name)) + else: + result = loadname + return result + + def visitStoreName(self, storename): + scope = self.namespace.find_for_store(storename.name) + if scope == "structure": + return self.dispatch(StoreAttr(lvalue=LoadRef(ref=self.namespace.structure), name=storename.name, expr=storename.expr)) + elif scope == "global": + return self.dispatch(StoreGlobal(name=storename.name, expr=storename.expr)) + else: + storename.expr = self.dispatch(storename.expr) + self.namespace.store(storename.name) + return storename + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r f42f9f25d112 -r 33af8e19a3f8 simplified.py --- a/simplified.py Tue Jul 25 23:04:14 2006 +0200 +++ b/simplified.py Fri Jul 28 00:20:57 2006 +0200 @@ -190,4 +190,61 @@ class Instance(Structure): "An instance." class Constant(Instance): "A constant." +class Namespace: + + """ + A local namespace which may either relate to a genuine set of function + locals or the initialisation of a structure. + """ + + def __init__(self, structure=None): + self.structure = structure + if structure is not None: + self.local = "structure" + else: + self.local = "local" + self.names = {} + self.not_local = [] + + def make_global(self, name): + if name not in self.not_local: + self.not_local.append(name) + + def find_for_store(self, name): + if name not in self.not_local: + return self.local + else: + return "global" + + def find_for_load(self, name): + if name not in self.not_local and self.names.has_key(name): + return self.local + else: + return "global" + + def store(self, name, types=None): + if name not in self.not_local: + self.names[name] = types + else: + raise KeyError, name + + def load(self, name): + if name in self.not_local or not self.names.has_key(name): + raise KeyError, name + else: + return self.names[name] + + def merge(self, namespace): + self.merge_items(namespace.names.items()) + + def merge_items(self, items): + for name, types in items: + if not self.names.has_key(name): + self.names[name] = types + else: + existing = self.names[name] + for type in types: + if type not in existing: + existing.append(type) + # vim: tabstop=4 expandtab shiftwidth=4 diff -r f42f9f25d112 -r 33af8e19a3f8 simplify.py --- a/simplify.py Tue Jul 25 23:04:14 2006 +0200 +++ b/simplify.py Fri Jul 28 00:20:57 2006 +0200 @@ -610,9 +610,9 @@ # Make a definition of the class associating it with a name. result = Assign(class_) + store = StoreName(name=class_.name, expr=LoadRef(ref=structure)) init = Invoke(expr=LoadRef(ref=subprogram), args=[], star=None, dstar=None) - store = StoreName(name=class_.name, expr=LoadRef(ref=structure)) - result.code = [init, store] + result.code = [store, init] return result def _visitFunction(self, function, subprogram): diff -r f42f9f25d112 -r 33af8e19a3f8 test.py --- a/test.py Tue Jul 25 23:04:14 2006 +0200 +++ b/test.py Fri Jul 28 00:20:57 2006 +0200 @@ -1,7 +1,11 @@ import simplify, compiler, sys +import fixnames import annotate v = simplify.Simplifier() +f = fixnames.Fixer() a = annotate.Annotator() m = compiler.parseFile(sys.argv[1]) -r = v.process(m) +v.process(m) +f.process_all(v) +r = v.result