# HG changeset patch # User Bram Moolenaar # Date 1389713811 -3600 # Node ID ec02e1474bc2bbfd73349e7fedf62ae45f941ad9 # Parent 98a642716acc256e4a03e2cdfee64ffa4e3cd9db updated for version 7.4.151 Problem: Python: slices with steps are not supported. Solution: Support slices in Python vim.List. (ZyX) diff --git a/src/eval.c b/src/eval.c --- 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 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -36,8 +36,9 @@ static const char *vim_special_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 DictionaryMeth }; 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,53 +2272,389 @@ ListItem(ListObject *self, Py_ssize_t in 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; - - n = last-first; - list = PyList_New(n); + + if (step == 0) + { + PyErr_SET_STRING(PyExc_ValueError, N_("slice step cannot be zero")); + return NULL; + } + + list = PyList_New(slicelen); if (list == NULL) return NULL; - for (i = 0; i < n; ++i) - { - PyObject *item = ListItem(self, first + i); + for (i = 0; i < slicelen; ++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; } + static PyObject * +ListItem(ListObject *self, PyObject* idx) +{ +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(idx)) + { + long _idx = PyInt_AsLong(idx); + return ListIndex(self, _idx); + } + else +#endif + if (PyLong_Check(idx)) + { + long _idx = PyLong_AsLong(idx); + return ListIndex(self, _idx); + } + else if (PySlice_Check(idx)) + { + Py_ssize_t start, stop, step, slicelen; + + if (PySlice_GetIndicesEx(idx, ListLength(self), + &start, &stop, &step, &slicelen) < 0) + return NULL; + return ListSlice(self, start, step, slicelen); + } + else + { + RAISE_INVALID_INDEX_TYPE(idx); + return NULL; + } +} + + 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--) + { + list_insert(l, lis[numreplaced], lis[slicelen + numreplaced]); + listitem_remove(l, lis[slicelen + numreplaced]); + } + while (numadded--) + { + listitem_T *next; + + next = lastaddedli->li_prev; + listitem_remove(l, lastaddedli); + lastaddedli = next; + } +} + + static int +ListAssSlice(ListObject *self, Py_ssize_t first, + Py_ssize_t step, Py_ssize_t slicelen, PyObject *obj) +{ + 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) + { + RAISE_LOCKED_LIST; + return -1; + } + + 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; + else + { + li = list_find(l, (long) first); + if (li == NULL) + { + PyErr_VIM_FORMAT(N_("internal error: no vim list item %d"), + (int)first); + if (obj != NULL) + PyMem_Free(lis); + return -1; + } + i = slicelen; + while (i-- && li != NULL) + { + 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); + 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; + } + } + + if (obj == NULL) + 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, 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) +{ + list_T *l = self->list; + PyObject *lookup_dict; + + if (l->lv_lock) + { + RAISE_LOCKED_LIST; + return NULL; + } + + if (!(lookup_dict = PyDict_New())) + return NULL; + + if (list_py_concat(l, obj, lookup_dict) == -1) + { + Py_DECREF(lookup_dict); + return NULL; + } + Py_DECREF(lookup_dict); + + Py_INCREF(self); + return (PyObject *)(self); +} + typedef struct { listwatch_T lw; @@ -2370,156 +2705,6 @@ ListIter(ListObject *self) 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) - { - 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 int -ListAssSlice(ListObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *obj) -{ - PyInt size = ListLength(self); - PyObject *iterator; - PyObject *item; - listitem_T *li; - listitem_T *next; - typval_T v; - list_T *l = self->list; - PyInt i; - - if (l->lv_lock) - { - RAISE_LOCKED_LIST; - return -1; - } - - PROC_RANGE - - if (first == size) - li = NULL; - else - { - li = list_find(l, (long) first); - if (li == NULL) - { - PyErr_VIM_FORMAT(N_("internal error: no vim list item %d"), - (int)first); - return -1; - } - if (last > first) - { - i = last - first; - while (i-- && li != NULL) - { - next = li->li_next; - listitem_remove(l, li); - li = next; - } - } - } - - if (obj == NULL) - return 0; - - if (!(iterator = PyObject_GetIter(obj))) - return -1; - - while ((item = PyIter_Next(iterator))) - { - if (ConvertFromPyObject(item, &v) == -1) - { - Py_DECREF(iterator); - Py_DECREF(item); - return -1; - } - Py_DECREF(item); - if (list_insert_tv(l, &v, li) == FAIL) - { - clear_tv(&v); - PyErr_SET_VIM(N_("internal error: failed to add item to list")); - return -1; - } - clear_tv(&v); - } - Py_DECREF(iterator); - - if (PyErr_Occurred()) - return -1; - - return 0; -} - - static PyObject * -ListConcatInPlace(ListObject *self, PyObject *obj) -{ - list_T *l = self->list; - PyObject *lookup_dict; - - if (l->lv_lock) - { - RAISE_LOCKED_LIST; - return NULL; - } - - if (!(lookup_dict = PyDict_New())) - return NULL; - - if (list_py_concat(l, obj, lookup_dict) == -1) - { - Py_DECREF(lookup_dict); - return NULL; - } - Py_DECREF(lookup_dict); - - Py_INCREF(self); - return (PyObject *)(self); -} - static char *ListAttrs[] = { "locked", NULL @@ -2567,6 +2752,25 @@ ListSetattr(ListObject *self, char *name } } +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 --- 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)(P 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 *, 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 * 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 --- 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)( 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, PyObj /* 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 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -60,6 +60,7 @@ int list_append_dict __ARGS((list_T *lis 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 --- 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 --- 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:('lon >>> 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 locke 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 --- 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 --- 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():(>> 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',)) @@ -818,6 +841,14 @@ ll[1:100] = "abcJ":(, 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',)) +(b'a', b'b', b'c', b'O') +nel[1:10:2] = "a":(, 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":(, ValueError('attempt to assign sequence of size greater then 0 to extended slice',)) +(b'a', b'b', b'c', b'O') +nel[:] = FailingIterNextN(2):(, NotImplementedError('next N',)) +(b'a', b'b', b'c', b'O') >>> Testing StringToChars using l[:] = [{%s : 1}] l[:] = [{1 : 1}]:(, TypeError('expected bytes() or str() instance, but got int',)) l[:] = [{b"\0" : 1}]:(, TypeError('expected bytes with no null',)) diff --git a/src/version.c b/src/version.c --- 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,