From: <pj...@us...> - 2008-07-28 06:38:48
|
Revision: 5007 http://jython.svn.sourceforge.net/jython/?rev=5007&view=rev Author: pjenvey Date: 2008-07-28 06:38:44 +0000 (Mon, 28 Jul 2008) Log Message: ----------- PEP 357 (__index__), adds: o PyObject.isIndex - true if int, long or implements __index__ o PyObject.asIndex - like asInt for indexes o also fixed a dispatching to __get/set/delitem__ vs __get/set/delslice__ bug and __get/set/delitem__ indices weren't utilizing __len__ when available (fixes test_userstring) Modified Paths: -------------- branches/asm/src/org/python/core/PyArray.java branches/asm/src/org/python/core/PyInstance.java branches/asm/src/org/python/core/PyInteger.java branches/asm/src/org/python/core/PyList.java branches/asm/src/org/python/core/PyLong.java branches/asm/src/org/python/core/PyObject.java branches/asm/src/org/python/core/PySequence.java branches/asm/src/org/python/core/PySlice.java branches/asm/src/org/python/core/PyString.java branches/asm/src/org/python/core/PyTuple.java branches/asm/src/org/python/modules/collections/PyDeque.java branches/asm/src/org/python/modules/operator.java branches/asm/src/templates/object.derived Modified: branches/asm/src/org/python/core/PyArray.java =================================================================== --- branches/asm/src/org/python/core/PyArray.java 2008-07-28 04:56:03 UTC (rev 5006) +++ branches/asm/src/org/python/core/PyArray.java 2008-07-28 06:38:44 UTC (rev 5007) @@ -252,11 +252,11 @@ @ExposedMethod(type = MethodType.BINARY) final PyObject array___imul__(PyObject o) { - if(!(o instanceof PyInteger || o instanceof PyLong)) { + if (!o.isIndex()) { return null; } if (delegate.getSize() > 0) { - int count = o.asInt(); + int count = o.asIndex(Py.OverflowError); if (count <= 0) { delegate.clear(); return this; @@ -276,10 +276,10 @@ @ExposedMethod(type = MethodType.BINARY) final PyObject array___mul__(PyObject o) { - if(!(o instanceof PyInteger || o instanceof PyLong)) { + if (!o.isIndex()) { return null; } - return repeat(o.asInt()); + return repeat(o.asIndex(Py.OverflowError)); } public PyObject __rmul__(PyObject o) { @@ -288,10 +288,10 @@ @ExposedMethod(type = MethodType.BINARY) final PyObject array___rmul__(PyObject o) { - if(!(o instanceof PyInteger || o instanceof PyLong)) { + if (!o.isIndex()) { return null; } - return repeat(o.asInt()); + return repeat(o.asIndex(Py.OverflowError)); } public PyObject __iadd__(PyObject other) { Modified: branches/asm/src/org/python/core/PyInstance.java =================================================================== --- branches/asm/src/org/python/core/PyInstance.java 2008-07-28 04:56:03 UTC (rev 5006) +++ branches/asm/src/org/python/core/PyInstance.java 2008-07-28 06:38:44 UTC (rev 5007) @@ -246,6 +246,11 @@ return __findattr__("__call__") != null; } + @Override + public boolean isIndex() { + return __findattr__("__index__") != null; + } + public PyObject invoke(String name) { PyObject f = ifindlocal(name); if (f == null) { @@ -582,34 +587,20 @@ return __finditem__(new PyInteger(key)); } - private PyObject trySlice(PyObject key, String name, PyObject extraArg) { - if (!(key instanceof PySlice)) - return null; + private PyObject trySlice(String name, PyObject start, PyObject stop) { + return trySlice(name, start, stop, null); + } - PySlice slice = (PySlice)key; - - if (slice.getStep() != Py.None && slice.getStep() != Py.One) { - if (slice.getStep() instanceof PyInteger) { - if (((PyInteger)slice.getStep()).getValue() != 1) { - return null; - } - } else { - return null; - } - } - + private PyObject trySlice(String name, PyObject start, PyObject stop, PyObject extraArg) { PyObject func = __findattr__(name); - if (func == null) + if (func == null) { return null; + } - PyObject start = slice.start; - PyObject stop = slice.stop; + PyObject[] indices = PySlice.indices2(this, start, stop); + start = indices[0]; + stop = indices[1]; - if (start == Py.None) - start = Py.Zero; - if (stop == Py.None) - stop = new PyInteger(PySystemState.maxint); - if (extraArg == null) { return func.__call__(start, stop); } else { @@ -624,10 +615,6 @@ } try { - PyObject ret = trySlice(key, "__getslice__", null); - if (ret != null) - return ret; - return invoke("__getitem__", key); } catch (PyException e) { if (Py.matchException(e, Py.IndexError)) @@ -647,11 +634,6 @@ } return ret; } - - PyObject ret = trySlice(key, "__getslice__", null); - if (ret != null) - return ret; - return invoke("__getitem__", key); } @@ -661,9 +643,6 @@ proxy.__setitem__(key, value); return; } - if (trySlice(key, "__setslice__", value) != null) - return; - invoke("__setitem__", key, value); } @@ -673,11 +652,36 @@ proxy.__delitem__(key); return; } - if (trySlice(key, "__delslice__", null) != null) - return; invoke("__delitem__", key); } + public PyObject __getslice__(PyObject start, PyObject stop, PyObject step) { + if (step != null) { + return __getitem__(new PySlice(start, stop, step)); + } + PyObject ret = trySlice("__getslice__", start, stop); + if (ret != null) { + return ret; + } + return super.__getslice__(start, stop, step); + } + + public void __setslice__(PyObject start, PyObject stop, PyObject step, PyObject value) { + if (step != null) { + __setitem__(new PySlice(start, stop, step), value); + } else if (trySlice("__setslice__", start, stop, value) == null) { + super.__setslice__(start, stop, step, value); + } + } + + public void __delslice__(PyObject start, PyObject stop, PyObject step) { + if (step != null) { + __delitem__(new PySlice(start, stop, step)); + } else if (trySlice("__delslice__", start, stop) == null) { + super.__delslice__(start, stop, step); + } + } + public PyObject __iter__() { PyObject iter = getCollectionIter(); if (iter != null) { @@ -858,6 +862,27 @@ return invoke("__invert__"); } + /** + * Implements the __index__ method by looking it up + * in the instance's dictionary and calling it if it is found. + **/ + public PyObject __index__() { + PyObject ret; + try { + ret = invoke("__index__"); + } catch (PyException pye) { + if (!Py.matchException(pye, Py.AttributeError)) { + throw pye; + } + throw Py.TypeError("object cannot be interpreted as an index"); + } + if (ret instanceof PyInteger || ret instanceof PyLong) { + return ret; + } + throw Py.TypeError(String.format("__index__ returned non-(int,long) (type %s)", + ret.getType().fastGetName())); + } + // Binary ops /** Modified: branches/asm/src/org/python/core/PyInteger.java =================================================================== --- branches/asm/src/org/python/core/PyInteger.java 2008-07-28 04:56:03 UTC (rev 5006) +++ branches/asm/src/org/python/core/PyInteger.java 2008-07-28 06:38:44 UTC (rev 5007) @@ -805,6 +805,26 @@ return int___getnewargs__(); } + @Override + public PyObject __index__() { + return int___index__(); + } + + @ExposedMethod + final PyObject int___index__() { + return this; + } + + @Override + public boolean isIndex() { + return true; + } + + @Override + public int asIndex(PyObject err) { + return getValue(); + } + public boolean isMappingType() { return false; } public boolean isSequenceType() { return false; } Modified: branches/asm/src/org/python/core/PyList.java =================================================================== --- branches/asm/src/org/python/core/PyList.java 2008-07-28 04:56:03 UTC (rev 5006) +++ branches/asm/src/org/python/core/PyList.java 2008-07-28 06:38:44 UTC (rev 5007) @@ -267,11 +267,12 @@ @ExposedMethod(type = MethodType.BINARY) final PyObject list___imul__(PyObject o) { - if(!(o instanceof PyInteger || o instanceof PyLong)) { + if (!o.isIndex()) { return null; } + int count = o.asIndex(Py.OverflowError); int l = size(); - int count = ((PyInteger)o.__int__()).getValue(); + int newSize = l * count; list.setSize(newSize); PyObject[] array = getArray(); @@ -282,22 +283,30 @@ return this; } + @Override + public PyObject __mul__(PyObject o) { + return list___mul__(o); + } + @ExposedMethod(type = MethodType.BINARY) final PyObject list___mul__(PyObject o) { - if(!(o instanceof PyInteger || o instanceof PyLong)) { + if (!o.isIndex()) { return null; } - int count = ((PyInteger)o.__int__()).getValue(); - return repeat(count); + return repeat(o.asIndex(Py.OverflowError)); } + @Override + public PyObject __rmul__(PyObject o) { + return list___rmul__(o); + } + @ExposedMethod(type = MethodType.BINARY) final PyObject list___rmul__(PyObject o) { - if(!(o instanceof PyInteger || o instanceof PyLong)) { + if (!o.isIndex()) { return null; } - int count = ((PyInteger)o.__int__()).getValue(); - return repeat(count); + return repeat(o.asIndex(Py.OverflowError)); } public PyObject __add__(PyObject o) { Modified: branches/asm/src/org/python/core/PyLong.java =================================================================== --- branches/asm/src/org/python/core/PyLong.java 2008-07-28 04:56:03 UTC (rev 5006) +++ branches/asm/src/org/python/core/PyLong.java 2008-07-28 06:38:44 UTC (rev 5007) @@ -836,7 +836,34 @@ return long___getnewargs__(); } + @Override + public PyObject __index__() { + return long___index__(); + } + @ExposedMethod + final PyObject long___index__() { + return this; + } + + @Override + public boolean isIndex() { + return true; + } + + @Override + public int asIndex(PyObject err) { + boolean tooLow = value.compareTo(PyInteger.minInt) < 0; + boolean tooHigh = value.compareTo(PyInteger.maxInt) > 0; + if (tooLow || tooHigh) { + if (err != null) { + throw new PyException(err, "cannot fit 'long' into an index-sized integer"); + } + return tooLow ? Integer.MIN_VALUE : Integer.MAX_VALUE; + } + return (int)value.longValue(); + } + public boolean isMappingType() { return false; } public boolean isSequenceType() { return false; } Modified: branches/asm/src/org/python/core/PyObject.java =================================================================== --- branches/asm/src/org/python/core/PyObject.java 2008-07-28 04:56:03 UTC (rev 5006) +++ branches/asm/src/org/python/core/PyObject.java 2008-07-28 06:38:44 UTC (rev 5007) @@ -418,6 +418,15 @@ return true; } + /** + * Determine if this object can act as an index (implements __index__). + * + * @return true if the object can act as an index + */ + public boolean isIndex() { + return getType().lookup("__index__") != null; + } + /* The basic functions to implement a mapping */ /** @@ -1588,6 +1597,17 @@ public PyObject __invert__() { throw Py.AttributeError("__invert__"); } + + /** + * Equivalent to the standard Python __index__ method. + * + * @return a PyInteger or PyLong + * @throws a Py.TypeError if not supported + **/ + public PyObject __index__() { + throw Py.TypeError(String.format("'%.200s' object cannot be interpreted as an index", + getType().fastGetName())); + } /** * @param op the String form of the op (e.g. "+") @@ -3775,7 +3795,29 @@ public long asLong(int index) throws ConversionException { throw new ConversionException(index); } - + + /** + * Coerce this object into an index-sized integer. + * + * @return an index-sized int + */ + public int asIndex() { + return asIndex(null); + } + + /** + * Coerce this object into an index-sized integer. + * + * Throws a Python exception on Overflow if specified an exception type for err. + * + * @param err the Python exception to raise on OverflowErrors + * @return an index-sized int + */ + public int asIndex(PyObject err) { + // OverflowErrors are handled in PyLong.asIndex + return __index__().asInt(); + } + static { for (Class unbootstrapped : Py.BOOTSTRAP_TYPES) { Py.writeWarning("init", "Bootstrap type wasn't encountered in bootstrapping[class=" Modified: branches/asm/src/org/python/core/PySequence.java =================================================================== --- branches/asm/src/org/python/core/PySequence.java 2008-07-28 04:56:03 UTC (rev 5006) +++ branches/asm/src/org/python/core/PySequence.java 2008-07-28 06:38:44 UTC (rev 5007) @@ -288,11 +288,11 @@ } final PyObject seq___finditem__(PyObject index) { - if(index instanceof PyInteger || index instanceof PyLong) { - return seq___finditem__(index.asInt()); - } else if(index instanceof PySlice) { + if (index.isIndex()) { + return seq___finditem__(index.asIndex(Py.IndexError)); + } else if (index instanceof PySlice) { PySlice s = (PySlice)index; - return __getslice__(s.start, s.stop, s.step); + return seq___getslice__(s.start, s.stop, s.step); } else { throw Py.TypeError(getType().fastGetName() + " indices must be integers"); } @@ -360,6 +360,10 @@ } public synchronized void __setitem__(int index, PyObject value) { + seq___setitem__(index, value); + } + + final synchronized void seq___setitem__(int index, PyObject value) { int i = fixindex(index); if(i == -1) { throw Py.IndexError(getType().fastGetName() + " assignment index out of range"); @@ -372,11 +376,11 @@ } final void seq___setitem__(PyObject index, PyObject value) { - if(index instanceof PyInteger || index instanceof PyLong) { - __setitem__(index.asInt(), value); - } else if(index instanceof PySlice) { + if (index.isIndex()) { + seq___setitem__(index.asIndex(Py.IndexError), value); + } else if (index instanceof PySlice) { PySlice s = (PySlice)index; - __setslice__(s.start, s.stop, s.step, value); + seq___setslice__(s.start, s.stop, s.step, value); } else { throw Py.TypeError(getType().fastGetName() + " indices must be integers"); } @@ -387,15 +391,15 @@ } final synchronized void seq___delitem__(PyObject index) { - if(index instanceof PyInteger || index instanceof PyLong) { - int i = fixindex(index.asInt()); - if(i == -1) { + if (index.isIndex()) { + int i = fixindex(index.asIndex(Py.IndexError)); + if (i == -1) { throw Py.IndexError(getType().fastGetName() + " assignment index out of range"); } del(i); - } else if(index instanceof PySlice) { + } else if (index instanceof PySlice) { PySlice s = (PySlice)index; - __delslice__(s.start, s.stop, s.step); + seq___delslice__(s.start, s.stop, s.step); } else { throw Py.TypeError(getType().fastGetName() + " indices must be integers"); } Modified: branches/asm/src/org/python/core/PySlice.java =================================================================== --- branches/asm/src/org/python/core/PySlice.java 2008-07-28 04:56:03 UTC (rev 5006) +++ branches/asm/src/org/python/core/PySlice.java 2008-07-28 06:38:44 UTC (rev 5007) @@ -114,13 +114,7 @@ @ExposedMethod public PyObject slice_indices(PyObject len) { - int ilen; - try { - ilen = len.asInt(0); - } catch(ConversionException e) { - throw Py.TypeError("length must be an int"); - } - int[] slice = indices(ilen); + int[] slice = indices(len.asIndex(Py.OverflowError)); PyInteger[] pyInts = new PyInteger[slice.length]; for(int i = 0; i < pyInts.length; i++) { pyInts[i] = Py.newInteger(slice[i]); @@ -128,23 +122,11 @@ return new PyTuple(pyInts); } - private static int calculateSliceIndex(PyObject v) { - if(v instanceof PyInteger) { - return ((PyInteger)v).getValue(); - } else if(v instanceof PyLong) { - try { - return v.asInt(); - } catch (PyException exc) { - if (Py.matchException(exc, Py.OverflowError)) { - if (new PyLong(0L).__cmp__(v) < 0) { - return Integer.MAX_VALUE; - }else { - return 0; - } - } - } + public static int calculateSliceIndex(PyObject v) { + if (v.isIndex()) { + return v.asIndex(); } - throw Py.TypeError("slice indices must be integers or None"); + throw Py.TypeError("slice indices must be integers or None or have an __index__ method"); } /** @@ -195,6 +177,39 @@ } return slice; } + + /** + * Calculate indices for the deprecated __get/set/delslice__ methods. + * + * @param obj the object being sliced + * @param start the slice operation's start + * @param stop the slice operation's stop + * @return an array with start at index 0 and stop at index 1 + */ + public static PyObject[] indices2(PyObject obj, PyObject start, PyObject stop) { + PyObject[] indices = new PyObject[2]; + int istart = start == null ? 0 : calculateSliceIndex(start); + int istop = stop == null ? PySystemState.maxint : calculateSliceIndex(stop); + if (istart < 0 || istop < 0) { + try { + int len = obj.__len__(); + if (istart < 0) { + istart += len; + } + if (istop < 0) { + istop += len; + } + } catch (PyException pye) { + if (!Py.matchException(pye, Py.AttributeError)) { + throw pye; + } + } + } + indices[0] = Py.newInteger(istart); + indices[1] = Py.newInteger(istop); + return indices; + } + private static final int START = 0, STOP = 1, STEP = 2; @ExposedGet Modified: branches/asm/src/org/python/core/PyString.java =================================================================== --- branches/asm/src/org/python/core/PyString.java 2008-07-28 04:56:03 UTC (rev 5006) +++ branches/asm/src/org/python/core/PyString.java 2008-07-28 06:38:44 UTC (rev 5007) @@ -673,20 +673,30 @@ return createInstance(new String(new_chars), true); } + @Override + public PyObject __mul__(PyObject o) { + return str___mul__(o); + } + @ExposedMethod(type = MethodType.BINARY) final PyObject str___mul__(PyObject o) { - if (!(o instanceof PyInteger || o instanceof PyLong)) + if (!o.isIndex()) { return null; - int count = ((PyInteger)o.__int__()).getValue(); - return repeat(count); + } + return repeat(o.asIndex(Py.OverflowError)); } + @Override + public PyObject __rmul__(PyObject o) { + return str___rmul__(o); + } + @ExposedMethod(type = MethodType.BINARY) final PyObject str___rmul__(PyObject o) { - if (!(o instanceof PyInteger || o instanceof PyLong)) + if (!o.isIndex()) { return null; - int count = ((PyInteger)o.__int__()).getValue(); - return repeat(count); + } + return repeat(o.asIndex(Py.OverflowError)); } public PyObject __add__(PyObject generic_other) { Modified: branches/asm/src/org/python/core/PyTuple.java =================================================================== --- branches/asm/src/org/python/core/PyTuple.java 2008-07-28 04:56:03 UTC (rev 5006) +++ branches/asm/src/org/python/core/PyTuple.java 2008-07-28 06:38:44 UTC (rev 5007) @@ -175,20 +175,30 @@ return sum; } + @Override + public PyObject __mul__(PyObject o) { + return tuple___mul__(o); + } + @ExposedMethod(type = MethodType.BINARY) final PyObject tuple___mul__(PyObject o) { - if (!(o instanceof PyInteger || o instanceof PyLong)) + if (!o.isIndex()) { return null; - int count = ((PyInteger)o.__int__()).getValue(); - return repeat(count); + } + return repeat(o.asIndex(Py.OverflowError)); } + @Override + public PyObject __rmul__(PyObject o) { + return tuple___rmul__(o); + } + @ExposedMethod(type = MethodType.BINARY) final PyObject tuple___rmul__(PyObject o) { - if (!(o instanceof PyInteger || o instanceof PyLong)) + if (!o.isIndex()) { return null; - int count = ((PyInteger)o.__int__()).getValue(); - return repeat(count); + } + return repeat(o.asIndex(Py.OverflowError)); } public PyObject __iter__() { Modified: branches/asm/src/org/python/modules/collections/PyDeque.java =================================================================== --- branches/asm/src/org/python/modules/collections/PyDeque.java 2008-07-28 04:56:03 UTC (rev 5006) +++ branches/asm/src/org/python/modules/collections/PyDeque.java 2008-07-28 06:38:44 UTC (rev 5007) @@ -296,11 +296,11 @@ private Node getNode(PyObject index) { int pos = 0; - if (index instanceof PyInteger || index instanceof PyLong) { - pos = ((PyInteger)index.__int__()).getValue(); - } else { - throw Py.TypeError("an integer is required"); + if (!index.isIndex()) { + throw Py.TypeError(String.format("sequence index must be integer, not '%.200s'", + index.getType().fastGetName())); } + pos = index.asIndex(Py.IndexError); if (pos < 0) { pos += size; Modified: branches/asm/src/org/python/modules/operator.java =================================================================== --- branches/asm/src/org/python/modules/operator.java 2008-07-28 04:56:03 UTC (rev 5006) +++ branches/asm/src/org/python/modules/operator.java 2008-07-28 06:38:44 UTC (rev 5007) @@ -31,6 +31,7 @@ case 18: return Py.newBoolean(arg1.isNumberType()); case 19: return Py.newBoolean(arg1.isSequenceType()); case 32: return arg1.__invert__(); + case 52: return arg1.__index__(); default: throw info.unexpectedCall(1, false); } @@ -253,6 +254,8 @@ dict.__setitem__("itruediv", new OperatorFunctions("itruediv", 50, 2)); dict.__setitem__("__ixor__", new OperatorFunctions("__ixor__", 51, 2)); dict.__setitem__("ixor", new OperatorFunctions("ixor", 51, 2)); + dict.__setitem__("__index__", new OperatorFunctions("__ixor__", 52, 1)); + dict.__setitem__("index", new OperatorFunctions("ixor", 52, 1)); dict.__setitem__("attrgetter", PyAttrGetter.TYPE); dict.__setitem__("itemgetter", PyItemGetter.TYPE); Modified: branches/asm/src/templates/object.derived =================================================================== --- branches/asm/src/templates/object.derived 2008-07-28 04:56:03 UTC (rev 5006) +++ branches/asm/src/templates/object.derived 2008-07-28 06:38:44 UTC (rev 5007) @@ -240,32 +240,46 @@ } public PyObject __getslice__(PyObject start, PyObject stop, PyObject step) { // ??? - PyType self_type=getType(); - PyObject impl=self_type.lookup("__getslice__"); - if (impl!=null) { - return impl.__get__(this,self_type).__call__(start, stop); - } - return super.__getslice__(start, stop, step); + if (step != null) { + return __getitem__(new PySlice(start, stop, step)); + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getslice__"); + if (impl!=null) { + PyObject[] indices = PySlice.indices2(this, start, stop); + return impl.__get__(this,self_type).__call__(indices[0], indices[1]); + } + return super.__getslice__(start,stop,step); } public void __setslice__(PyObject start, PyObject stop, PyObject step, PyObject value) { - PyType self_type=getType(); - PyObject impl=self_type.lookup("__setslice__"); - if (impl!=null) { - impl.__get__(this,self_type).__call__(start, stop, value); - return; - } - super.__setslice__(start, stop, step, value); + if (step != null) { + __setitem__(new PySlice(start, stop, step), value); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setslice__"); + if (impl!=null) { + PyObject[] indices = PySlice.indices2(this, start, stop); + impl.__get__(this,self_type).__call__(indices[0], indices[1], value); + return; + } + super.__setslice__(start,stop,step,value); } public void __delslice__(PyObject start,PyObject stop,PyObject step) { - PyType self_type=getType(); - PyObject impl=self_type.lookup("__delslice__"); - if (impl!=null) { - impl.__get__(this,self_type).__call__(start, stop); - return; - } - super.__delslice__(start, stop, step); + if (step != null) { + __delitem__(new PySlice(start, stop, step)); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delslice__"); + if (impl!=null) { + PyObject[] indices = PySlice.indices2(this, start, stop); + impl.__get__(this,self_type).__call__(indices[0], indices[1]); + return; + } + super.__delslice__(start,stop,step); } public void __delitem__(PyObject key) { // ??? @@ -400,6 +414,20 @@ } } + public PyObject __index__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__index__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + if (res instanceof PyInteger || res instanceof PyLong) { + return res; + } + throw Py.TypeError(String.format("__index__ returned non-(int,long) (type %s)", + res.getType().fastGetName())); + } + return super.__index__(); + } + public Object __tojava__(Class c) { // If we are not being asked by the "default" conversion to java, then // we can provide this as the result, as long as it is a instance of the This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |