[pypy-svn] rev 2206 - in pypy/trunk/src/pypy/translator: . test

arigo at codespeak.net arigo at codespeak.net
Mon Nov 17 18:29:21 CET 2003


Author: arigo
Date: Mon Nov 17 18:29:19 2003
New Revision: 2206

Added:
   pypy/trunk/src/pypy/translator/annotation.py
   pypy/trunk/src/pypy/translator/test/test_annotation.py
Modified:
   pypy/trunk/src/pypy/translator/annheap.py
   pypy/trunk/src/pypy/translator/test/test_annheap.py
Log:
Added dependencies among annotations.  AnnotationHeap.merge() will now 
recursively kill annotations and those that depended on them.

The new Transaction class is needed to record dependencies.  Annotations are 
no longer looked up through the AnnotationHeap but via a Transaction instance, 
which records it so that new annotations can be marked as depending on 
the existing annotations that have just been looked up.


Modified: pypy/trunk/src/pypy/translator/annheap.py
==============================================================================
--- pypy/trunk/src/pypy/translator/annheap.py	(original)
+++ pypy/trunk/src/pypy/translator/annheap.py	Mon Nov 17 18:29:19 2003
@@ -1,152 +1,72 @@
 from __future__ import generators
-import weakref
-from pypy.objspace.flow.model import Variable, Constant, SpaceOperation
-
-
-class XCell:
-    """A placeholder for a heap object contained in an AnnotationHeap.
-    It represents an object that will actually appear at run-time in the heap.
-    XCells are the arguments and return value of SpaceOperations when
-    used as annotations."""
-
-    counter = 0
-
-    # Multiple XCells can be "shared"; a group of shared cells
-    # act essentially like a single cell (they become all equal).
-    
-    def __init__(self, name=None):
-        if not name:
-            name = 'X%d' % XCell.counter
-            XCell.counter += 1
-        self.name = name
-        self.shared = []    # list of weakrefs to XCells
-                            # defining a group of shared cells.
-
-    def __repr__(self):
-        names = [cell.name for cell in self.cellsingroup()]
-        names.sort()
-        return '=='.join(names)
-
-    def __eq__(self, other):
-        "Two sharing cells are equal."
-        return isinstance(other, XCell) and self.is_shared(other)
-
-    def __ne__(self, other):
-        return not (self == other)
-
-    def cellsingroup(self):
-        if self.shared:
-            l = [s() for s in self.shared]
-            assert self in l
-            return [c for c in l if c is not None]
-        else:
-            return [self]
-
-    def getsharelist(self):
-        if not self.shared:
-            self.shared = [weakref.ref(self)]
-        return self.shared
-
-    def is_shared(self, other):
-        "Test if two cells are shared."
-        return self.shared is other.shared
-
-    def share(self, other):
-        "Make two cells shared."
-        if not self.is_shared(other):
-            lst1 = self.getsharelist()
-            lst2 = other.getsharelist()
-            for s in lst2:
-                c = s()
-                if c is not None:
-                    c.shared = lst1
-                    lst1.append(s)
-
-
-class XConstant(XCell):
-    """A fully determined XCell.  For immutable constants."""
-
-    def __init__(self, value):
-        XCell.__init__(self)
-        self.value = value
-
-    def __eq__(self, other):
-        "Two constants with the same value are equal."
-        return (isinstance(other, XConstant) and self.value == other.value
-                or XCell.__eq__(self, other))
-
-
-# The more annotations about an XCell, the least general
-# it is.  Extreme case: *all* possible annotations stand for an
-# object that cannot exist (e.g. the return value of a function
-# that never returns or we didn't see return so far).
-# This is specified by using nothingyet instead of a real XCell().
-# Conversely, *no* annotation stands for any object.
-
-nothingyet = XCell('nothingyet')
+from annotation import Annotation, XCell, XConstant, nothingyet
 
 
 class AnnotationHeap:
-    """An annotation heap is a (large) family of annotations.
-    An annotation is a SpaceOperation with XCells as arguments and result."""
+    """An annotation heap is a (large) family of Annotations."""
+
+    # XXX STORED AS A PLAIN LIST, THE COMPLEXITY IS PLAINLY WRONG
 
     def __init__(self, annlist=[]):
