[pypy-svn] rev 2269 - in pypy/trunk/src/pypy/annotation: . test

hpk at codespeak.net hpk at codespeak.net
Wed Nov 26 19:27:32 CET 2003


Author: hpk
Date: Wed Nov 26 19:27:30 2003
New Revision: 2269

Modified:
   pypy/trunk/src/pypy/annotation/README.txt
   pypy/trunk/src/pypy/annotation/annset.py
   pypy/trunk/src/pypy/annotation/model.py
   pypy/trunk/src/pypy/annotation/test/test_annset.py
Log:
added some more meat to AnnotationSet, mainly tests and
implementation for the new 'recording' facility. 
See the new para in annotation/README.txt 
(armin, holger)


Modified: pypy/trunk/src/pypy/annotation/README.txt
==============================================================================
--- pypy/trunk/src/pypy/annotation/README.txt	(original)
+++ pypy/trunk/src/pypy/annotation/README.txt	Wed Nov 26 19:27:30 2003
@@ -37,3 +37,11 @@
 annotations, more possibilities. 
 
 Annotations are stored in a global list, which is an AnnotationSet instance.  AnnotationSet provides (via Transactions) methods to query, add and kill annotations.  It also manages "sharing": two different SomeValue's can be later found to be identical (in the Python sense of "is"), and the AnnotationSet can be taught about this.
+
+You can't directly add annotations to an AnnotationSet. Adding an
+annotation is considered to be dependent on previous annotations. 
+Thus you invoke annset.record(func), and your function 'func' will
+be invoked with a 'Recorder' instance: you perform queries with it
+and when you add/set a new annotation the recorder will remember
+the dependency of the previous (queried) annotation towards the
+new annotation. 

Modified: pypy/trunk/src/pypy/annotation/annset.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/annset.py	(original)
+++ pypy/trunk/src/pypy/annotation/annset.py	Wed Nov 26 19:27:30 2003
@@ -10,6 +10,7 @@
     def __init__(self, annlist=[]):
         self.annlist = list(annlist)    # List of annotations
         self._shared = {}
+        self.forward_deps = {}
 
     def getsharelist(self, someval):
         return self._shared.get(someval, [someval])
@@ -28,6 +29,18 @@
     def tempid(self, someval):
         return id(self.getsharelist(someval)[0])
 
+    def annequal(self, ann1, ann2):
+        if ann1.predicate != ann2.predicate:
+            return False
+        for a1, a2 in zip(ann1.args, ann2.args):
+            if not self.isshared(a1, a2):
+                return False
+        return True
+
+    def temporarykey(self, ann):
+        """ a temporary hashable representation of an annotation """
+        return (ann.predicate, tuple([self.tempid(arg) for arg in ann.args]))
+
     def dump(self):     # debugging
         for ann in self.enumerate():
             print ann
@@ -81,65 +94,83 @@
         else:
             return None
 
+    def record(self, recfunc, *args):
+        rec = Recorder(self)
+        return recfunc(rec, *args)
 
-class Recorder:
-    """A recorder contains methods to look for annotations in the
-    AnnotationSet and create new annotations accordingly.  Each
-    Recorder instance records which Annotations were needed, which
-    allows dependencies to be tracked."""
-
-    def __init__(self, annset):
-        self.annset = annset
-        self.using_annotations = []  # annotations that we have used
-
-    def using(self, *annlist):
-        """Mark all 'ann' in 'annlist' as used in this transaction."""
-        self.using_annotations += annlist
-
-    def query(self, *querylist):
-        results = []
-        for depends, match in self.annset.getmatches(*querylist):                
-            self.using(*depends)
-            results.append(match)
-        return results
+    def kill(self, *annlist):
+        self.simplify(kill=annlist)
 
