diff options
author | Bram Moolenaar <Bram@vim.org> | 2014-01-14 16:36:51 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2014-01-14 16:36:51 +0100 |
commit | 063a46ba77c3251f0b5245e872dcbad003c71024 (patch) | |
tree | e85d7ca1c040ef4ecbef8f7bbbf7d92fe4ce823c /src | |
parent | 14177b77bf7bb9c3f1c7c8805bc6cff1b651c136 (diff) | |
download | vim-git-063a46ba77c3251f0b5245e872dcbad003c71024.tar.gz |
updated for version 7.4.151v7.4.151
Problem: Python: slices with steps are not supported.
Solution: Support slices in Python vim.List. (ZyX)
Diffstat (limited to 'src')
-rw-r--r-- | src/eval.c | 11 | ||||
-rw-r--r-- | src/if_py_both.h | 454 | ||||
-rw-r--r-- | src/if_python.c | 23 | ||||
-rw-r--r-- | src/if_python3.c | 76 | ||||
-rw-r--r-- | src/proto/eval.pro | 1 | ||||
-rw-r--r-- | src/testdir/test86.in | 65 | ||||
-rw-r--r-- | src/testdir/test86.ok | 20 | ||||
-rw-r--r-- | src/testdir/test87.in | 90 | ||||
-rw-r--r-- | src/testdir/test87.ok | 31 | ||||
-rw-r--r-- | src/version.c | 2 |
10 files changed, 561 insertions, 212 deletions
diff --git a/src/eval.c b/src/eval.c index 693896cff..65f4b1138 100644 --- a/src/eval.c +++ b/src/eval.c @@ -6425,6 +6425,16 @@ list_insert_tv(l, tv, item) if (ni == NULL) return FAIL; copy_tv(tv, &ni->li_tv); + list_insert(l, ni, item); + return OK; +} + + void +list_insert(l, ni, item) + list_T *l; + listitem_T *ni; + listitem_T *item; +{ if (item == NULL) /* Append new item at end of list. */ list_append(l, ni); @@ -6446,7 +6456,6 @@ list_insert_tv(l, tv, item) item->li_prev = ni; ++l->lv_len; } - return OK; } /* diff --git a/src/if_py_both.h b/src/if_py_both.h index 17c02a9ec..6e3939abe 100644 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -36,8 +36,9 @@ static const char *vim_special_path = "_vim_path_"; #define PyErr_SET_STRING(exc, str) PyErr_SetString(exc, _(str)) #define PyErr_SetVim(str) PyErr_SetString(VimError, str) #define PyErr_SET_VIM(str) PyErr_SET_STRING(VimError, str) -#define PyErr_FORMAT(exc, str, tail) PyErr_Format(exc, _(str), tail) -#define PyErr_VIM_FORMAT(str, tail) PyErr_FORMAT(VimError, str, tail) +#define PyErr_FORMAT(exc, str, arg) PyErr_Format(exc, _(str), arg) +#define PyErr_FORMAT2(exc, str, arg1, arg2) PyErr_Format(exc, _(str), arg1,arg2) +#define PyErr_VIM_FORMAT(str, arg) PyErr_FORMAT(VimError, str, arg) #define Py_TYPE_NAME(obj) (obj->ob_type->tp_name == NULL \ ? "(NULL)" \ @@ -2108,8 +2109,6 @@ static struct PyMethodDef DictionaryMethods[] = { }; static PyTypeObject ListType; -static PySequenceMethods ListAsSeq; -static PyMappingMethods ListAsMapping; typedef struct { @@ -2253,7 +2252,7 @@ ListLength(ListObject *self) } static PyObject * -ListItem(ListObject *self, Py_ssize_t index) +ListIndex(ListObject *self, Py_ssize_t index) { listitem_T *li; @@ -2273,164 +2272,110 @@ ListItem(ListObject *self, Py_ssize_t index) return ConvertToPyObject(&li->li_tv); } -#define PROC_RANGE \ - if (last < 0) {\ - if (last < -size) \ - last = 0; \ - else \ - last += size; \ - } \ - if (first < 0) \ - first = 0; \ - if (first > size) \ - first = size; \ - if (last > size) \ - last = size; - static PyObject * -ListSlice(ListObject *self, Py_ssize_t first, Py_ssize_t last) +ListSlice(ListObject *self, Py_ssize_t first, Py_ssize_t step, + Py_ssize_t slicelen) { PyInt i; - PyInt size = ListLength(self); - PyInt n; PyObject *list; - int reversed = 0; - PROC_RANGE - if (first >= last) - first = last; + if (step == 0) + { + PyErr_SET_STRING(PyExc_ValueError, N_("slice step cannot be zero")); + return NULL; + } - n = last-first; - list = PyList_New(n); + list = PyList_New(slicelen); if (list == NULL) return NULL; - for (i = 0; i < n; ++i) + for (i = 0; i < slicelen; ++i) { - PyObject *item = ListItem(self, first + i); + PyObject *item; + + item = ListIndex(self, first + i*step); if (item == NULL) { Py_DECREF(list); return NULL; } - PyList_SET_ITEM(list, ((reversed)?(n-i-1):(i)), item); + PyList_SET_ITEM(list, i, item); } return list; } -typedef struct -{ - listwatch_T lw; - list_T *list; -} listiterinfo_T; - - static void -ListIterDestruct(listiterinfo_T *lii) -{ - list_rem_watch(lii->list, &lii->lw); - PyMem_Free(lii); -} - static PyObject * -ListIterNext(listiterinfo_T **lii) +ListItem(ListObject *self, PyObject* idx) { - PyObject *ret; - - if (!((*lii)->lw.lw_item)) - return NULL; - - if (!(ret = ConvertToPyObject(&((*lii)->lw.lw_item->li_tv)))) - return NULL; - - (*lii)->lw.lw_item = (*lii)->lw.lw_item->li_next; - - return ret; -} - - static PyObject * -ListIter(ListObject *self) -{ - listiterinfo_T *lii; - list_T *l = self->list; - - if (!(lii = PyMem_New(listiterinfo_T, 1))) +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(idx)) { - PyErr_NoMemory(); - return NULL; + long _idx = PyInt_AsLong(idx); + return ListIndex(self, _idx); } - - list_add_watch(l, &lii->lw); - lii->lw.lw_item = l->lv_first; - lii->list = l; - - return IterNew(lii, - (destructorfun) ListIterDestruct, (nextfun) ListIterNext, - NULL, NULL); -} - - static int -ListAssItem(ListObject *self, Py_ssize_t index, PyObject *obj) -{ - typval_T tv; - list_T *l = self->list; - listitem_T *li; - Py_ssize_t length = ListLength(self); - - if (l->lv_lock) + else +#endif + if (PyLong_Check(idx)) { - RAISE_LOCKED_LIST; - return -1; + long _idx = PyLong_AsLong(idx); + return ListIndex(self, _idx); } - if (index > length || (index == length && obj == NULL)) + else if (PySlice_Check(idx)) { - PyErr_SET_STRING(PyExc_IndexError, N_("list index out of range")); - return -1; - } + Py_ssize_t start, stop, step, slicelen; - if (obj == NULL) + if (PySlice_GetIndicesEx(idx, ListLength(self), + &start, &stop, &step, &slicelen) < 0) + return NULL; + return ListSlice(self, start, step, slicelen); + } + else { - li = list_find(l, (long) index); - list_remove(l, li, li); - clear_tv(&li->li_tv); - vim_free(li); - return 0; + RAISE_INVALID_INDEX_TYPE(idx); + return NULL; } +} - if (ConvertFromPyObject(obj, &tv) == -1) - return -1; - - if (index == length) + static void +list_restore(Py_ssize_t numadded, Py_ssize_t numreplaced, Py_ssize_t slicelen, + list_T *l, listitem_T **lis, listitem_T *lastaddedli) +{ + while (numreplaced--) { - if (list_append_tv(l, &tv) == FAIL) - { - clear_tv(&tv); - PyErr_SET_VIM(N_("failed to add item to list")); - return -1; - } + list_insert(l, lis[numreplaced], lis[slicelen + numreplaced]); + listitem_remove(l, lis[slicelen + numreplaced]); } - else + while (numadded--) { - li = list_find(l, (long) index); - clear_tv(&li->li_tv); - copy_tv(&tv, &li->li_tv); - clear_tv(&tv); + listitem_T *next; + + next = lastaddedli->li_prev; + listitem_remove(l, lastaddedli); + lastaddedli = next; } - return 0; } static int -ListAssSlice(ListObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *obj) +ListAssSlice(ListObject *self, Py_ssize_t first, + Py_ssize_t step, Py_ssize_t slicelen, PyObject *obj) { - PyInt size = ListLength(self); PyObject *iterator; PyObject *item; listitem_T *li; + listitem_T *lastaddedli = NULL; listitem_T *next; typval_T v; list_T *l = self->list; PyInt i; + PyInt j; + PyInt numreplaced = 0; + PyInt numadded = 0; + PyInt size; + listitem_T **lis; + + size = ListLength(self); if (l->lv_lock) { @@ -2438,7 +2383,42 @@ ListAssSlice(ListObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *obj) return -1; } - PROC_RANGE + if (step == 0) + { + PyErr_SET_STRING(PyExc_ValueError, N_("slice step cannot be zero")); + return -1; + } + + if (step != 1 && slicelen == 0) + { + /* Nothing to do. Only error out if obj has some items. */ + int ret = 0; + + if (obj == NULL) + return 0; + + if (!(iterator = PyObject_GetIter(obj))) + return -1; + + if ((item = PyIter_Next(iterator))) + { + PyErr_FORMAT(PyExc_ValueError, + N_("attempt to assign sequence of size greater then %d " + "to extended slice"), 0); + Py_DECREF(item); + ret = -1; + } + Py_DECREF(iterator); + return ret; + } + + if (obj != NULL) + /* XXX May allocate zero bytes. */ + if (!(lis = PyMem_New(listitem_T *, slicelen * 2))) + { + PyErr_NoMemory(); + return -1; + } if (first == size) li = NULL; @@ -2449,17 +2429,33 @@ ListAssSlice(ListObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *obj) { PyErr_VIM_FORMAT(N_("internal error: no vim list item %d"), (int)first); + if (obj != NULL) + PyMem_Free(lis); return -1; } - if (last > first) + i = slicelen; + while (i-- && li != NULL) { - i = last - first; - while (i-- && li != NULL) - { - next = li->li_next; + j = step; + next = li; + if (step > 0) + while (next != NULL && ((next = next->li_next) != NULL) && --j); + else + while (next != NULL && ((next = next->li_prev) != NULL) && ++j); + + if (obj == NULL) listitem_remove(l, li); - li = next; - } + else + lis[slicelen - i - 1] = li; + + li = next; + } + if (li == NULL && i != -1) + { + PyErr_SET_VIM(N_("internal error: not enough list items")); + if (obj != NULL) + PyMem_Free(lis); + return -1; } } @@ -2467,33 +2463,172 @@ ListAssSlice(ListObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *obj) return 0; if (!(iterator = PyObject_GetIter(obj))) + { + PyMem_Free(lis); return -1; + } + i = 0; while ((item = PyIter_Next(iterator))) { if (ConvertFromPyObject(item, &v) == -1) { Py_DECREF(iterator); Py_DECREF(item); + PyMem_Free(lis); return -1; } Py_DECREF(item); - if (list_insert_tv(l, &v, li) == FAIL) + if (list_insert_tv(l, &v, numreplaced < slicelen + ? lis[numreplaced] + : li) == FAIL) { clear_tv(&v); PyErr_SET_VIM(N_("internal error: failed to add item to list")); + list_restore(numadded, numreplaced, slicelen, l, lis, lastaddedli); + PyMem_Free(lis); return -1; } + if (numreplaced < slicelen) + { + lis[slicelen + numreplaced] = lis[numreplaced]->li_prev; + list_remove(l, lis[numreplaced], lis[numreplaced]); + numreplaced++; + } + else + { + if (li) + lastaddedli = li->li_prev; + else + lastaddedli = l->lv_last; + numadded++; + } clear_tv(&v); + if (step != 1 && i >= slicelen) + { + Py_DECREF(iterator); + PyErr_FORMAT(PyExc_ValueError, + N_("attempt to assign sequence of size greater then %d " + "to extended slice"), slicelen); + list_restore(numadded, numreplaced, slicelen, l, lis, lastaddedli); + PyMem_Free(lis); + return -1; + } + ++i; } Py_DECREF(iterator); + if (step != 1 && i != slicelen) + { + PyErr_FORMAT2(PyExc_ValueError, + N_("attempt to assign sequence of size %d to extended slice " + "of size %d"), i, slicelen); + list_restore(numadded, numreplaced, slicelen, l, lis, lastaddedli); + PyMem_Free(lis); + return -1; + } + if (PyErr_Occurred()) + { + list_restore(numadded, numreplaced, slicelen, l, lis, lastaddedli); + PyMem_Free(lis); + return -1; + } + + for (i = 0; i < numreplaced; i++) + listitem_free(lis[i]); + if (step == 1) + for (i = numreplaced; i < slicelen; i++) + listitem_remove(l, lis[i]); + + PyMem_Free(lis); + + return 0; +} + + static int +ListAssIndex(ListObject *self, Py_ssize_t index, PyObject *obj) +{ + typval_T tv; + list_T *l = self->list; + listitem_T *li; + Py_ssize_t length = ListLength(self); + + if (l->lv_lock) + { + RAISE_LOCKED_LIST; + return -1; + } + if (index > length || (index == length && obj == NULL)) + { + PyErr_SET_STRING(PyExc_IndexError, N_("list index out of range")); return -1; + } + if (obj == NULL) + { + li = list_find(l, (long) index); + list_remove(l, li, li); + clear_tv(&li->li_tv); + vim_free(li); + return 0; + } + + if (ConvertFromPyObject(obj, &tv) == -1) + return -1; + + if (index == length) + { + if (list_append_tv(l, &tv) == FAIL) + { + clear_tv(&tv); + PyErr_SET_VIM(N_("failed to add item to list")); + return -1; + } + } + else + { + li = list_find(l, (long) index); + clear_tv(&li->li_tv); + copy_tv(&tv, &li->li_tv); + clear_tv(&tv); + } return 0; } + static Py_ssize_t +ListAssItem(ListObject *self, PyObject *idx, PyObject *obj) +{ +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(idx)) + { + long _idx = PyInt_AsLong(idx); + return ListAssIndex(self, _idx, obj); + } + else +#endif + if (PyLong_Check(idx)) + { + long _idx = PyLong_AsLong(idx); + return ListAssIndex(self, _idx, obj); + } + else if (PySlice_Check(idx)) + { + Py_ssize_t start, stop, step, slicelen; + + if (PySlice_GetIndicesEx(idx, ListLength(self), + &start, &stop, &step, &slicelen) < 0) + return -1; + return ListAssSlice(self, start, step, slicelen, + obj); + } + else + { + RAISE_INVALID_INDEX_TYPE(idx); + return -1; + } +} + static PyObject * ListConcatInPlace(ListObject *self, PyObject *obj) { @@ -2520,6 +2655,56 @@ ListConcatInPlace(ListObject *self, PyObject *obj) return (PyObject *)(self); } +typedef struct +{ + listwatch_T lw; + list_T *list; +} listiterinfo_T; + + static void +ListIterDestruct(listiterinfo_T *lii) +{ + list_rem_watch(lii->list, &lii->lw); + PyMem_Free(lii); +} + + static PyObject * +ListIterNext(listiterinfo_T **lii) +{ + PyObject *ret; + + if (!((*lii)->lw.lw_item)) + return NULL; + + if (!(ret = ConvertToPyObject(&((*lii)->lw.lw_item->li_tv)))) + return NULL; + + (*lii)->lw.lw_item = (*lii)->lw.lw_item->li_next; + + return ret; +} + + static PyObject * +ListIter(ListObject *self) +{ + listiterinfo_T *lii; + list_T *l = self->list; + + if (!(lii = PyMem_New(listiterinfo_T, 1))) + { + PyErr_NoMemory(); + return NULL; + } + + list_add_watch(l, &lii->lw); + lii->lw.lw_item = l->lv_first; + lii->list = l; + + return IterNew(lii, + (destructorfun) ListIterDestruct, (nextfun) ListIterNext, + NULL, NULL); +} + static char *ListAttrs[] = { "locked", NULL @@ -2567,6 +2752,25 @@ ListSetattr(ListObject *self, char *name, PyObject *valObject) } } +static PySequenceMethods ListAsSeq = { + (lenfunc) ListLength, /* sq_length, len(x) */ + (binaryfunc) 0, /* RangeConcat, sq_concat, x+y */ + 0, /* RangeRepeat, sq_repeat, x*n */ + (PyIntArgFunc) ListIndex, /* sq_item, x[i] */ + 0, /* was_sq_slice, x[i:j] */ + (PyIntObjArgProc) ListAssIndex, /* sq_as_item, x[i]=v */ + 0, /* was_sq_ass_slice, x[i:j]=v */ + 0, /* sq_contains */ + (binaryfunc) ListConcatInPlace,/* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + +static PyMappingMethods ListAsMapping = { + /* mp_length */ (lenfunc) ListLength, + /* mp_subscript */ (binaryfunc) ListItem, + /* mp_ass_subscript */ (objobjargproc) ListAssItem, +}; + static struct PyMethodDef ListMethods[] = { {"extend", (PyCFunction)ListConcatInPlace, METH_O, ""}, {"__dir__", (PyCFunction)ListDir, METH_NOARGS, ""}, diff --git a/src/if_python.c b/src/if_python.c index e34bd280f..92510b367 100644 --- a/src/if_python.c +++ b/src/if_python.c @@ -196,6 +196,7 @@ struct PyMethodDef { Py_ssize_t a; }; # define PyTuple_Size dll_PyTuple_Size # define PyTuple_GetItem dll_PyTuple_GetItem # define PyTuple_Type (*dll_PyTuple_Type) +# define PySlice_GetIndicesEx dll_PySlice_GetIndicesEx # define PyImport_ImportModule dll_PyImport_ImportModule # define PyDict_New dll_PyDict_New # define PyDict_GetItemString dll_PyDict_GetItemString @@ -241,6 +242,7 @@ struct PyMethodDef { Py_ssize_t a; }; # define PySys_GetObject dll_PySys_GetObject # define PySys_SetArgv dll_PySys_SetArgv # define PyType_Type (*dll_PyType_Type) +# define PySlice_Type (*dll_PySlice_Type) # define PyType_Ready (*dll_PyType_Ready) # define PyType_GenericAlloc dll_PyType_GenericAlloc # define Py_BuildValue dll_Py_BuildValue @@ -341,6 +343,9 @@ static PyObject*(*dll_PySequence_Fast)(PyObject *, const char *); static PyInt(*dll_PyTuple_Size)(PyObject *); static PyObject*(*dll_PyTuple_GetItem)(PyObject *, PyInt); static PyTypeObject* dll_PyTuple_Type; +static int (*dll_PySlice_GetIndicesEx)(PyObject *r, PyInt length, + PyInt *start, PyInt *stop, PyInt *step, + PyInt *slicelen); static PyObject*(*dll_PyImport_ImportModule)(const char *); static PyObject*(*dll_PyDict_New)(void); static PyObject*(*dll_PyDict_GetItemString)(PyObject *, const char *); @@ -382,6 +387,7 @@ static int(*dll_PySys_SetObject)(char *, PyObject *); static PyObject *(*dll_PySys_GetObject)(char *); static int(*dll_PySys_SetArgv)(int, char **); static PyTypeObject* dll_PyType_Type; +static PyTypeObject* dll_PySlice_Type; static int (*dll_PyType_Ready)(PyTypeObject *type); static PyObject* (*dll_PyType_GenericAlloc)(PyTypeObject *type, PyInt nitems); static PyObject*(*dll_Py_BuildValue)(char *, ...); @@ -521,6 +527,7 @@ static struct {"PyTuple_GetItem", (PYTHON_PROC*)&dll_PyTuple_GetItem}, {"PyTuple_Size", (PYTHON_PROC*)&dll_PyTuple_Size}, {"PyTuple_Type", (PYTHON_PROC*)&dll_PyTuple_Type}, + {"PySlice_GetIndicesEx", (PYTHON_PROC*)&dll_PySlice_GetIndicesEx}, {"PyImport_ImportModule", (PYTHON_PROC*)&dll_PyImport_ImportModule}, {"PyDict_GetItemString", (PYTHON_PROC*)&dll_PyDict_GetItemString}, {"PyDict_Next", (PYTHON_PROC*)&dll_PyDict_Next}, @@ -562,6 +569,7 @@ static struct {"PySys_GetObject", (PYTHON_PROC*)&dll_PySys_GetObject}, {"PySys_SetArgv", (PYTHON_PROC*)&dll_PySys_SetArgv}, {"PyType_Type", (PYTHON_PROC*)&dll_PyType_Type}, + {"PySlice_Type", (PYTHON_PROC*)&dll_PySlice_Type}, {"PyType_Ready", (PYTHON_PROC*)&dll_PyType_Ready}, {"PyType_GenericAlloc", (PYTHON_PROC*)&dll_PyType_GenericAlloc}, {"Py_FindMethod", (PYTHON_PROC*)&dll_Py_FindMethod}, @@ -1472,21 +1480,6 @@ DictionaryGetattr(PyObject *self, char *name) return Py_FindMethod(DictionaryMethods, self, name); } -static PySequenceMethods ListAsSeq = { - (PyInquiry) ListLength, - (binaryfunc) 0, - (PyIntArgFunc) 0, - (PyIntArgFunc) ListItem, - (PyIntIntArgFunc) ListSlice, - (PyIntObjArgProc) ListAssItem, - (PyIntIntObjArgProc) ListAssSlice, - (objobjproc) 0, -#if PY_MAJOR_VERSION >= 2 - (binaryfunc) ListConcatInPlace, - 0, -#endif -}; - static PyObject * ListGetattr(PyObject *self, char *name) { diff --git a/src/if_python3.c b/src/if_python3.c index 40bc97bc8..55779e79b 100644 --- a/src/if_python3.c +++ b/src/if_python3.c @@ -97,6 +97,9 @@ #define Py_ssize_t_fmt "n" #define Py_bytes_fmt "y" +#define PyIntArgFunc ssizeargfunc +#define PyIntObjArgProc ssizeobjargproc + #if defined(DYNAMIC_PYTHON3) || defined(PROTO) # ifndef WIN3264 @@ -292,7 +295,8 @@ static PyObject* (*py3_PyTuple_GetItem)(PyObject *, Py_ssize_t); static int (*py3_PyMapping_Check)(PyObject *); static PyObject* (*py3_PyMapping_Keys)(PyObject *); static int (*py3_PySlice_GetIndicesEx)(PyObject *r, Py_ssize_t length, - Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelength); + Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, + Py_ssize_t *slicelen); static PyObject* (*py3_PyErr_NoMemory)(void); static void (*py3_Py_Finalize)(void); static void (*py3_PyErr_SetString)(PyObject *, const char *); @@ -1478,76 +1482,6 @@ DictionarySetattro(PyObject *self, PyObject *nameobj, PyObject *val) /* List object - Definitions */ -static PySequenceMethods ListAsSeq = { - (lenfunc) ListLength, /* sq_length, len(x) */ - (binaryfunc) 0, /* RangeConcat, sq_concat, x+y */ - (ssizeargfunc) 0, /* RangeRepeat, sq_repeat, x*n */ - (ssizeargfunc) ListItem, /* sq_item, x[i] */ - (void *) 0, /* was_sq_slice, x[i:j] */ - (ssizeobjargproc) ListAssItem, /* sq_as_item, x[i]=v */ - (void *) 0, /* was_sq_ass_slice, x[i:j]=v */ - 0, /* sq_contains */ - (binaryfunc) ListConcatInPlace,/* sq_inplace_concat */ - 0, /* sq_inplace_repeat */ -}; - -static PyObject *ListSubscript(PyObject *, PyObject *); -static Py_ssize_t ListAsSubscript(PyObject *, PyObject *, PyObject *); - -static PyMappingMethods ListAsMapping = { - /* mp_length */ (lenfunc) ListLength, - /* mp_subscript */ (binaryfunc) ListSubscript, - /* mp_ass_subscript */ (objobjargproc) ListAsSubscript, -}; - - static PyObject * -ListSubscript(PyObject *self, PyObject* idx) -{ - if (PyLong_Check(idx)) - { - long _idx = PyLong_AsLong(idx); - return ListItem((ListObject *)(self), _idx); - } - else if (PySlice_Check(idx)) - { - Py_ssize_t start, stop, step, slicelen; - - if (PySlice_GetIndicesEx(idx, ListLength((ListObject *)(self)), - &start, &stop, &step, &slicelen) < 0) - return NULL; - return ListSlice((ListObject *)(self), start, stop); - } - else - { - RAISE_INVALID_INDEX_TYPE(idx); - return NULL; - } -} - - static Py_ssize_t -ListAsSubscript(PyObject *self, PyObject *idx, PyObject *obj) -{ - if (PyLong_Check(idx)) - { - long _idx = PyLong_AsLong(idx); - return ListAssItem((ListObject *)(self), _idx, obj); - } - else if (PySlice_Check(idx)) - { - Py_ssize_t start, stop, step, slicelen; - - if (PySlice_GetIndicesEx(idx, ListLength((ListObject *)(self)), - &start, &stop, &step, &slicelen) < 0) - return -1; - return ListAssSlice((ListObject *)(self), start, stop, obj); - } - else - { - RAISE_INVALID_INDEX_TYPE(idx); - return -1; - } -} - static PyObject * ListGetattro(PyObject *self, PyObject *nameobj) { diff --git a/src/proto/eval.pro b/src/proto/eval.pro index ee2da1b02..3fa265ef7 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -60,6 +60,7 @@ int list_append_dict __ARGS((list_T *list, dict_T *dict)); int list_append_string __ARGS((list_T *l, char_u *str, int len)); int list_insert_tv __ARGS((list_T *l, typval_T *tv, listitem_T *item)); void list_remove __ARGS((list_T *l, listitem_T *item, listitem_T *item2)); +void list_insert __ARGS((list_T *l, listitem_T *ni, listitem_T *item)); int garbage_collect __ARGS((void)); void set_ref_in_ht __ARGS((hashtab_T *ht, int copyID)); void set_ref_in_list __ARGS((list_T *l, int copyID)); diff --git a/src/testdir/test86.in b/src/testdir/test86.in index 128055b32..1ccf7bd3d 100644 --- a/src/testdir/test86.in +++ b/src/testdir/test86.in @@ -135,6 +135,18 @@ EOF :py l=vim.bindeval('l') :py del l[-6:2] :$put =string(l) +:let l = [0, 1, 2, 3] +:py l=vim.bindeval('l') +:py del l[::2] +:$put =string(l) +:let l = [0, 1, 2, 3] +:py l=vim.bindeval('l') +:py del l[3:0:-2] +:$put =string(l) +:let l = [0, 1, 2, 3] +:py l=vim.bindeval('l') +:py del l[2:4:-2] +:$put =string(l) :" :" Slice assignment to a list :let l = [0, 1, 2, 3] @@ -169,6 +181,26 @@ EOF :py l=vim.bindeval('l') :py l[0:0]=['h'] :$put =string(l) +:let l = range(8) +:py l=vim.bindeval('l') +:py l[2:6:2] = [10, 20] +:$put =string(l) +:let l = range(8) +:py l=vim.bindeval('l') +:py l[6:2:-2] = [10, 20] +:$put =string(l) +:let l = range(8) +:py l=vim.bindeval('l') +:py l[6:2] = () +:$put =string(l) +:let l = range(8) +:py l=vim.bindeval('l') +:py l[6:2:1] = () +:$put =string(l) +:let l = range(8) +:py l=vim.bindeval('l') +:py l[2:2:1] = () +:$put =string(l) :" :" Locked variables :let l = [0, 1, 2, 3] @@ -390,6 +422,13 @@ EOF :$put =string(pyeval('l')) :py l = ll[-10:10] :$put =string(pyeval('l')) +:py l = ll[4:2:-1] +:$put =string(pyeval('l')) +:py l = ll[::2] +:$put =string(pyeval('l')) +:py l = ll[4:2:1] +:$put =string(pyeval('l')) +:py del l :" :" Vars :let g:foo = 'bac' @@ -907,6 +946,7 @@ dl.locked = True l = vim.List() ll = vim.List('abcE') ll.locked = True +nel = vim.List('abcO') f = vim.Function('string') fd = vim.Function('F') fdel = vim.Function('D') @@ -994,6 +1034,20 @@ class FailingIterNext(object): def next(self): raise NotImplementedError('next') +class FailingIterNextN(object): + def __init__(self, n): + self.n = n + + def __iter__(self): + return self + + def next(self): + if self.n: + self.n -= 1 + return 1 + else: + raise NotImplementedError('next N') + class FailingMappingKey(object): def __getitem__(self, item): raise NotImplementedError('getitem:mappingkey') @@ -1098,6 +1152,7 @@ cb.append(">>> kwargs") cb.append(">>> iter") ee('d.update(FailingMapping())') ee('d.update([FailingIterNext()])') +ee('d.update([FailingIterNextN(1)])') iter_test('d.update(%s)') convertfrompyobject_test('d.update(%s)') stringtochars_test('d.update(((%s, 0),))') @@ -1120,6 +1175,14 @@ ee('l[1000] = 3') cb.append(">> ListAssSlice") ee('ll[1:100] = "abcJ"') iter_test('l[:] = %s') +ee('nel[1:10:2] = "abcK"') +cb.append(repr(tuple(nel))) +ee('nel[1:10:2] = "a"') +cb.append(repr(tuple(nel))) +ee('nel[1:1:-1] = "a"') +cb.append(repr(tuple(nel))) +ee('nel[:] = FailingIterNextN(2)') +cb.append(repr(tuple(nel))) convertfrompyobject_test('l[:] = [%s]') cb.append(">> ListConcatInPlace") iter_test('l.extend(%s)') @@ -1201,6 +1264,7 @@ del ned del dl del l del ll +del nel del f del fd del fdel @@ -1214,6 +1278,7 @@ del number_test del FailingTrue del FailingIter del FailingIterNext +del FailingIterNextN del FailingMapping del FailingMappingKey del FailingList diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok index 9ef21db0c..42cb0259c 100644 --- a/src/testdir/test86.ok +++ b/src/testdir/test86.ok @@ -41,6 +41,9 @@ None [2, 3] [2, 3] [2, 3] +[1, 3] +[0, 2] +[0, 1, 2, 3] ['a', 0, 1, 2, 3] [0, 'b', 2, 3] [0, 1, 'c'] @@ -49,6 +52,11 @@ None ['f', 2, 3] [0, 1, 'g', 2, 3] ['h'] +[0, 1, 10, 3, 20, 5, 6, 7] +[0, 1, 2, 3, 20, 5, 10, 7] +[0, 1, 2, 3, 4, 5, 6, 7] +[0, 1, 2, 3, 4, 5, 6, 7] +[0, 1, 2, 3, 4, 5, 6, 7] [0, 1, 2, 3] [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd'] [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}] @@ -96,6 +104,9 @@ vim: Vim(let):E859: [0, 1, 2, 3, 4, 5] [0, 1, 2, 3, 4, 5] [0, 1, 2, 3, 4, 5] +[4, 3] +[0, 2, 4] +[] Abc bac def @@ -599,6 +610,7 @@ d["a"] = FailingNumber():TypeError:('long() argument must be a string or a numbe >>> iter d.update(FailingMapping()):NotImplementedError:('keys',) d.update([FailingIterNext()]):NotImplementedError:('next',) +d.update([FailingIterNextN(1)]):NotImplementedError:('next N',) >>> Testing *Iter* using d.update(%s) d.update(FailingIter()):NotImplementedError:('iter',) d.update(FailingIterNext()):NotImplementedError:('next',) @@ -829,6 +841,14 @@ ll[1:100] = "abcJ":error:('list is locked',) l[:] = FailingIter():NotImplementedError:('iter',) l[:] = FailingIterNext():NotImplementedError:('next',) <<< Finished +nel[1:10:2] = "abcK":ValueError:('attempt to assign sequence of size greater then 2 to extended slice',) +('a', 'b', 'c', 'O') +nel[1:10:2] = "a":ValueError:('attempt to assign sequence of size 1 to extended slice of size 2',) +('a', 'b', 'c', 'O') +nel[1:1:-1] = "a":ValueError:('attempt to assign sequence of size greater then 0 to extended slice',) +('a', 'b', 'c', 'O') +nel[:] = FailingIterNextN(2):NotImplementedError:('next N',) +('a', 'b', 'c', 'O') >>> Testing StringToChars using l[:] = [{%s : 1}] l[:] = [{1 : 1}]:TypeError:('expected str() or unicode() instance, but got int',) l[:] = [{u"\0" : 1}]:TypeError:('expected string without null bytes',) diff --git a/src/testdir/test87.in b/src/testdir/test87.in index 9abc17b1e..79b24b00d 100644 --- a/src/testdir/test87.in +++ b/src/testdir/test87.in @@ -128,6 +128,18 @@ EOF :py3 l=vim.bindeval('l') :py3 del l[-6:2] :$put =string(l) +:let l = [0, 1, 2, 3] +:py3 l=vim.bindeval('l') +:py3 del l[::2] +:$put =string(l) +:let l = [0, 1, 2, 3] +:py3 l=vim.bindeval('l') +:py3 del l[3:0:-2] +:$put =string(l) +:let l = [0, 1, 2, 3] +:py3 l=vim.bindeval('l') +:py3 del l[2:4:-2] +:$put =string(l) :" :" Slice assignment to a list :let l = [0, 1, 2, 3] @@ -162,6 +174,26 @@ EOF :py3 l=vim.bindeval('l') :py3 l[0:0]=['h'] :$put =string(l) +:let l = range(8) +:py3 l=vim.bindeval('l') +:py3 l[2:6:2] = [10, 20] +:$put =string(l) +:let l = range(8) +:py3 l=vim.bindeval('l') +:py3 l[6:2:-2] = [10, 20] +:$put =string(l) +:let l = range(8) +:py3 l=vim.bindeval('l') +:py3 l[6:2] = () +:$put =string(l) +:let l = range(8) +:py3 l=vim.bindeval('l') +:py3 l[6:2:1] = () +:$put =string(l) +:let l = range(8) +:py3 l=vim.bindeval('l') +:py3 l[2:2:1] = () +:$put =string(l) :" :" Locked variables :let l = [0, 1, 2, 3] @@ -363,6 +395,38 @@ EOF :py3 del trace_main :$put =string(l) :" +:" Slice +:py3 ll = vim.bindeval('[0, 1, 2, 3, 4, 5]') +:py3 l = ll[:4] +:$put =string(py3eval('l')) +:py3 l = ll[2:] +:$put =string(py3eval('l')) +:py3 l = ll[:-4] +:$put =string(py3eval('l')) +:py3 l = ll[-2:] +:$put =string(py3eval('l')) +:py3 l = ll[2:4] +:$put =string(py3eval('l')) +:py3 l = ll[4:2] +:$put =string(py3eval('l')) +:py3 l = ll[-4:-2] +:$put =string(py3eval('l')) +:py3 l = ll[-2:-4] +:$put =string(py3eval('l')) +:py3 l = ll[:] +:$put =string(py3eval('l')) +:py3 l = ll[0:6] +:$put =string(py3eval('l')) +:py3 l = ll[-10:10] +:$put =string(py3eval('l')) +:py3 l = ll[4:2:-1] +:$put =string(py3eval('l')) +:py3 l = ll[::2] +:$put =string(py3eval('l')) +:py3 l = ll[4:2:1] +:$put =string(py3eval('l')) +:py3 del l +:" :" Vars :let g:foo = 'bac' :let w:abc3 = 'def' @@ -859,6 +923,7 @@ dl.locked = True l = vim.List() ll = vim.List('abcE') ll.locked = True +nel = vim.List('abcO') f = vim.Function('string') fd = vim.Function('F') fdel = vim.Function('D') @@ -946,6 +1011,20 @@ class FailingIterNext(object): def __next__(self): raise NotImplementedError('next') +class FailingIterNextN(object): + def __init__(self, n): + self.n = n + + def __iter__(self): + return self + + def __next__(self): + if self.n: + self.n -= 1 + return 1 + else: + raise NotImplementedError('next N') + class FailingMappingKey(object): def __getitem__(self, item): raise NotImplementedError('getitem:mappingkey') @@ -1050,6 +1129,7 @@ cb.append(">>> kwargs") cb.append(">>> iter") ee('d.update(FailingMapping())') ee('d.update([FailingIterNext()])') +ee('d.update([FailingIterNextN(1)])') iter_test('d.update(%s)') convertfrompyobject_test('d.update(%s)') stringtochars_test('d.update(((%s, 0),))') @@ -1072,6 +1152,14 @@ ee('l[1000] = 3') cb.append(">> ListAssSlice") ee('ll[1:100] = "abcJ"') iter_test('l[:] = %s') +ee('nel[1:10:2] = "abcK"') +cb.append(repr(tuple(nel))) +ee('nel[1:10:2] = "a"') +cb.append(repr(tuple(nel))) +ee('nel[1:1:-1] = "a"') +cb.append(repr(tuple(nel))) +ee('nel[:] = FailingIterNextN(2)') +cb.append(repr(tuple(nel))) convertfrompyobject_test('l[:] = [%s]') cb.append(">> ListConcatInPlace") iter_test('l.extend(%s)') @@ -1153,6 +1241,7 @@ del ned del dl del l del ll +del nel del f del fd del fdel @@ -1166,6 +1255,7 @@ del number_test del FailingTrue del FailingIter del FailingIterNext +del FailingIterNextN del FailingMapping del FailingMappingKey del FailingList diff --git a/src/testdir/test87.ok b/src/testdir/test87.ok index d970d5f3a..57ac1a63a 100644 --- a/src/testdir/test87.ok +++ b/src/testdir/test87.ok @@ -41,6 +41,9 @@ None [2, 3] [2, 3] [2, 3] +[1, 3] +[0, 2] +[0, 1, 2, 3] ['a', 0, 1, 2, 3] [0, 'b', 2, 3] [0, 1, 'c'] @@ -49,6 +52,11 @@ None ['f', 2, 3] [0, 1, 'g', 2, 3] ['h'] +[0, 1, 10, 3, 20, 5, 6, 7] +[0, 1, 2, 3, 20, 5, 10, 7] +[0, 1, 2, 3, 4, 5, 6, 7] +[0, 1, 2, 3, 4, 5, 6, 7] +[0, 1, 2, 3, 4, 5, 6, 7] [0, 1, 2, 3] [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd'] [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}] @@ -85,6 +93,20 @@ undefined_name: Vim(let):Trace vim: Vim(let):E859: [1] [1, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 1] +[0, 1, 2, 3] +[2, 3, 4, 5] +[0, 1] +[4, 5] +[2, 3] +[] +[2, 3] +[] +[0, 1, 2, 3, 4, 5] +[0, 1, 2, 3, 4, 5] +[0, 1, 2, 3, 4, 5] +[4, 3] +[0, 2, 4] +[] Abc bac def @@ -588,6 +610,7 @@ d["a"] = FailingNumber():(<class 'NotImplementedError'>, NotImplementedError('in >>> iter d.update(FailingMapping()):(<class 'NotImplementedError'>, NotImplementedError('keys',)) d.update([FailingIterNext()]):(<class 'NotImplementedError'>, NotImplementedError('next',)) +d.update([FailingIterNextN(1)]):(<class 'NotImplementedError'>, NotImplementedError('next N',)) >>> Testing *Iter* using d.update(%s) d.update(FailingIter()):(<class 'NotImplementedError'>, NotImplementedError('iter',)) d.update(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',)) @@ -818,6 +841,14 @@ ll[1:100] = "abcJ":(<class 'vim.error'>, error('list is locked',)) l[:] = FailingIter():(<class 'NotImplementedError'>, NotImplementedError('iter',)) l[:] = FailingIterNext():(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished +nel[1:10:2] = "abcK":(<class 'ValueError'>, ValueError('attempt to assign sequence of size greater then 2 to extended slice',)) +(b'a', b'b', b'c', b'O') +nel[1:10:2] = "a":(<class 'ValueError'>, ValueError('attempt to assign sequence of size 1 to extended slice of size 2',)) +(b'a', b'b', b'c', b'O') +nel[1:1:-1] = "a":(<class 'ValueError'>, ValueError('attempt to assign sequence of size greater then 0 to extended slice',)) +(b'a', b'b', b'c', b'O') +nel[:] = FailingIterNextN(2):(<class 'NotImplementedError'>, NotImplementedError('next N',)) +(b'a', b'b', b'c', b'O') >>> Testing StringToChars using l[:] = [{%s : 1}] l[:] = [{1 : 1}]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',)) l[:] = [{b"\0" : 1}]:(<class 'TypeError'>, TypeError('expected bytes with no null',)) diff --git a/src/version.c b/src/version.c index 6c2c60fb0..c0fe21f3f 100644 --- a/src/version.c +++ b/src/version.c @@ -739,6 +739,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 151, +/**/ 150, /**/ 149, |