-        self.annlist = []    # List of annotations  XXX optimize
-        for ann in annlist:
-            self.add(ann)
+        self.annlist = list(annlist)    # List of annotations
 
     def dump(self):     # debugging
         for ann in self.enumerate():
             print ann
 
-    def add(self, annotation):
-        """Register an annotation into the heap."""
-        if annotation not in self.annlist:
-            self.annlist.append(annotation)
-
     def enumerate(self):
         """Enumerates all annotations in the heap."""
         return iter(self.annlist)
 
     __iter__ = enumerate
 
-    def set_type(self, cell, type):
-        """Register an annotation describing the type of the object 'cell'."""
-        self.add(SpaceOperation('type', [cell], XConstant(type)))
+    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
+        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
+        # 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()
+            if key in allkeys:  # duplicate?
+                previous = allkeys[key]
+                previous.forward_deps += ann.forward_deps   # merge
+            else:
+                allkeys[key] = ann
 
-    def get_type(self, cell):
-        """Get the type of 'cell', as specified by the annotations, or None."""
-        c = self.get_opresult('type', [cell])
-        if isinstance(c, XConstant):
-            return c.value
-        else:
-            return None
+        killkeys = {}  # set of temporarykeys of annotations to remove
+        for ann in kill:
+            killkeys[ann.temporarykey()] = 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)
 
