# HG changeset patch # User paulb@jeremy # Date 1153175672 -7200 # Node ID d992c0a04de0f75b015f256abf3da8249f1ff6dc # Parent af353c35b70b40e96620b400992e7f40d3a880d5 Moved common visitor facilities into the simplified module. Added an annotate module and introduced subprogram traversal functionality with namespace population. Introduced a list of structures to simplify.Visitor. diff -r af353c35b70b -r d992c0a04de0 annotate.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/annotate.py Tue Jul 18 00:34:32 2006 +0200 @@ -0,0 +1,125 @@ +#!/usr/bin/env python + +""" +Traverse and annotate simplified AST structures. + +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 + +class Namespace: + def __init__(self, parent=None): + self.names = {} + self.not_local = [] + self.parent = parent + + def make_global(self, name): + if name not in self.not_local: + self.not_local.append(name) + + def store(self, name, types): + if name not in self.not_local: + self.names[name] = types + else: + self.parent.store(name, types) + + def load(self, name): + if name in self.not_local or not self.names.has_key(name): + return self.parent.load(name) + else: + return self.names[name] + + def merge(self, namespace): + for name, types in namespace.names.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 System: + def __init__(self): + self.count = 0 + def init(self, node): + if not hasattr(node, "types"): + node.types = [] + def annotate(self, node, types): + for type in types: + if type not in node.types: + node.types.append(type) + self.count += 1 + +class Traverser(Visitor): + def __init__(self): + Visitor.__init__(self) + self.system = System() + self.types = None + self.temp = {} + + def traverse(self, node): + self.namespace = Namespace() + compiler.walk(node, self, self) + if hasattr(node, "structure"): + node.structure.namespace = self.namespace + + def default(self, node): + for attr in ("args", "params"): + value = getattr(node, attr, None) + if value is not None: + self.dispatches(value) + for attr in ("expr", "lvalue", "test", "handler", "star", "dstar"): + value = getattr(node, attr, None) + if value is not None: + self.dispatch(value) + for attr in ("body", "else_", "finally_", "code"): + value = getattr(node, attr, None) + if value is not None: + for n in value: + self.dispatch(n) + print node + + def visitGlobal(self, global_): + for name in global_.names: + self.make_global(name) + + def visitLoadRef(self, loadref): + self.types = [loadref.ref] + + def visitLoadName(self, loadname): + self.types = self.namespace.load(loadname.name) + + def visitStoreName(self, storename): + self.namespace.store(storename.name, self.types) + + def visitLoadTemp(self, loadtemp): + index = getattr(loadtemp, "index", None) + self.types = self.temp[index] + + def visitStoreTemp(self, storetemp): + index = getattr(storetemp, "index", None) + self.temp[index] = self.types + + def visitReleaseTemp(self, releasetemp): + index = getattr(releasetemp, "index", None) + del self.temp[index] + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r af353c35b70b -r d992c0a04de0 simplified.py --- a/simplified.py Mon Jul 17 00:10:35 2006 +0200 +++ b/simplified.py Tue Jul 18 00:34:32 2006 +0200 @@ -21,6 +21,8 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from compiler.visitor import ASTVisitor + class Node: """ @@ -135,4 +137,20 @@ class Raise(Node): "An exception raising node." class Not(Node): "A negation of an expression." +class Visitor(ASTVisitor): + def __init__(self): + ASTVisitor.__init__(self) + + def default(self, node, *args): + raise ValueError, node.__class__ + + def dispatch(self, node, *args): + return ASTVisitor.dispatch(self, node, *args) + + def dispatches(self, nodes, *args): + results = [] + for node in nodes: + results.append(self.dispatch(node, *args)) + return results + # vim: tabstop=4 expandtab shiftwidth=4 diff -r af353c35b70b -r d992c0a04de0 simplify.py --- a/simplify.py Mon Jul 17 00:10:35 2006 +0200 +++ b/simplify.py Tue Jul 18 00:34:32 2006 +0200 @@ -21,11 +21,10 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from compiler.visitor import ASTVisitor +from simplified import * import compiler.ast -from simplified import * -class Simplifier(ASTVisitor): +class Simplifier(Visitor): """ A simplifying visitor for AST nodes. @@ -44,25 +43,12 @@ """ def __init__(self): - ASTVisitor.__init__(self) + Visitor.__init__(self) self.result = None # The resulting tree. self.subprograms = [] # Subprograms outside the tree. + self.structures = [] # Structures/classes self.current_subprograms = [] # Current subprograms being processed. - # Generic visitor methods. - - def default(self, node, *args): - raise ValueError, node.__class__ - - def dispatch(self, node, *args): - return ASTVisitor.dispatch(self, node, *args) - - def dispatches(self, nodes, *args): - results = [] - for node in nodes: - results.append(self.dispatch(node, *args)) - return results - def dispatch_or_none(self, node, *args): if node is not None: return self.dispatch(node, *args) @@ -87,26 +73,6 @@ self.result.code = self.dispatch(module.node) return self.result - def visitClass(self, class_): - structure = Class(name=hex(id(class_)), bases=class_.bases) - - subprogram = Subprogram(name=hex(id(class_)), acquire_locals=1, structure=structure, params=[], star=None, dstar=None) - self.current_subprograms.append(subprogram) - - subprogram.code = self.dispatch(class_.code) - - self.current_subprograms.pop() - self.subprograms.append(subprogram) - - # Make a definition of the class associating it with a name. - - result = Assign(class_) - init = Invoke(expr=LoadRef(ref=subprogram), args=[], star=None, dstar=None) - load = LoadRef(ref=structure) - store = StoreName(name=class_.name) - result.code = [init, load, store] - return result - def visitGetattr(self, getattr): result = LoadAttr(getattr, name=getattr.attrname) result.expr = self.dispatch(getattr.expr) @@ -588,6 +554,26 @@ # Invocation and subprogram transformations. + def visitClass(self, class_): + structure = Class(name=hex(id(class_)), bases=class_.bases) + self.structures.append(structure) + + subprogram = Subprogram(name=hex(id(class_)), acquire_locals=1, structure=structure, params=[], star=None, dstar=None) + self.current_subprograms.append(subprogram) + + subprogram.code = self.dispatch(class_.code) + + self.current_subprograms.pop() + self.subprograms.append(subprogram) + + # Make a definition of the class associating it with a name. + + result = Assign(class_) + init = Invoke(expr=LoadRef(ref=subprogram), args=[], star=None, dstar=None) + store = StoreName(name=class_.name, expr=LoadRef(ref=structure)) + result.code = [init, store] + return result + def _visitFunction(self, function, subprogram): if function.flags & 4 != 0: has_star = 1 else: has_star = 0 @@ -631,10 +617,7 @@ # Make a definition of the function associating it with a name. - result = Assign(function) - load = LoadRef(ref=subprogram) - store = StoreName(name=function.name) - result.code = [load, store] + result = StoreName(name=function.name, expr=LoadRef(ref=subprogram)) return result def visitLambda(self, lambda_): diff -r af353c35b70b -r d992c0a04de0 test.py --- a/test.py Mon Jul 17 00:10:35 2006 +0200 +++ b/test.py Tue Jul 18 00:34:32 2006 +0200 @@ -1,4 +1,11 @@ import simplify, compiler, sys +import annotate + +def traverse(n): + traverser = annotate.Traverser() + traverser.traverse(n) + return traverser + visitor = simplify.Simplifier() m = compiler.parseFile(sys.argv[1]) v = compiler.walk(m, visitor, visitor)