From: Samuele P. <ped...@us...> - 2004-09-07 15:16:34
|
Update of /cvsroot/jython/jython/org/python/core In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14783/org/python/core Modified Files: Tag: newstyle-branch PyFloat.java PyInteger.java PyDictionary.java PyInstance.java PyObject.java __builtin__.java PyLong.java PyComplex.java Log Message: rework coercion and compare interaction: (see also discussion of patch http://sourceforge.net/tracker/index.php?func=detail&aid=859555&group_id=12867&atid=312867) Moved coercion logic inside numeric comparsions, rich comparison for complex number so non-equality compares fail as expected. Dictionary grows richcomp using __eq__ and __ne__ (to deal correctly with complex numbers and other types only with equality). PyInstance compare more simalr to CPython. The global behavior should be more CPython like up to corner cases (because of legacy __cmp__ vs. rich comparisons, legacy coercion etc comapirisons are still a messy underspecified aspect of Python) Reverted to use ids for the default comparison code but avoid to compute them for equality/inequality cases. test_compare and test_richcmp now pass. Index: PyFloat.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyFloat.java,v retrieving revision 2.12.2.1 retrieving revision 2.12.2.2 diff -C2 -d -r2.12.2.1 -r2.12.2.2 *** PyFloat.java 26 Jan 2004 02:18:39 -0000 2.12.2.1 --- PyFloat.java 7 Sep 2004 15:16:11 -0000 2.12.2.2 *************** *** 79,83 **** public int __cmp__(PyObject other) { ! double v = ((PyFloat)other).value; return value < v ? -1 : value > v ? 1 : 0; } --- 79,85 ---- public int __cmp__(PyObject other) { ! if (!canCoerce(other)) ! return -2; ! double v = coerce(other); return value < v ? -1 : value > v ? 1 : 0; } Index: PyInteger.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyInteger.java,v retrieving revision 2.19.2.1 retrieving revision 2.19.2.2 diff -C2 -d -r2.19.2.1 -r2.19.2.2 *** PyInteger.java 26 Jan 2004 02:18:39 -0000 2.19.2.1 --- PyInteger.java 7 Sep 2004 15:16:11 -0000 2.19.2.2 *************** *** 70,74 **** public int __cmp__(PyObject other) { ! int v = ((PyInteger)other).value; return value < v ? -1 : value > v ? 1 : 0; } --- 70,76 ---- public int __cmp__(PyObject other) { ! if (!canCoerce(other)) ! return -2; ! int v = coerce(other); return value < v ? -1 : value > v ? 1 : 0; } Index: PyDictionary.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyDictionary.java,v retrieving revision 2.21.2.1 retrieving revision 2.21.2.2 diff -C2 -d -r2.21.2.1 -r2.21.2.2 *** PyDictionary.java 26 Jan 2004 02:18:39 -0000 2.21.2.1 --- PyDictionary.java 7 Sep 2004 15:16:11 -0000 2.21.2.2 *************** *** 221,224 **** --- 221,253 ---- } + public PyObject __eq__(PyObject ob_other) { + if (ob_other.getType() != getType()) + return null; + + PyDictionary other = (PyDictionary)ob_other; + int an = table.size(); + int bn = other.table.size(); + if (an != bn) + return Py.Zero; + + PyList akeys = keys(); + for (int i=0; i<an; i++) { + PyObject akey = akeys.get(i); + PyObject bvalue = other.__finditem__(akey); + if (bvalue == null) + return Py.Zero; + PyObject avalue = __finditem__(akey); + if (!avalue._eq(bvalue).__nonzero__()) + return Py.Zero; + } + return Py.One; + } + + public PyObject __ne__(PyObject ob_other) { + PyObject eq_result = __eq__(ob_other); + if (eq_result == null) return null; + return eq_result == Py.One?Py.Zero:Py.One; + } + public int __cmp__(PyObject ob_other) { if (ob_other.getType() != getType()) Index: PyInstance.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyInstance.java,v retrieving revision 2.33.2.2 retrieving revision 2.33.2.3 diff -C2 -d -r2.33.2.2 -r2.33.2.3 *** PyInstance.java 17 Feb 2004 14:33:02 -0000 2.33.2.2 --- PyInstance.java 7 Sep 2004 15:16:11 -0000 2.33.2.3 *************** *** 431,443 **** } ! public int __cmp__(PyObject o) { ! PyObject ret = invoke_ex("__cmp__", o); ! if (ret == null) ! return -2; ! if (ret instanceof PyInteger) { ! int v = ((PyInteger)ret).getValue(); ! return v < 0 ? -1 : v > 0 ? 1 : 0; } ! throw Py.TypeError("__cmp__() must return int"); } --- 431,472 ---- } ! // special case: does all the work ! public int __cmp__(PyObject other) { ! PyObject[] coerced = this._coerce(other); ! PyObject v; ! PyObject w; ! PyObject ret = null; ! if (coerced != null) { ! v = coerced[0]; ! w = coerced[1]; ! if (!(v instanceof PyInstance) && ! !(w instanceof PyInstance)) ! return v._cmp(w); ! } else { ! v = this; ! w = other; } ! if (v instanceof PyInstance) { ! ret = ((PyInstance)v).invoke_ex("__cmp__",w); ! if (ret != null) { ! if (ret instanceof PyInteger) { ! int result = ((PyInteger)ret).getValue(); ! return result < 0 ? -1 : result > 0 ? 1 : 0; ! } ! throw Py.TypeError("__cmp__() must return int"); ! } ! } ! if (w instanceof PyInstance) { ! ret = ((PyInstance)w).invoke_ex("__cmp__",v); ! if (ret != null) { ! if (ret instanceof PyInteger) { ! int result = ((PyInteger)ret).getValue(); ! return -(result < 0 ? -1 : result > 0 ? 1 : 0); ! } ! throw Py.TypeError("__cmp__() must return int"); ! } ! ! } ! return -2; } Index: PyObject.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyObject.java,v retrieving revision 2.30.2.2 retrieving revision 2.30.2.3 diff -C2 -d -r2.30.2.2 -r2.30.2.3 *** PyObject.java 17 Feb 2004 14:33:02 -0000 2.30.2.2 --- PyObject.java 7 Sep 2004 15:16:11 -0000 2.30.2.3 *************** *** 910,913 **** --- 910,944 ---- /** + * Implements coerce(this,other), result as PyObject[] + * @param oher + * @return PyObject[] + */ + PyObject[] _coerce(PyObject other) { + Object result; + if (this.getType() == other.getType() && + !(this instanceof PyInstance)) { + return new PyObject[] {this, other}; + } + result = this.__coerce_ex__(other); + if (result != null && result != Py.None) { + if (result instanceof PyObject[]) { + return (PyObject[])result; + } else { + return new PyObject[] {this, (PyObject)result}; + } + } + result = other.__coerce_ex__(this); + if (result != null && result != Py.None) { + if (result instanceof PyObject[]) { + return (PyObject[])result; + } else { + return new PyObject[] {(PyObject)result, other}; + } + } + return null; + + } + + /** * Equivalent to the standard Python __coerce__ method. * *************** *** 932,935 **** --- 963,968 ---- } + + /* The basic comparision operations */ *************** *** 1056,1124 **** } ! private final int _cmp_unsafe(PyObject o2_in) { ! // Shortcut for equal objects ! if (this == o2_in) return 0; ! PyObject o2 = o2_in; ! PyObject o1 = this; ! int itmp; ! Object ctmp; ! if (o1.getType() != o2.getType()) { ! ctmp = o1.__coerce_ex__(o2); ! if (ctmp != null) { ! if (ctmp instanceof PyObject[]) { ! o1 = ((PyObject[]) ctmp)[0]; ! o2 = ((PyObject[]) ctmp)[1]; ! } else { ! o2 = (PyObject) ctmp; ! } ! } ! } else ! ctmp = null; ! if (ctmp != Py.None && (itmp = o1.__cmp__(o2)) != -2) ! return itmp; ! o1 = this; ! o2 = o2_in; ! if (o1.getType() != o2.getType()) { ! ctmp = o2.__coerce_ex__(o1); ! if (ctmp != null) { ! if (ctmp instanceof PyObject[]) { ! o2 = ((PyObject[]) ctmp)[0]; ! o1 = ((PyObject[]) ctmp)[1]; ! } else { ! o1 = (PyObject) ctmp; ! } ! } } - if (ctmp != Py.None && (itmp = o2.__cmp__(o1)) != -2) - return -itmp; ! if (this == o2_in) return 0; ! /* None is smaller than anything */ ! if (this == Py.None) ! return -1; ! if (o2_in == Py.None) ! return 1; ! // No rational way to compare these, so ask their classes to compare ! itmp = this.getType().__cmp__(o2_in.getType()); ! if (itmp == 0) ! return System.identityHashCode(this) ! < System.identityHashCode(o2_in) ! ? -1 ! : 1; ! if (itmp != -2) ! return itmp; ! return System.identityHashCode(this.getType()) ! < System.identityHashCode(o2_in.getType()) ! ? -1 ! : 1; } private final static PyObject check_recursion( ThreadState ts, --- 1089,1159 ---- } ! private final int _default_cmp(PyObject other) { ! int result; ! if (this._is(other).__nonzero__()) return 0; + + /* None is smaller than anything */ + if (this == Py.None) + return -1; + if (other == Py.None) + return 1; ! // No rational way to compare these, so ask their classes to compare ! PyType this_type = this.getType(); ! PyType other_type = other.getType(); ! if (this_type == other_type) { ! return Py.id(this) < Py.id(other)? -1: 1; ! } ! result = this_type.fastGetName().compareTo(other_type.fastGetName()); ! if (result == 0) ! return Py.id(this_type)<Py.id(other_type)? -1: 1; ! return result < 0? -1: 1; ! } ! private final int _cmp_unsafe(PyObject other) { ! // Shortcut for equal objects ! if (this == other) ! return 0; ! ! int result; ! result = this.__cmp__(other); ! if (result != -2) ! return result; ! ! if (!(this instanceof PyInstance)) { ! result = other.__cmp__(this); ! if (result != -2) ! return -result; } ! return this._default_cmp(other); ! } ! ! /* ! * Like _cmp_unsafe but limited to ==/!= as 0/!=0, ! * avoids to invoke Py.id ! */ ! private final int _cmpeq_unsafe(PyObject other) { ! // Shortcut for equal objects ! if (this == other) return 0; ! int result; ! result = this.__cmp__(other); ! if (result != -2) ! return result; ! if (!(this instanceof PyInstance)) { ! result = other.__cmp__(this); ! if (result != -2) ! return -result; ! } ! return this._is(other).__nonzero__()?0:1; } + + private final static PyObject check_recursion( ThreadState ts, *************** *** 1165,1169 **** if (res != null) return res; ! return _cmp_unsafe(o) == 0 ? Py.One : Py.Zero; } finally { delete_token(ts, token); --- 1200,1204 ---- if (res != null) return res; ! return _cmpeq_unsafe(o) == 0 ? Py.One : Py.Zero; } finally { delete_token(ts, token); *************** *** 1193,1197 **** if (res != null) return res; ! return _cmp_unsafe(o) != 0 ? Py.One : Py.Zero; } finally { delete_token(ts, token); --- 1228,1232 ---- if (res != null) return res; ! return _cmpeq_unsafe(o) != 0 ? Py.One : Py.Zero; } finally { delete_token(ts, token); Index: __builtin__.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/__builtin__.java,v retrieving revision 2.57.2.2 retrieving revision 2.57.2.3 diff -C2 -d -r2.57.2.2 -r2.57.2.3 *** __builtin__.java 17 Feb 2004 14:33:02 -0000 2.57.2.2 --- __builtin__.java 7 Sep 2004 15:16:11 -0000 2.57.2.3 *************** *** 2,6 **** package org.python.core; - import org.python.parser.SimpleNode; import java.util.Hashtable; import java.math.BigInteger; --- 2,5 ---- *************** *** 198,222 **** public static PyTuple coerce(PyObject o1, PyObject o2) { ! Object ctmp; ! PyTuple ret; ! if (o1.getType() == o2.getType()) { ! return new PyTuple(new PyObject[] {o1, o2}); ! } ! ctmp = o1.__coerce_ex__(o2); ! if (ctmp != null && ctmp != Py.None) { ! if (ctmp instanceof PyObject[]) { ! return new PyTuple((PyObject[])ctmp); ! } else { ! return new PyTuple(new PyObject[] {o1, (PyObject)ctmp}); ! } ! } ! ctmp = o2.__coerce_ex__(o1); ! if (ctmp != null && ctmp != Py.None) { ! if (ctmp instanceof PyObject[]) { ! return new PyTuple((PyObject[])ctmp); ! } else { ! return new PyTuple(new PyObject[] {(PyObject)ctmp, o2}); ! } ! } throw Py.TypeError("number coercion failed"); } --- 197,203 ---- public static PyTuple coerce(PyObject o1, PyObject o2) { ! PyObject[] result = o1._coerce(o2); ! if (result != null) ! return new PyTuple(result); throw Py.TypeError("number coercion failed"); } *************** *** 676,705 **** PyObject x = objs[0]; PyObject y = objs[1]; ! if (x.getType() == y.getType()) return true; - Object ctmp = x.__coerce_ex__(y); - if (ctmp != null && ctmp != Py.None) { - if (ctmp instanceof PyObject[]) { - x = ((PyObject[])ctmp)[0]; - y = ((PyObject[])ctmp)[1]; - } else { - y = (PyObject)ctmp; - } } ! objs[0] = x; objs[1] = y; ! if (x.getType() == y.getType()) return true; - ctmp = y.__coerce_ex__(x); - if (ctmp != null && ctmp != Py.None) { - if (ctmp instanceof PyObject[]) { - y = ((PyObject[])ctmp)[0]; - x = ((PyObject[])ctmp)[1]; - } else { - x = (PyObject)ctmp; - } } ! objs[0] = x; objs[1] = y; ! //System.out.println(""+x.__class__+" : "+y.__class__); ! return x.getType() == y.getType(); } --- 657,674 ---- PyObject x = objs[0]; PyObject y = objs[1]; ! PyObject[] result; ! result = x._coerce(y); ! if (result != null) { ! objs[0] = result[0]; ! objs[1] = result[1]; return true; } ! result = y._coerce(x); ! if (result != null) { ! objs[0] = result[1]; ! objs[1] = result[0]; return true; } ! return false; } Index: PyLong.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyLong.java,v retrieving revision 2.18.2.1 retrieving revision 2.18.2.2 diff -C2 -d -r2.18.2.1 -r2.18.2.2 *** PyLong.java 26 Jan 2004 02:18:39 -0000 2.18.2.1 --- PyLong.java 7 Sep 2004 15:16:11 -0000 2.18.2.2 *************** *** 137,141 **** public int __cmp__(PyObject other) { ! return value.compareTo(((PyLong)other).value); } --- 137,143 ---- public int __cmp__(PyObject other) { ! if (!canCoerce(other)) ! return -2; ! return value.compareTo(coerce(other)); } Index: PyComplex.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyComplex.java,v retrieving revision 2.10.2.1 retrieving revision 2.10.2.2 diff -C2 -d -r2.10.2.1 -r2.10.2.2 *** PyComplex.java 26 Jan 2004 02:18:39 -0000 2.10.2.1 --- PyComplex.java 7 Sep 2004 15:16:11 -0000 2.10.2.2 *************** *** 68,73 **** public int __cmp__(PyObject other) { ! double oreal = ((PyComplex)other).real; ! double oimag = ((PyComplex)other).imag; if (real == oreal && imag == oimag) return 0; --- 68,76 ---- public int __cmp__(PyObject other) { ! if (!canCoerce(other)) ! return -2; ! PyComplex c = coerce(other); ! double oreal = c.real; ! double oimag = c.imag; if (real == oreal && imag == oimag) return 0; *************** *** 79,82 **** --- 82,128 ---- } + /* + * @see org.python.core.PyObject#__eq__(org.python.core.PyObject) + */ + public PyObject __eq__(PyObject other) { + if (!canCoerce(other)) + return null; + PyComplex c = coerce(other); + return Py.newBoolean(real == c.real && imag == c.imag); + } + + /* + * @see org.python.core.PyObject#__ne__(org.python.core.PyObject) + */ + public PyObject __ne__(PyObject other) { + if (!canCoerce(other)) + return null; + PyComplex c = coerce(other); + return Py.newBoolean(real != c.real || imag != c.imag); + } + + private PyObject unsupported_comparison(PyObject other) { + if (!canCoerce(other)) + return null; + throw Py.TypeError("cannot compare complex numbers using <, <=, >, >="); + } + + public PyObject __ge__(PyObject other) { + return unsupported_comparison(other); + } + + public PyObject __gt__(PyObject other) { + return unsupported_comparison(other); + } + + public PyObject __le__(PyObject other) { + return unsupported_comparison(other); + } + + public PyObject __lt__(PyObject other) { + return unsupported_comparison(other); + } + + public Object __coerce_ex__(PyObject other) { if (other instanceof PyComplex) *************** *** 377,379 **** --- 423,427 ---- public boolean isSequenceType() { return false; } + + } |