[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