[pypy-svn] r9235 - in pypy/dist/pypy: interpreter module/test objspace

ac at codespeak.net ac at codespeak.net
Tue Feb 15 16:06:34 CET 2005


Author: ac
Date: Tue Feb 15 16:06:34 2005
New Revision: 9235

Modified:
   pypy/dist/pypy/interpreter/baseobjspace.py
   pypy/dist/pypy/interpreter/executioncontext.py
   pypy/dist/pypy/module/test/test_builtin.py
   pypy/dist/pypy/objspace/descroperation.py
Log:
Implement python 2.3 semantics for comparing cyclic strucures.

All of this kludge can go away as soon as we move to tracking
python 2.4 behaviour.



Modified: pypy/dist/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/dist/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/dist/pypy/interpreter/baseobjspace.py	Tue Feb 15 16:06:34 2005
@@ -97,6 +97,11 @@
         return cache.getorbuild(key, builder, self) 
     loadfromcache._specialize_ = "location" 
 
+
+    def get_ec_state_dict(self):
+        "Return the 'state dict' from the active execution context."
+        return self.getexecutioncontext().get_state_dict()
+    
     def getexecutioncontext(self):
         "Return what we consider to be the active execution context."
         ec = getthreadlocals().executioncontext

Modified: pypy/dist/pypy/interpreter/executioncontext.py
==============================================================================
--- pypy/dist/pypy/interpreter/executioncontext.py	(original)
+++ pypy/dist/pypy/interpreter/executioncontext.py	Tue Feb 15 16:06:34 2005
@@ -9,7 +9,8 @@
         # Note that self.framestack only contains PyFrames
         self.space = space
         self.framestack = Stack()
