From: Finn B. <bc...@us...> - 2002-01-06 21:19:17
|
Update of /cvsroot/jython/jython/org/python/core In directory usw-pr-cvs1:/tmp/cvs-serv15999/core Modified Files: Py.java PyArray.java PyClass.java PyDictionary.java PyInstance.java PyObject.java PySequence.java PyString.java PyStringMap.java __builtin__.java codecs.java exceptions.java imp.java Added Files: PyCallIter.java PySequenceIter.java Log Message: Support for the __iter__ protocol. With this change, all loops over sequences will use the __iter__() method to get a iterator object and all builtin sequence objects will ofcourse define the __iter__() method. --- NEW FILE: PyCallIter.java --- package org.python.core; public class PyCallIter extends PyObject { private PyObject callable; private PyObject sentinel; private int idx; public PyCallIter(PyObject callable, PyObject sentinel) { this.callable = callable; this.sentinel = sentinel; } public PyObject __iter__() { return this; } public PyObject __iternext__() { PyObject val = null; try { val = callable.__call__(); } catch (PyException exc) { if (Py.matchException(exc, Py.StopIteration)) return null; throw exc; } if (val._eq(sentinel).__nonzero__()) return null; return val; } public PyObject next() { return __iternext__(); } // __class__ boilerplate -- see PyObject for details public static PyClass __class__; protected PyClass getPyClass() { return __class__; } } --- NEW FILE: PySequenceIter.java --- package org.python.core; public class PySequenceIter extends PyObject { private PyObject seq; private int idx; public PySequenceIter(PyObject seq) { this.seq = seq; this.idx = 0; } public PyObject __iter__() { return this; } public PyObject __iternext__() { return seq.__finditem__(idx++); } public PyObject next() { return __iternext__(); } // __class__ boilerplate -- see PyObject for details public static PyClass __class__; protected PyClass getPyClass() { return __class__; } } Index: Py.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/Py.java,v retrieving revision 2.63 retrieving revision 2.64 diff -C2 -d -r2.63 -r2.64 *** Py.java 2002/01/06 16:12:52 2.63 --- Py.java 2002/01/06 21:19:13 2.64 *************** *** 184,190 **** } ! public static PyObject StopIterator; ! public static PyException StopIterator(String message) { ! return new PyException(Py.StopIterator, message); } --- 184,190 ---- } ! public static PyObject StopIteration; ! public static PyException StopIteration(String message) { ! return new PyException(Py.StopIteration, message); } *************** *** 537,541 **** Exception = initExc("Exception", exc, dict); SystemExit = initExc("SystemExit", exc, dict); ! StopIterator = initExc("StopIterator", exc, dict); StandardError = initExc("StandardError", exc, dict); KeyboardInterrupt = initExc("KeyboardInterrupt", exc, dict); --- 537,541 ---- Exception = initExc("Exception", exc, dict); SystemExit = initExc("SystemExit", exc, dict); ! StopIteration = initExc("StopIteration", exc, dict); StandardError = initExc("StandardError", exc, dict); KeyboardInterrupt = initExc("KeyboardInterrupt", exc, dict); *************** *** 1628,1631 **** --- 1628,1641 ---- } return ret; + } + + public static PyObject iter(PyObject seq, String message) { + try { + return seq.__iter__(); + } catch (PyException exc) { + if (Py.matchException(exc, Py.TypeError)) + throw Py.TypeError(message); + throw exc; + } } Index: PyArray.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyArray.java,v retrieving revision 2.7 retrieving revision 2.8 diff -C2 -d -r2.7 -r2.8 *** PyArray.java 2001/10/28 17:13:43 2.7 --- PyArray.java 2002/01/06 21:19:13 2.8 *************** *** 33,39 **** public static PyArray array(PyObject seq, Class ctype) { PyArray array = new PyArray(ctype, seq.__len__()); ! PyObject o; ! for(int i=0; (o=seq.__finditem__(i)) != null; i++) { ! array.set(i, o); } return array; --- 33,40 ---- public static PyArray array(PyObject seq, Class ctype) { PyArray array = new PyArray(ctype, seq.__len__()); ! PyObject iter = seq.__iter__(); ! PyObject item = null; ! for (int i = 0; (item = iter.__iternext__()) != null; i++) { ! array.set(i, item); } return array; Index: PyClass.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyClass.java,v retrieving revision 2.28 retrieving revision 2.29 diff -C2 -d -r2.28 -r2.29 *** PyClass.java 2001/11/27 19:07:21 2.28 --- PyClass.java 2002/01/06 21:19:13 2.29 *************** *** 133,143 **** PyObject snames = superDict.__finditem__("__supernames__"); if (snames != null) { ! PyObject sname; ! int i; ! for (i = 0; (sname = snames.__finditem__(i)) != null; i++) { ! if (__dict__.__finditem__(sname) == null) { ! PyObject superFunc = superDict.__finditem__(sname); if (superFunc != null) ! __dict__.__setitem__(sname, superFunc); } } --- 133,142 ---- PyObject snames = superDict.__finditem__("__supernames__"); if (snames != null) { ! PyObject iter = snames.__iter__(); ! for (PyObject item; (item = iter.__iternext__()) != null; ) { ! if (__dict__.__finditem__(item) == null) { ! PyObject superFunc = superDict.__finditem__(item); if (superFunc != null) ! __dict__.__setitem__(item, superFunc); } } Index: PyDictionary.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyDictionary.java,v retrieving revision 2.17 retrieving revision 2.18 diff -C2 -d -r2.17 -r2.18 *** PyDictionary.java 2001/10/28 17:13:43 2.17 --- PyDictionary.java 2002/01/06 21:19:13 2.18 *************** *** 3,6 **** --- 3,7 ---- import java.util.Hashtable; + import java.util.Enumeration; *************** *** 192,195 **** --- 193,200 ---- } + public PyObject __iter__() { + return new PyDictionaryIter(this, table.keys()); + } + public String toString() { ThreadState ts = Py.getThreadState(); *************** *** 317,322 **** public void update(PyStringMap d) { PyObject keys = d.keys(); ! PyObject key; ! for (int i = 0; (key = keys.__finditem__(i)) != null; i++) __setitem__(key, d.__getitem__(key)); } --- 322,327 ---- public void update(PyStringMap d) { PyObject keys = d.keys(); ! PyObject iter = keys.__iter__(); ! for (PyObject key; (key = iter.__iternext__()) != null; ) __setitem__(key, d.__getitem__(key)); } *************** *** 408,409 **** --- 413,429 ---- } } + + class PyDictionaryIter extends PyObject { + private Enumeration enumeration; + + public PyDictionaryIter(PyObject dict, Enumeration e) { + enumeration = e; + } + + public PyObject __iternext__() { + if (!enumeration.hasMoreElements()) + return null; + return (PyObject) enumeration.nextElement(); + } + } + Index: PyInstance.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyInstance.java,v retrieving revision 2.28 retrieving revision 2.29 diff -C2 -d -r2.28 -r2.29 *** PyInstance.java 2001/12/16 13:04:02 2.28 --- PyInstance.java 2002/01/06 21:19:13 2.29 *************** *** 601,604 **** --- 601,628 ---- } + public PyObject __iter__() { + PyObject func = __findattr__("__iter__"); + if (func != null) + return func.__call__(); + func = __findattr__("__getitem__"); + if (func == null) + return super.__iter__(); + return new PySequenceIter(this); + } + + public PyObject __iternext__() { + PyObject func = __findattr__("next"); + if (func != null) { + try { + return func.__call__(); + } catch (PyException exc) { + if (Py.matchException(exc, Py.StopIteration)) + return null; + throw exc; + } + } + throw Py.TypeError("instance has no next() method"); + } + public boolean __contains__(PyObject o) { PyObject func = __findattr__("__contains__"); Index: PyObject.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyObject.java,v retrieving revision 2.26 retrieving revision 2.27 diff -C2 -d -r2.26 -r2.27 *** PyObject.java 2001/10/28 17:13:43 2.26 --- PyObject.java 2002/01/06 21:19:13 2.27 *************** *** 602,606 **** --- 602,648 ---- } + /*The basic functions to implement an iterator */ + + + /** + * Return an iterator that is used to iterate the element of this + * sequence. + * From version 2.2, this method is the primary protocol for looping + * over sequences. + * <p> + * If a PyObject subclass should support iteration based in the + * __finditem__() method, it must supply an implementation of __iter__() + * like this: + * <pre> + * public PyObject __iter__() { + * return new PySequenceIter(this); + * } + * </pre> + * + * When iterating over a python sequence from java code, it should be + * done with code like this: + * <pre> + * PyObject iter = seq.__iter__(); + * for (PyObject item; (item = iter.__next__()) != null; { + * // Do somting with item + * } + * </pre> + * + * @since 2.2 + */ + public PyObject __iter__() { + throw Py.TypeError("iteration over non-sequence"); + } + /** + * Return the next element of the sequence that this is an iterator + * for. Returns null when the end of the sequence is reached. + * + * @since 2.2 + */ + public PyObject __iternext__() { + return null; + } + /*The basic functions to implement a namespace*/ *************** *** 1262,1270 **** **/ public boolean __contains__(PyObject o) { ! PyObject tmp; ! int i = 0; ! ! while ((tmp = __finditem__(i++)) != null) { ! if (o._eq(tmp).__nonzero__()) return true; } --- 1304,1310 ---- **/ public boolean __contains__(PyObject o) { ! PyObject iter = __iter__(); ! for (PyObject item = null; (item = iter.__iternext__()) != null; ) { ! if (o._eq(item).__nonzero__()) return true; } Index: PySequence.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PySequence.java,v retrieving revision 2.18 retrieving revision 2.19 diff -C2 -d -r2.18 -r2.19 *** PySequence.java 2001/10/28 17:13:43 2.18 --- PySequence.java 2002/01/06 21:19:13 2.19 *************** *** 186,189 **** --- 186,193 ---- } + public PyObject __iter__() { + return new PySequenceIter(this); + } + public synchronized PyObject __eq__(PyObject o) { if (o.__class__ != __class__) *************** *** 273,281 **** throw Py.TypeError(msg); - int n = seq.__len__(); - PyList list = new PyList(); ! PyObject item; ! for (int i = 0; (item = list.__finditem__(i)) != null; i++) { list.append(item); } --- 277,283 ---- throw Py.TypeError(msg); PyList list = new PyList(); ! PyObject iter = Py.iter(seq, msg); ! for (PyObject item = null; (item = iter.__iternext__()) != null; ) { list.append(item); } Index: PyString.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyString.java,v retrieving revision 2.53 retrieving revision 2.54 diff -C2 -d -r2.53 -r2.54 *** PyString.java 2001/12/07 14:15:18 2.53 --- PyString.java 2002/01/06 21:19:13 2.54 *************** *** 1461,1466 **** StringBuffer buf = new StringBuffer(); ! PyObject obj; ! for (int i=0; (obj = seq.__finditem__(i)) != null; i++) { if (!(obj instanceof PyString)) throw Py.TypeError( --- 1461,1467 ---- StringBuffer buf = new StringBuffer(); ! PyObject iter = seq.__iter__(); ! PyObject obj = null; ! for (int i = 0; (obj = iter.__iternext__()) != null; i++) { if (!(obj instanceof PyString)) throw Py.TypeError( Index: PyStringMap.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyStringMap.java,v retrieving revision 2.12 retrieving revision 2.13 diff -C2 -d -r2.12 -r2.13 *** PyStringMap.java 2001/10/28 17:13:43 2.12 --- PyStringMap.java 2002/01/06 21:19:13 2.13 *************** *** 128,131 **** --- 128,135 ---- } + public PyObject __iter__() { + return new PyStringMapIter(keys, values); + } + private final void insertkey(String key, PyObject value) { String[] table = keys; *************** *** 542,543 **** --- 546,578 ---- } } + + class PyStringMapIter extends PyObject { + String[] keyTable; + PyObject[] valTable; + private int idx; + + public PyStringMapIter(String[] keys, PyObject[] values) { + this.keyTable = keys; + this.valTable = values; + this.idx = 0; + } + + public PyObject __iternext__() { + int n = keyTable.length; + + for (; idx < n; idx++) { + String key = keyTable[idx]; + if (key == null || key == "<deleted key>" || valTable[idx] == null) + continue; + idx++; + return Py.newString(key); + } + return null; + } + + // __class__ boilerplate -- see PyObject for details + public static PyClass __class__; + protected PyClass getPyClass() { return __class__; } + } + + Index: __builtin__.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/__builtin__.java,v retrieving revision 2.41 retrieving revision 2.42 diff -C2 -d -r2.41 -r2.42 *** __builtin__.java 2001/12/20 22:45:11 2.41 --- __builtin__.java 2002/01/06 21:19:13 2.42 *************** *** 336,351 **** public static PyObject filter(PyObject f, PyObject l) { - int i=0; - PyObject element; PyList list = new PyList(); ! while ((element = l.__finditem__(i++)) != null) { if (f == Py.None) { ! if (!element.__nonzero__()) continue; } else { ! if (!f.__call__(element).__nonzero__()) continue; } ! list.append(element); } return list; --- 336,350 ---- public static PyObject filter(PyObject f, PyObject l) { PyList list = new PyList(); ! PyObject iter = l.__iter__(); ! for (PyObject item = null; (item = iter.__iternext__()) != null; ) { if (f == Py.None) { ! if (!item.__nonzero__()) continue; } else { ! if (!f.__call__(item).__nonzero__()) continue; } ! list.append(item); } return list; *************** *** 502,506 **** public static PyObject map(PyObject[] argstar) { - int i=0; int n = argstar.length-1; if (n < 1) --- 501,504 ---- *************** *** 510,517 **** PyList list = new PyList(); PyObject[] args = new PyObject[n]; while (true) { boolean any_items = false; ! for(int j=0; j<n; j++) { ! if ((element = argstar[j+1].__finditem__(i)) != null) { args[j] = element; any_items = true; --- 508,522 ---- PyList list = new PyList(); PyObject[] args = new PyObject[n]; + PyObject[] iters = new PyObject[n]; + + for (int j = 0; j < n; j++) { + iters[j] = Py.iter(argstar[j+1], "argument " + j + "to map() " + + "must support iteration"); + } + while (true) { boolean any_items = false; ! for(int j = 0; j < n; j++) { ! if ((element = iters[j].__iternext__()) != null) { args[j] = element; any_items = true; *************** *** 531,539 **** list.append(f.__call__(args)); } - i = i+1; } return list; } // I've never been happy with max and min builtin's... --- 536,544 ---- list.append(f.__call__(args)); } } return list; } + // I've never been happy with max and min builtin's... *************** *** 545,557 **** private static PyObject max(PyObject o) { ! PyObject max = o.__finditem__(0); if (max == null) throw Py.ValueError("max of empty sequence"); - PyObject element; - int i=1; - while ((element = o.__finditem__(i++)) != null) { - if (element._gt(max).__nonzero__()) - max = element; - } return max; } --- 550,561 ---- private static PyObject max(PyObject o) { ! PyObject max = null; ! PyObject iter = o.__iter__(); ! for (PyObject item; (item = iter.__iternext__()) != null; ) { ! if (max == null || item._gt(max).__nonzero__()) ! max = item; ! } if (max == null) throw Py.ValueError("max of empty sequence"); return max; } *************** *** 564,576 **** private static PyObject min(PyObject o) { ! PyObject min = o.__finditem__(0); if (min == null) throw Py.ValueError("min of empty sequence"); - PyObject element; - int i=1; - while ((element = o.__finditem__(i++)) != null) { - if (element._lt(min).__nonzero__()) - min = element; - } return min; } --- 568,579 ---- private static PyObject min(PyObject o) { ! PyObject min = null; ! PyObject iter = o.__iter__(); ! for (PyObject item; (item = iter.__iternext__()) != null; ) { ! if (min == null || item._lt(min).__nonzero__()) ! min = item; ! } if (min == null) throw Py.ValueError("min of empty sequence"); return min; } *************** *** 763,778 **** public static PyObject reduce(PyObject f, PyObject l, PyObject z) { ! int i=0; ! PyObject element, result; ! result = z; if (result == null) { ! result = l.__finditem__(i++); ! if (result == null) { ! throw Py.TypeError( "reduce of empty sequence with no initial value"); - } - } - while ((element = l.__finditem__(i++)) != null) { - result = f.__call__(result, element); } return result; --- 766,781 ---- public static PyObject reduce(PyObject f, PyObject l, PyObject z) { ! PyObject result = z; ! PyObject iter = Py.iter(l, "reduce() arg 2 must support iteration"); ! ! for (PyObject item; (item = iter.__iternext__()) != null; ) { ! if (result == null) ! result = item; ! else ! result = f.__call__(result, item); ! } if (result == null) { ! throw Py.TypeError( "reduce of empty sequence with no initial value"); } return result; *************** *** 828,831 **** --- 831,841 ---- } + public static PyObject iter(PyObject obj) { + return obj.__iter__(); + } + + public static PyObject iter(PyObject callable, PyObject sentinel) { + return new PyCallIter(callable, sentinel); + } public static PyString str(PyObject o) { *************** *** 987,991 **** for(int i=0; i<n; i++) { ! objs[i] = o.__finditem__(i); } return objs; --- 997,1001 ---- for(int i=0; i<n; i++) { ! objs[i] = o.__finditem__(i); // XXX: convert to __iter__! } return objs; Index: codecs.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/codecs.java,v retrieving revision 2.11 retrieving revision 2.12 diff -C2 -d -r2.11 -r2.12 *** codecs.java 2001/08/06 20:04:12 2.11 --- codecs.java 2002/01/06 21:19:13 2.12 *************** *** 50,56 **** "can't find encoding"); ! int i = 0; PyObject func = null; ! for (; (func = searchPath.__finditem__(i)) != null; i++) { result = func.__call__(v); if (result == Py.None) --- 50,56 ---- "can't find encoding"); ! PyObject iter = searchPath.__iter__(); PyObject func = null; ! while ((func = iter.__iternext__()) != null) { result = func.__call__(v); if (result == Py.None) *************** *** 61,65 **** break; } ! if (i == searchPath.__len__()) throw new PyException(Py.LookupError, "unknown encoding " + encoding); --- 61,65 ---- break; } ! if (func == null) throw new PyException(Py.LookupError, "unknown encoding " + encoding); Index: exceptions.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/exceptions.java,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** exceptions.java 2002/01/06 16:11:06 1.11 --- exceptions.java 2002/01/06 21:19:13 1.12 *************** *** 210,214 **** "Request to exit from the interpreter."); ! buildClass(dict, "StopIterator", "Exception", "empty__init__", "Signal the end from iterator.next()."); --- 210,214 ---- "Request to exit from the interpreter."); ! buildClass(dict, "StopIteration", "Exception", "empty__init__", "Signal the end from iterator.next()."); Index: imp.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/imp.java,v retrieving revision 2.59 retrieving revision 2.60 diff -C2 -d -r2.59 -r2.60 *** imp.java 2001/12/21 00:20:17 2.59 --- imp.java 2002/01/06 21:19:13 2.60 *************** *** 13,17 **** public class imp { ! public static final int APIVersion = 9; private imp() { ; } --- 13,17 ---- public class imp { ! public static final int APIVersion = 10; private imp() { ; } *************** *** 744,750 **** PyObject locals, boolean filter) { ! int i=0; ! PyObject name; ! while ((name=names.__finditem__(i++)) != null) { String sname = ((PyString)name).internedString(); if (filter && sname.startsWith("_")) { --- 744,749 ---- PyObject locals, boolean filter) { ! PyObject iter = names.__iter__(); ! for (PyObject name; (name = iter.__iternext__()) != null; ) { String sname = ((PyString)name).internedString(); if (filter && sname.startsWith("_")) { |