-'''
     def simplify(self, kill=[]):
         """Kill annotations in the list, and recursively all the annotations
-        that depend on them, and simplify the resulting heap to remove
+        that depend on them, and simplify the resulting list to remove
         duplicates."""
         # temporarykey() returns a tuple with all the information about
         # the annotation; equal temporarykey() means equal annotations.
-        # Such keys are temporary because making new XCells shared can
+        # Such keys are temporary because making SomeValues shared can
         # change the temporarykey(), but this doesn't occur during
         # one call to simplify().
         
         allkeys = {}   # map temporarykeys to Annotation instances
         for ann in self.annlist:
-            key = ann.temporarykey()
+            key = self.temporarykey(ann)
             if key in allkeys:  # duplicate?
                 previous = allkeys[key]
-                previous.forward_deps += ann.forward_deps   # merge
+                if ann in self.forward_deps:
+                    deps = self.forward_deps.setdefault(previous, [])
+                    deps += self.forward_deps[ann]   # merge
             else:
                 allkeys[key] = ann
 
         killkeys = {}  # set of temporarykeys of annotations to remove
         for ann in kill:
-            killkeys[ann.temporarykey()] = True
-
+            killkeys[self.temporarykey(ann)] = True
+        
         pending = killkeys.keys()
         for key in pending:
             if key in allkeys:
                 ann = allkeys[key]
                 del allkeys[key]    # remove annotations from the dict
-                for dep in ann.forward_deps:   # propagate dependencies
-                    depkey = dep.temporarykey()
-                    if depkey not in killkeys:
-                        killkeys[depkey] = True
-                        pending.append(depkey)
+                if ann in self.forward_deps:
+                    for dep in self.forward_deps[ann]:   # propagate dependencies
+                        depkey = self.temporarykey(dep)
+                        if depkey not in killkeys:
+                            killkeys[depkey] = True
+                            pending.append(depkey)
+                    del self.forward_deps[ann]
 
         self.annlist = allkeys.values()
 
+
+class Recorder:
+    """A recorder contains methods to look for annotations in the
+    AnnotationSet and create new annotations accordingly.  Each
+    Recorder instance records which Annotations were needed, which
+    allows dependencies to be tracked."""
+
+    def __init__(self, annset):
+        self.annset = annset
+        self.using_annotations = []  # annotations that we have used
+
+    def using(self, *annlist):
+        """Mark all 'ann' in 'annlist' as used in this transaction."""
+        self.using_annotations += annlist
+
+    def query(self, *querylist):
+        results = []
+        for depends, match in self.annset.getmatches(*querylist):                
+            self.using(*depends)
+            results.append(match)
+        return results
+
+    def set(self, ann):
+        """Insert the annotation into the AnnotationSet, recording dependency
+        from all previous queries done on this Recorder instance."""
+        self.annset.annlist.append(ann)
+        for previous_ann in self.using_annotations:
+            deps = self.annset.forward_deps.setdefault(previous_ann, [])
+            deps.append(ann)
+'''
     def merge(self, oldcell, newcell):
         """Update the heap to account for the merging of oldcell and newcell.
         Return the merged cell."""

Modified: pypy/trunk/src/pypy/annotation/model.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/model.py	(original)
+++ pypy/trunk/src/pypy/annotation/model.py	Wed Nov 26 19:27:30 2003
@@ -23,6 +23,8 @@
         if self.arity == 1:
             args = (args,)
         return Annotation(self, *args)
+    def __str__(self):
+        return self.name
 
 class ann:
     add = Predicate('add', 3)
@@ -45,14 +47,6 @@
         args = [renameargs.get(arg, arg) for arg in self.args]
         return Annotation(self.predicate, *args)
 
-    def __eq__(self, other):
-        return (self.__class__ is other.__class__ and 
-                self.predicate == other.predicate and
-                self.args == other.args)
-
-    def __ne__(self, other):
-        return not (self == other)
-
     def __repr__(self):
         return "Annotation(%s, %s)" % (
                 self.predicate, ", ".join(map(repr, self.args)))

Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/test/test_annset.py	(original)
+++ pypy/trunk/src/pypy/annotation/test/test_annset.py	Wed Nov 26 19:27:30 2003
@@ -31,6 +31,13 @@
         id1 = a.tempid(c1)
         id2 = a.tempid(c2)
         self.assertNotEquals(id1, id2)
+
+    def test_annequal(self):
+        c1,c2,c3,c4 = SomeValue(), SomeValue(), SomeValue(), SomeValue()
+        a = AnnotationSet()
+        a.setshared(c1,c4)
+        self.assert_(a.annequal(ann.add[c1,c2,c3],
+                                ann.add[c4,c2,c3]))
     
     def test_query_one_annotation_arg(self):
         c1,c2,c3 = SomeValue(), SomeValue(), SomeValue()
@@ -57,5 +64,36 @@
                     ann.snuff[..., c3])
         self.assertEquals(c, [c2])
 
+class TestRecording(test.IntTestCase):
+
+    def assertSameSet(self, annset, a, b):
+        a = [annset.temporarykey(a1) for a1 in a]
+        b = [annset.temporarykey(b1) for b1 in b]
+        # try to reorder a to match b, without failing if the lists
+        # are different -- this will be checked by assertEquals()
+        for i in range(len(b)):
+            try:
+                j = i + a[i:].index(b[i])
+            except ValueError:
+                pass
+            else:
+                a[i], a[j] = a[j], a[i]
+        self.assertEquals(a, b)
+
+    def test_simple(self):
+        c1,c2,c3 = SomeValue(), SomeValue(), SomeValue()
+        lst = [
+            ann.add[c1, c3, c2],
+        ]
+        a = AnnotationSet(lst)
+        def f(rec):
+            if rec.query(ann.add[c1, c3, ...]):
+                rec.set(ann.snuff[c1, c3]) 
+        a.record(f)
+        self.assertSameSet(a, a, lst + [ann.snuff[c1, c3]])
+
+        a.kill(lst[0])
+        self.assertSameSet(a, a, [])
+
 if __name__ == '__main__':
     test.main()


More information about the Pypy-commit mailing list