-
+        self.stateDict = {}
+        
     def enter(self, frame):
         if self.framestack.depth() > self.space.recursion_limit:
             raise OperationError(self.space.w_RuntimeError,
@@ -54,3 +55,9 @@
             if frame.last_exception is not None:
                 return frame.last_exception
         return None
+
+    def get_state_dict(self):
+        """A mechanism to store arbitrary per ExecutionContext data.
+        Similar to cpython's PyThreadState_GetDict.
+        """
+        return self.stateDict

Modified: pypy/dist/pypy/module/test/test_builtin.py
==============================================================================
--- pypy/dist/pypy/module/test/test_builtin.py	(original)
+++ pypy/dist/pypy/module/test/test_builtin.py	Tue Feb 15 16:06:34 2005
@@ -251,6 +251,18 @@
         c2 = C()
         raises(RuntimeError, cmp, c1, c2)
 
+    def test_cmp_cyclic(self):
+        a = []; a.append(a)
+        b = []; b.append(b)
+        from UserList import UserList
+        c = UserList(); c.append(c)
+        assert cmp(a, b) == 0
+        assert cmp(b, c) == 0
+        assert cmp(c, a) == 0
+        assert cmp(a, c) == 0
+        # okay, now break the cycles
+        a.pop(); b.pop(); c.pop()
+        
     def test_coerce(self):
         assert coerce(1, 2)    == (1, 2)
         assert coerce(1L, 2L)  == (1L, 2L)

Modified: pypy/dist/pypy/objspace/descroperation.py
==============================================================================
--- pypy/dist/pypy/objspace/descroperation.py	(original)
+++ pypy/dist/pypy/objspace/descroperation.py	Tue Feb 15 16:06:34 2005
@@ -275,23 +275,64 @@
         if w_del is not None:
             space.get_and_call_function(w_del, w_obj)
 
-    def cmp(space, w_x, w_y):
-        # full compliant implementation of the built-in cmp().
-        if space.is_w(w_x, w_y):
-            return space.wrap(0)   # identical objects always compare equal.
-        if space.is_w(space.type(w_x), space.type(w_y)):
-            # for object of the same type, prefer __cmp__ over rich comparison.
-            w_cmp = space.lookup(w_x, '__cmp__')
-            w_res = _invoke_binop(space, w_cmp, w_x, w_y)
-            if w_res is not None:
-                return w_res
-        # fall back to rich comparison.
-        if space.eq_w(w_x, w_y):
+    _NESTING_LIMIT = 20
+
+    _compare_nesting = 0
+
+    def cmp(space, w_v, w_w):
+        # Icky implementation trying to mimic python 2.3 semantics.
+
+        if space.is_w(w_v, w_w):
             return space.wrap(0)
-        elif space.is_true(space.lt(w_x, w_y)):
-            return space.wrap(-1)
-        else:
-            return space.wrap(1)
+
+        w_vt = space.type(w_v)
+        token = None
+        _inprogress_dict = None
+        try:
+            # Try to do some magic to compare cyclic constructs.
+            space._compare_nesting += 1
+            if (space._compare_nesting > space._NESTING_LIMIT and
+                (space.lookup(w_v, '__getitem__') is not None) and
+                not (space.is_w(w_vt, space.w_str) or
+                     space.is_w(w_vt, space.w_tuple))):
+                try:
+                    iv = space.int_w(space.id(w_v))
+                    iw = space.int_w(space.id(w_w))
+                    if iv <= iw:
+                        t = (iv, iw, -1)
+                    else:
+                        t = (iw, iv, -1)
+                    _inprogress_dict = space.get_ec_state_dict().setdefault('cmp_state', {})
+                    if t in _inprogress_dict:
+                        # If we are allready trying to compare the arguments
+                        # presume they are equal
+                        return space.wrap(0)
+                    else:
+                        token = _inprogress_dict[t] = t
+                except:
+                    return space.wrap(-1)
+            try:
+                # The real comparison
+                if space.is_w(space.type(w_v), space.type(w_w)):
+                    # for object of the same type, prefer __cmp__ over rich comparison.
+                    w_cmp = space.lookup(w_v, '__cmp__')
+                    w_res = _invoke_binop(space, w_cmp, w_v, w_w)
+                    if w_res is not None:
+                        return w_res
+                # fall back to rich comparison.
+                if space.eq_w(w_v, w_w):
+                    return space.wrap(0)
+                elif space.is_true(space.lt(w_v, w_w)):
+                    return space.wrap(-1)
+                return space.wrap(1)
+            finally:
+                if token is not None:
+                    try:
+                        del _inprogress_dict[token]
+                    except:
+                        pass
+        finally:
+            space._compare_nesting -= 1
 
     def coerce(space, w_obj1, w_obj2):
         w_typ1 = space.type(w_obj1)
@@ -425,25 +466,60 @@
         w_first = w_obj1
         w_second = w_obj2
         
-        if space.is_true(space.is_(w_typ1, w_typ2)):
-            w_right_impl = None
-        else:
-            w_right_impl = space.lookup(w_obj2, right)
-            if space.is_true(space.issubtype(w_typ1, w_typ2)):
-                w_obj1, w_obj2 = w_obj2, w_obj1
-                w_left_impl, w_right_impl = w_right_impl, w_left_impl
-
-        w_res = _invoke_binop(space, w_left_impl, w_obj1, w_obj2)
-        if w_res is not None:
-            return w_res
-        w_res = _invoke_binop(space, w_right_impl, w_obj2, w_obj1)
-        if w_res is not None:
-            return w_res
-        # fallback: lt(a, b) <= lt(cmp(a, b), 0) ...
-        w_res = _cmp(space, w_first, w_second)
-        res = space.int_w(w_res)
-        return space.wrap(op(res, 0))
+        token = None
+        _inprogress_dict = None
+        try:
+            # Try to do some magic to compare cyclic constructs.
+            space._compare_nesting += 1
+            if (space._compare_nesting > space._NESTING_LIMIT and
+                (space.lookup(w_obj1, '__getitem__') is not None) and
+                not (space.is_w(w_typ1, space.w_str) or
+                     space.is_w(w_typ1, space.w_tuple))):
+                i1 = space.int_w(space.id(w_obj1))
+                i2 = space.int_w(space.id(w_obj2))
+                if i1 <= i2:
+                    t = (i1, i2, left)
+                else:
+                    t = (i2, i1, right)
+                _inprogress_dict = space.get_ec_state_dict().setdefault('cmp_state', {})
+                if t in _inprogress_dict:
+                    # If we are allready trying to compare the arguments
+                    # presume they are equal
+                    if symbol == '==':
+                        return space.w_True
+                    elif symbol == '!=':
+                        return space.w_False
+                    else:
+                        raise OperationError(space.w_ValueError,
+                                             space.wrap("can't order recursive values"))
+                else:
+                    token = _inprogress_dict[t] = t
+
+            if space.is_true(space.is_(w_typ1, w_typ2)):
+                w_right_impl = None
+            else:
+                w_right_impl = space.lookup(w_obj2, right)
+                if space.is_true(space.issubtype(w_typ1, w_typ2)):
+                    w_obj1, w_obj2 = w_obj2, w_obj1
+                    w_left_impl, w_right_impl = w_right_impl, w_left_impl
 
+            w_res = _invoke_binop(space, w_left_impl, w_obj1, w_obj2)
+            if w_res is not None:
+                return w_res
+            w_res = _invoke_binop(space, w_right_impl, w_obj2, w_obj1)
+            if w_res is not None:
+                return w_res
+            # fallback: lt(a, b) <= lt(cmp(a, b), 0) ...
+            w_res = _cmp(space, w_first, w_second)
+            res = space.int_w(w_res)
+            return space.wrap(op(res, 0))
+        finally:
+            if token is not None:
+                try:
+                    del _inprogress_dict[token]
+                except:
+                    pass
+                
     return func_with_new_name(comparison_impl, 'comparison_%s_impl'%left.strip('_'))
 
 



More information about the Pypy-commit mailing list