-    def get_opresult(self, name, args):
-        """Return the Cell with the annotation 'name(args) = cell',
-        or None if there is no such annotation, or several different ones."""
-        result = None
-        for ann in self.annlist:
-            if ann.opname == name and ann.args == args:
-                if result is None:
-                    result = ann.result
-                elif ann.result != result:
-                    return None
-        return result
+        self.annlist = allkeys.values()
 
     def merge(self, oldcell, newcell):
         """Update the heap to account for the merging of oldcell and newcell.
-        Return (resultcell, changeflag) where resultcell is the merged cell.
-        changeflag is false only if the merged cell is equal to oldcell and
-        no annotations about oldcell have been dropped."""
+        Return the merged cell."""
         if newcell is nothingyet or newcell == oldcell:
-            return oldcell, False
+            return oldcell
         elif oldcell is nothingyet:
-            return newcell, True
+            return newcell
         else:
             # find the annotations common to oldcell and newcell
             common = []
-            deleting = False  # means deleting an annotation about oldcell
+            deleting = []  # annotations about oldcell that must be killed
             for ann in self.annlist:
                 if oldcell in ann.args or oldcell == ann.result:
                     test1 = rename(ann, oldcell, newcell)
@@ -154,30 +74,32 @@
                     if test1 in self.annlist and test2 in self.annlist:
                         common.append(test1)
                     else:
-                        deleting = True
+                        deleting.append(test1)
             # the involved objects are immutable if we have both
             # 'immutable() -> oldcell' and 'immutable() -> newcell'
-            if SpaceOperation('immutable', [], newcell) in common:
+            if Annotation('immutable', [], newcell) in common:
                 # for immutable objects we can create a new cell if necessary
                 if not deleting:
-                    return oldcell, False  # nothing must be removed from oldcell
+                    return oldcell  # nothing must be removed from oldcell
                 else:
                     resultcell = XCell()  # invent a new cell
                     for ann in common:
-                        self.add(rename(ann, newcell, resultcell))
-                    return resultcell, True
+                        self.annlist.append(rename(ann, newcell, resultcell))
+                    return resultcell
             else:
                 # for mutable objects we must identify oldcell and newcell,
                 # and only keep the common annotations
                 newcell.share(oldcell)
-                # add to 'common' all annotations that don't talk about oldcell
-                # (nor newcell, but at this point oldcell == newcell)
+                # search again and list all annotations that talk about
+                # oldcell or newcell (same thing now) but are not in 'common'
+                deleting = []
                 for ann in self.annlist:
-                    if not (oldcell in ann.args or oldcell == ann.result):
-                        common.append(ann)
-                # 'common' is now the list of remaining annotations
-                self.annlist[:] = common
-                return oldcell, deleting
+                    if oldcell in ann.args or oldcell == ann.result:
+                        if ann not in common:
+                            deleting.append(ann)
+                # apply changes
+                self.simplify(kill=deleting)
+                return oldcell
 
 
 def rename(ann, oldcell, newcell):
@@ -190,4 +112,57 @@
     a = ann.result
     if a == oldcell:
         a = newcell
-    return SpaceOperation(ann.opname, args, a)
+    return Annotation(ann.opname, args, a)
+
+
+class Transaction:
+    """A transaction contains methods to look for annotations in the
+    AnnotationHeap and create new annotations accordingly.  Each
+    Transaction instance records which Annotations were needed, which
+    allows dependencies to be tracked."""
+
+    def __init__(self, heap):
+        self.heap = heap
+        self.using_annotations = []  # annotations that we have used
+
+    def get(self, opname, args):
+        """Return the Cell with the annotation 'opname(args) -> Cell',
+        or None if there is no such annotation or several different ones."""
+        matchann = None
+        for ann in self.heap.annlist:
+            if ann.opname == opname and ann.args == args:
+                if matchann is None:
+                    matchann = ann     # first possible annotation
+                elif matchann != ann:
+                    return None        # more than one annotation would match
+        if matchann is None:
+            return None
+        else:
+            self.using(matchann)
+            return matchann.result
+        # a note about duplicate Annotations in annlist: their forward_deps
+        # lists will automatically be merged during the next simplify(),
+        # so that we only need to record the dependency from one of them.
+
+    def set(self, opname, args, result):
+        """Put a new annotation into the AnnotationHeap."""
+        ann = Annotation(opname, args, result)
+        for prev in self.using_annotations:
+            prev.forward_deps.append(ann)
+        self.heap.annlist.append(ann)
+
+    def get_type(self, cell):
+        """Get the type of 'cell', as specified by the annotations, or None."""
+        c = self.get('type', [cell])
+        if isinstance(c, XConstant):
+            return c.value
+        else:
+            return None
+
+    def set_type(self, cell, type):
+        """Register an annotation describing the type of the object 'cell'."""
+        self.set('type', [cell], XConstant(type))
+
+    def using(self, ann):
+        """Mark 'ann' as used in this transaction."""
+        self.using_annotations.append(ann)

Added: pypy/trunk/src/pypy/translator/annotation.py
==============================================================================
--- (empty file)
+++ pypy/trunk/src/pypy/translator/annotation.py	Mon Nov 17 18:29:19 2003
@@ -0,0 +1,123 @@
+import weakref
+
+
+class Annotation:
+    """An Annotation asserts something about heap objects represented
+    by XCell instances."""
+    
+    # Note that this is very much like a SpaceOperation, but we keep
+    # them separate because they have different purposes.
+
+    # Attention, handle Annotations with care!  Two Annotations that
+    # were initially different could become equal when XCells become
+    # shared.  This is the reason why Annotations are not hashable.
+
+    def __init__(self, opname, args, result):
+        self.opname = opname      # operation name
+        self.args   = list(args)  # list of XCells
+        self.result = result      # an XCell
+        self.forward_deps = []    # annotations that depend on this one
+
+    def __eq__(self, other):
+        return (self.__class__ is other.__class__ and 
+                self.opname == other.opname and
+                self.args == other.args and
+                self.result == other.result)
+
+    def __ne__(self, other):
+        return not (self == other)
+
+    def __repr__(self):
+        return "%s(%s) -> %s" % (self.opname, ", ".join(map(repr, self.args)),
+                                 self.result)
+
+    def temporarykey(self):
+        lst = [self.opname, self.result.temporarykey()]
+        lst += [arg.temporarykey() for arg in self.args]
+        return tuple(lst)
+
+
+class XCell:
+    """A placeholder for a heap object contained in an AnnotationHeap.
+    It represents an object that will actually appear at run-time in the heap.
+    XCells are the arguments and return value of Annotations."""
+
+    counter = 0
+
+    # Multiple XCells can be "shared"; a group of shared cells
+    # act essentially like a single cell (they become all equal).
+    
+    def __init__(self, name=None):
+        if not name:
+            name = 'X%d' % XCell.counter
+            XCell.counter += 1
+        self.name = name
+        self.shared = []    # list of weakrefs to XCells
+                            # defining a group of shared cells.
+
+    def __repr__(self):
+        names = [cell.name for cell in self.cellsingroup()]
+        names.sort()
+        return '=='.join(names)
+
+    def __eq__(self, other):
+        "Two sharing cells are equal."
+        return isinstance(other, XCell) and self.is_shared(other)
+
+    def __ne__(self, other):
+        return not (self == other)
+
+    def temporarykey(self):
+        ids = [id(cell) for cell in self.cellsingroup()]
+        return min(ids)
+
+    def cellsingroup(self):
+        if self.shared:
+            l = [s() for s in self.shared]
+            assert self in l
+            return [c for c in l if c is not None]
+        else:
+            return [self]
+
+    def getsharelist(self):
+        if not self.shared:
+            self.shared = [weakref.ref(self)]
+        return self.shared
+
+    def is_shared(self, other):
+        "Test if two cells are shared."
+        return self.shared is other.shared
+
+    def share(self, other):
+        "Make two cells shared."
+        if not self.is_shared(other):
+            lst1 = self.getsharelist()
+            lst2 = other.getsharelist()
+            for s in lst2:
+                c = s()
+                if c is not None:
+                    c.shared = lst1
+                    lst1.append(s)
+
+
+class XConstant(XCell):
+    """A fully determined XCell.  For immutable constants."""
+
+    def __init__(self, value):
+        XCell.__init__(self)
+        self.value = value
+
+    def __eq__(self, other):
+        "Two constants with the same value are equal."
+        return (isinstance(other, XConstant) and self.value == other.value
+                or XCell.__eq__(self, other))
+
+
+# The more annotations about an XCell, the least general
+# it is.  Extreme case: *all* possible annotations stand for an
+# object that cannot exist (e.g. the return value of a function
+# that never returns or we didn't see return so far).
+# This is specified by using nothingyet instead of a real XCell().
+# Conversely, *no* annotation stands for any object.
+
+nothingyet = XCell('nothingyet')

Modified: pypy/trunk/src/pypy/translator/test/test_annheap.py
==============================================================================
--- pypy/trunk/src/pypy/translator/test/test_annheap.py	(original)
+++ pypy/trunk/src/pypy/translator/test/test_annheap.py	Mon Nov 17 18:29:19 2003
@@ -2,33 +2,8 @@
 import autopath
 from pypy.tool import test
 
-from pypy.translator.annheap import XCell, XConstant, AnnotationHeap, nothingyet
-from pypy.objspace.flow.model import SpaceOperation
-
-
-class TestXCell(test.IntTestCase):
-
-    def test_is_shared(self):
-        c1 = XCell()
-        c2 = XCell()
-        c3 = XCell()
-        c4 = XCell()
-        for a in (c1,c2,c3,c4):
-            for b in (c1,c2,c3,c4):
-                if a is not b:
-                    self.failIfEqual(a, b)
-        c1.share(c2)
-        c4.share(c2)
-        c1.share(c3)
-        for a in (c1,c2,c3,c4):
-            for b in (c1,c2,c3,c4):
-                self.assert_(a.is_shared(b))
-                self.assertEquals(a, b)
-
-    def test_constant(self):
-        self.assertEquals(XConstant(5), XConstant(5))
-        self.failIfEqual(XConstant(5), XConstant(6))
-        self.failIfEqual(XConstant(5), XCell())
+from pypy.translator.annotation import XCell, XConstant, nothingyet, Annotation
+from pypy.translator.annheap import AnnotationHeap, Transaction
 
 
 class TestAnnotationHeap(test.IntTestCase):
@@ -52,110 +27,103 @@
                 a[i], a[j] = a[j], a[i]
         self.assertEquals(a, b)
 
-    def test_add(self):
-        lst = [SpaceOperation('add', [self.c1, self.c3], self.c2),
-               SpaceOperation('neg', [self.c2], self.c3)]
-        a = AnnotationHeap()
-        self.assertSameSet(a, [])
-        a.add(lst[1])
-        self.assertSameSet(a, [lst[1]])
-        a.add(lst[0])
-        self.assertSameSet(a, lst)
-        a.add(lst[0])
-        self.assertSameSet(a, lst)
-        a.add(lst[1])
-        self.assertSameSet(a, lst)
-
     def test_enumerate(self):
-        lst = [SpaceOperation('add', [self.c1, self.c3], self.c2)]
+        lst = [Annotation('add', [self.c1, self.c3], self.c2)]
         a = AnnotationHeap(lst)
         self.assertSameSet(a.enumerate(), lst)
 
-    def test_get_opresult(self):
-        lst = [SpaceOperation('add', [self.c1, self.c3], self.c2)]
+    def test_simplify(self):
+        lst = [Annotation('add', [self.c1, self.c3], self.c2),
+               Annotation('add', [self.c1, self.c2], self.c2),
+               Annotation('neg', [self.c2], self.c3)]
+        a = AnnotationHeap(lst)
+        a.simplify()
+        self.assertSameSet(a, lst)
+        
+        self.c2.share(self.c3)
+        a.simplify()
+        self.assertSameSet(a, lst[1:])
+
+    def test_simplify_kill(self):
+        ann1 = Annotation('add', [self.c1, self.c3], self.c2)
+        lst = [ann1,
+               Annotation('add', [self.c1, self.c2], self.c2),
+               Annotation('neg', [self.c2], self.c3)]
+        a = AnnotationHeap(lst)
+        a.simplify(kill=[ann1])
+        self.assertSameSet(a, lst[1:])
+
+    def test_simplify_kill_deps(self):
+        ann1 = Annotation('add', [self.c1, self.c3], self.c2)
+        ann2 = Annotation('add', [self.c1, self.c2], self.c2)
+        ann3 = Annotation('add', [self.c1, self.c1], self.c2)
+        ann1.forward_deps.append(ann2)
+        ann2.forward_deps.append(ann3)
+        lst = [ann1, ann2, ann3,
+               Annotation('neg', [self.c2], self.c3)]
         a = AnnotationHeap(lst)
-        self.assertEquals(a.get_opresult('add', [self.c1, self.c3]), self.c2)
-        self.assertEquals(a.get_opresult('add', [self.c1, self.c2]), None)
-        self.assertEquals(a.get_opresult('sub', [self.c1, self.c3]), None)
-
-    def test_get_type(self):
-        lst = [SpaceOperation('type', [self.c1], self.c3),
-               SpaceOperation('type', [self.c2], self.c1)]
-        a = AnnotationHeap(lst)
-        self.assertEquals(a.get_type(self.c1), -2)
-        self.assertEquals(a.get_type(self.c2), None)
-        self.assertEquals(a.get_type(self.c3), None)
-
-    def test_set_type(self):
-        a = AnnotationHeap()
-        a.set_type(self.c1, int)
-        lst = [SpaceOperation('type', [self.c1], XConstant(int))]
-        self.assertSameSet(a, lst)
+        a.simplify(kill=[ann1])
+        self.assertSameSet(a, lst[3:])
 
     def test_merge_nothingyet(self):
-        lst = [SpaceOperation('add', [self.c1, self.c3], self.c2),
-               SpaceOperation('neg', [self.c2], self.c3)]
+        lst = [Annotation('add', [self.c1, self.c3], self.c2),
+               Annotation('neg', [self.c2], self.c3)]
         a = AnnotationHeap(lst)
         # (c3) inter (all annotations) == (c3)
-        c, changeflag = a.merge(self.c3, nothingyet)
-        self.failIf(changeflag)
+        c = a.merge(self.c3, nothingyet)
         self.assertEquals(c, self.c3)
         self.failIfEqual(c, nothingyet)
         self.assertSameSet(a, lst)
 
     def test_merge_mutable1(self):
-        lst = [SpaceOperation('type', [self.c1], self.c3),
-               SpaceOperation('type', [self.c2], self.c3),
-               SpaceOperation('somethingelse', [self.c2, self.c3], self.c3)]
+        lst = [Annotation('type', [self.c1], self.c3),
+               Annotation('type', [self.c2], self.c3),
+               Annotation('somethingelse', [self.c2, self.c3], self.c3)]
         a = AnnotationHeap(lst)
         # (c1) inter (c2) == (c1 shared with c2)
-        c, changeflag = a.merge(self.c1, self.c2)
-        self.failIf(changeflag)
+        c = a.merge(self.c1, self.c2)
         self.assertEquals(c, self.c1)
         self.assertEquals(c, self.c2)
         self.assertEquals(self.c1, self.c2)
-        self.assertSameSet(a, [SpaceOperation('type', [c], self.c3)])
+        self.assertSameSet(a, [Annotation('type', [c], self.c3)])
 
     def test_merge_mutable2(self):
-        lst = [SpaceOperation('type', [self.c1], self.c3),
-               SpaceOperation('type', [self.c2], self.c3),
-               SpaceOperation('somethingelse', [self.c1, self.c3], self.c3)]
+        lst = [Annotation('type', [self.c1], self.c3),
+               Annotation('type', [self.c2], self.c3),
+               Annotation('somethingelse', [self.c1, self.c3], self.c3)]
         a = AnnotationHeap(lst)
         # (c1) inter (c2) == (c1 shared with c2)
-        c, changeflag = a.merge(self.c1, self.c2)
-        self.assert_(changeflag)
+        c = a.merge(self.c1, self.c2)
         self.assertEquals(c, self.c1)
         self.assertEquals(c, self.c2)
         self.assertEquals(self.c1, self.c2)
-        self.assertSameSet(a, [SpaceOperation('type', [c], self.c3)])
+        self.assertSameSet(a, [Annotation('type', [c], self.c3)])
 
     def test_merge_immutable(self):
-        lst = [SpaceOperation('type', [self.c1], self.c3),
-               SpaceOperation('type', [self.c2], self.c3),
-               SpaceOperation('immutable', [], self.c1),
-               SpaceOperation('immutable', [], self.c2),
-               SpaceOperation('somethingelse', [self.c2, self.c3], self.c3)]
+        lst = [Annotation('type', [self.c1], self.c3),
+               Annotation('type', [self.c2], self.c3),
+               Annotation('immutable', [], self.c1),
+               Annotation('immutable', [], self.c2),
+               Annotation('somethingelse', [self.c2, self.c3], self.c3)]
         a = AnnotationHeap(lst)
         # (c1) inter (c2) == (some new c4)
-        c, changeflag = a.merge(self.c1, self.c2)
-        self.failIf(changeflag)  # because only c2 has annotations dropped
+        c = a.merge(self.c1, self.c2)
         self.failIfEqual(self.c1, self.c2)
         # c could be equal to c1 here, but we don't require that
-        for op in [SpaceOperation('type', [c], self.c3),
-                   SpaceOperation('immutable', [], c)]:
+        for op in [Annotation('type', [c], self.c3),
+                   Annotation('immutable', [], c)]:
             if op not in lst:
                 lst.append(op)
         self.assertSameSet(a, lst)
 
     def test_merge_mutable_ex(self):
-        lst = [SpaceOperation('add', [self.c1, self.c2], self.c2),
-               SpaceOperation('neg', [self.c2], self.c1),
-               SpaceOperation('add', [self.c3, self.c2], self.c2),
-               SpaceOperation('immutable', [], self.c2)]
+        lst = [Annotation('add', [self.c1, self.c2], self.c2),
+               Annotation('neg', [self.c2], self.c1),
+               Annotation('add', [self.c3, self.c2], self.c2),
+               Annotation('immutable', [], self.c2)]
         a = AnnotationHeap(lst)
         # (c1) inter (c3) == (c1 shared with c3)
-        c, changeflag = a.merge(self.c1, self.c3)
-        self.assert_(changeflag)
+        c = a.merge(self.c1, self.c3)
         self.assertEquals(c, self.c1)
         self.assertEquals(c, self.c3)
         self.assertEquals(self.c1, self.c3)
@@ -163,20 +131,19 @@
         self.assertSameSet(a, [lst[2], lst[3]])
 
     def test_merge_immutable_ex(self):
-        lst = [SpaceOperation('add', [self.c1, self.c2], self.c2),
-               SpaceOperation('neg', [self.c2], self.c1),
-               SpaceOperation('add', [self.c3, self.c2], self.c2),
-               SpaceOperation('immutable', [], self.c1),
-               SpaceOperation('immutable', [], self.c2),
-               SpaceOperation('immutable', [], self.c3)]
+        lst = [Annotation('add', [self.c1, self.c2], self.c2),
+               Annotation('neg', [self.c2], self.c1),
+               Annotation('add', [self.c3, self.c2], self.c2),
+               Annotation('immutable', [], self.c1),
+               Annotation('immutable', [], self.c2),
+               Annotation('immutable', [], self.c3)]
         a = AnnotationHeap(lst)
         # (c1) inter (c3) == (some new c4)
-        c, changeflag = a.merge(self.c1, self.c3)
-        self.assert_(changeflag)  # because 'neg(..)=c1' is dropped
+        c = a.merge(self.c1, self.c3)
         self.failIfEqual(c, self.c1)
         self.failIfEqual(c, self.c3)
-        lst += [SpaceOperation('add', [c, self.c2], self.c2),
-                SpaceOperation('immutable', [], c)]
+        lst += [Annotation('add', [c, self.c2], self.c2),
+                Annotation('immutable', [], c)]
         self.assertSameSet(a, lst)
 
     def dont_test_merge_mutable_ex(self):
@@ -185,14 +152,13 @@
         # clear enough right now.  In theory in the intersection below
         # 'add' should be kept.  In practice the extra 'c3' messes things
         # up.  I can only think about much-more-obscure algos to fix that.
-        lst = [SpaceOperation('add', [self.c1, self.c3], self.c2),
-               SpaceOperation('neg', [self.c2], self.c1),
-               SpaceOperation('add', [self.c3, self.c3], self.c2),
-               SpaceOperation('immutable', [], self.c2)]
+        lst = [Annotation('add', [self.c1, self.c3], self.c2),
+               Annotation('neg', [self.c2], self.c1),
+               Annotation('add', [self.c3, self.c3], self.c2),
+               Annotation('immutable', [], self.c2)]
         a = AnnotationHeap(lst)
         # (c1) inter (c3) == (c1 shared with c3)
-        c, changeflag = a.merge(self.c1, self.c3)
-        self.assert_(changeflag)
+        c = a.merge(self.c1, self.c3)
         self.assertEquals(c, self.c1)
         self.assertEquals(c, self.c3)
         self.assertEquals(self.c1, self.c3)
@@ -201,22 +167,77 @@
 
     def dont_test_merge_immutable_ex(self):
         # Disabled -- same as above.
-        lst = [SpaceOperation('add', [self.c1, self.c3], self.c2),
-               SpaceOperation('neg', [self.c2], self.c1),
-               SpaceOperation('add', [self.c3, self.c3], self.c2),
-               SpaceOperation('immutable', [], self.c1),
-               SpaceOperation('immutable', [], self.c2),
-               SpaceOperation('immutable', [], self.c3)]
+        lst = [Annotation('add', [self.c1, self.c3], self.c2),
+               Annotation('neg', [self.c2], self.c1),
+               Annotation('add', [self.c3, self.c3], self.c2),
+               Annotation('immutable', [], self.c1),
+               Annotation('immutable', [], self.c2),
+               Annotation('immutable', [], self.c3)]
         a = AnnotationHeap(lst)
         # (c1) inter (c3) == (some new c4)
-        c, changeflag = a.merge(self.c1, self.c3)
-        self.assert_(changeflag)  # because 'neg(..)=c1' is dropped
+        c = a.merge(self.c1, self.c3)
         self.failIfEqual(c, self.c1)
         self.failIfEqual(c, self.c3)
-        lst += [SpaceOperation('add', [c, self.c3], self.c2),
-                SpaceOperation('immutable', [], c)]
+        lst += [Annotation('add', [c, self.c3], self.c2),
+                Annotation('immutable', [], c)]
         self.assertSameSet(a, lst)
 
 
+class TestTransaction(test.IntTestCase):
+
+    def setUp(self):
+        self.c1 = XCell()
+        self.c2 = XCell()
+        self.c3 = XConstant(-2)
+        self.lst = [Annotation('add', [self.c1, self.c3], self.c2),
+                    Annotation('neg', [self.c2], self.c1),
+                    Annotation('add', [self.c3, self.c3], self.c2),
+                    Annotation('immutable', [], self.c1),
+                    Annotation('type', [self.c1], self.c3),
+                    Annotation('type', [self.c3], self.c2)]
+        self.a = AnnotationHeap(self.lst)
+
+    def test_get(self):
+        t = Transaction(self.a)
+        self.assertEquals(t.get('add', [self.c1, self.c3]), self.c2)
+        self.assertEquals(t.get('add', [self.c1, self.c2]), None)
+        self.assertEquals(t.get('sub', [self.c1, self.c3]), None)
+
+    def test_get_type(self):
+        t = Transaction(self.a)
+        self.assertEquals(t.get_type(self.c1), -2)
+        self.assertEquals(t.get_type(self.c2), None)
+        self.assertEquals(t.get_type(self.c3), None)
+
+    def test_set(self):
+        t = Transaction(self.a)
+        t.set('dummy', [self.c2], self.c1)
+        self.assertEquals(t.get('dummy', [self.c2]), self.c1)
+
+    def test_set_type(self):
+        t = Transaction(self.a)
+        t.set_type(self.c2, int)
+        self.assertEquals(t.get('type', [self.c2]), XConstant(int))
+
+    def test_dep_set(self):
+        t = Transaction(self.a)
+        t.get('add', [self.c1, self.c3])
+        t.get_type(self.c1)
+        t.set('dummy', [self.c2], self.c1)
+        new_ann = Annotation('dummy', [self.c2], self.c1)
+        self.cases = []
+        for ann in self.a.enumerate():
+            if ann == Annotation('add', [self.c1, self.c3], self.c2):
+                self.cases.append(0)
+                self.assertEquals(ann.forward_deps, [new_ann])
+            elif ann == Annotation('type', [self.c1], self.c3):
+                self.cases.append(1)
+                self.assertEquals(ann.forward_deps, [new_ann])
+            else:
+                self.assertEquals(ann.forward_deps, [])
+        self.cases.sort()
+        self.assertEquals(self.cases, [0, 1])
+
+
 if __name__ == '__main__':
     test.main()

Added: pypy/trunk/src/pypy/translator/test/test_annotation.py
==============================================================================
--- (empty file)
+++ pypy/trunk/src/pypy/translator/test/test_annotation.py	Mon Nov 17 18:29:19 2003
@@ -0,0 +1,46 @@
+
+import autopath
+from pypy.tool import test
+
+from pypy.translator.annotation import XCell, XConstant, nothingyet, Annotation
+
+
+class TestAnnotation(test.IntTestCase):
+
+    def test_is_shared(self):
+        c1 = XCell()
+        c2 = XCell()
+        c3 = XCell()
+        c4 = XCell()
+        for a in (c1,c2,c3,c4):
+            for b in (c1,c2,c3,c4):
+                if a is not b:
+                    self.failIfEqual(a, b)
+        c1.share(c2)
+        c4.share(c2)
+        c1.share(c3)
+        for a in (c1,c2,c3,c4):
+            for b in (c1,c2,c3,c4):
+                self.assert_(a.is_shared(b))
+                self.assertEquals(a, b)
+
+    def test_constant(self):
+        self.assertEquals(XConstant(5), XConstant(5))
+        self.failIfEqual(XConstant(5), XConstant(6))
+        self.failIfEqual(XConstant(5), XCell())
+
+    def test_annotation(self):
+        c1 = XCell()
+        c2 = XCell()
+        c3 = XCell()
+        a1 = Annotation('hello', [c1], c2)
+        a2 = Annotation('hello', [c1], c3)
+
+        self.assertEquals(a1, a1)
+        self.failIfEqual (a1, a2)
+        c2.share(c3)
+        self.assertEquals(a1, a2)
+
+
+if __name__ == '__main__':
+    test.main()


More information about the Pypy-commit mailing list