[pypy-svn] rev 2055 - in pypy/trunk/src/pypy/objspace/flow: . test

hpk at codespeak.net hpk at codespeak.net
Sat Oct 25 18:44:41 CEST 2003


Author: hpk
Date: Sat Oct 25 18:44:40 2003
New Revision: 2055

Added:
   pypy/trunk/src/pypy/objspace/flow/test/test_model.py
Modified:
   pypy/trunk/src/pypy/objspace/flow/model.py
Log:
added a 'traverse' and a 'flatten' method to the model. 

'traverse' lets you send a visitor over the graph. 
the visitor can either be a callable (will get all nodes)
or an object which has methods for 
    
    visit_FunctionGraph
    visit_Block
    visit_Link

or possibly even methods for subclasses like SpamBlock, EggBlock etc. 



Modified: pypy/trunk/src/pypy/objspace/flow/model.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/flow/model.py	(original)
+++ pypy/trunk/src/pypy/objspace/flow/model.py	Sat Oct 25 18:44:40 2003
@@ -3,6 +3,7 @@
 # 
 # the below object/attribute model evolved from
 # a discussion in Berlin, 4th of october 2003
+from __future__ import generators
 
 class FunctionGraph:
     def __init__(self, name, startblock, return_var=None):
@@ -91,3 +92,64 @@
             seen[item] = True
     return result
 
+
+#_________________________________________________________
+# a visitor for easy traversal of the above model
+
+import inspect   # for getmro
+
+class traverse:
+    edgedef = {
+        FunctionGraph : ('startblock',),
+        Block : ('exits',),
+        Link : ('target',),
+        }
+
+    def __init__(self, visitor, functiongraph):
+        """ send the visitor over all (reachable) nodes. 
+            the visitor needs to have either callable attributes 'visit_typename'
+            or otherwise is callable itself.  
+        """
+        self.visitor = visitor
+        self.seen = {}
+        self.visit(functiongraph)
+
+    def visit(self, node):
+        if id(node) in self.seen:
+            return
+
+        # do the visit
+        cls = node.__class__
+        for subclass in inspect.getmro(cls):
+            consume = getattr(self.visitor, "visit_" + subclass.__name__, None)
+            if consume:
+                break
+        else:
+            consume = self.visitor
+
+        self.seen[id(node)] = consume(node)
+
+        # recurse
+        for dispclass, attrs in self.edgedef.items():
+            for subclass in inspect.getmro(cls):
+                if subclass == dispclass:
+                    for attr in attrs:
+                        for obj in flattenobj(getattr(node, attr)):
+                            self.visit(obj)
+                    return
+
+        raise ValueError, "could not dispatch %r" % cls
+
+def flatten(funcgraph):
+    l = []
+    traverse(l.append, funcgraph)
+    return l
+
+def flattenobj(*args):
+    for arg in args:
+        try:
+            for atom in flattenobj(*arg):
+                yield atom
+        except: yield arg
+
+

Added: pypy/trunk/src/pypy/objspace/flow/test/test_model.py
==============================================================================
--- (empty file)
+++ pypy/trunk/src/pypy/objspace/flow/test/test_model.py	Sat Oct 25 18:44:40 2003
@@ -0,0 +1,62 @@
+import autopath
+from pypy.tool import test
+
+from pypy.objspace.flow.model import *
+
+class TestModel(test.TestCase):
+    def setUp(self):
+        self.space = test.objspace('flow')
+
+    def getflow(self, func):
+        import inspect
+        try:
+            func = func.im_func
+        except AttributeError:
+            pass
+        #name = func.func_name
+        return self.space.build_flow(func)
+
+    #_____________________________________________
+    def simplefunc(x):
+        return x+1
+
+    def test_simplefunc(self):
+        graph = self.getflow(self.simplefunc)
+        l = flatten(graph)
+        self.assertEquals(len(l), 4)
+
+    def test_class(self):
+        graph = self.getflow(self.simplefunc)
+
+        class MyVisitor:
+            def __init__(self):
+                self.blocks = []
+                self.links = []
+
+            def visit_FunctionGraph(self, graph):
+                self.graph = graph
+            def visit_Block(self, block):
+                self.blocks.append(block)
+            def visit_Link(self, link):
+                self.links.append(link)
+
+        v = MyVisitor()
+        traverse(v, graph)
+        self.assertEquals(len(v.blocks), 2)
+        self.assertEquals(len(v.links), 1)
+        self.assertEquals(v.graph, graph)
+        self.assertEquals(v.links[0], graph.startblock.exits[0])
+
+    def loop(x):
+        x = abs(x)
+        while x:
+            x = x - 1
+
+    def test_loop(self):
+        graph = self.getflow(self.simplefunc)
+        l = flatten(graph)
+        self.assertEquals(len(l), 4)
+
+
+if __name__ == '__main__':
+    test.main()


More information about the Pypy-commit mailing list