summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2014-01-14 16:36:51 +0100
committerBram Moolenaar <Bram@vim.org>2014-01-14 16:36:51 +0100
commit063a46ba77c3251f0b5245e872dcbad003c71024 (patch)
treee85d7ca1c040ef4ecbef8f7bbbf7d92fe4ce823c
parent14177b77bf7bb9c3f1c7c8805bc6cff1b651c136 (diff)
downloadvim-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)
-rw-r--r--src/eval.c11
-rw-r--r--src/if_py_both.h454
-rw-r--r--src/if_python.c23
-rw-r--r--src/if_python3.c76
-rw-r--r--src/proto/eval.pro1
-rw-r--r--src/testdir/test86.in65
-rw-r--r--src/testdir/test86.ok20
-rw-r--r--src/testdir/test87.in90
-rw-r--r--src/testdir/test87.ok31
-rw-r--r--src/version.c2
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,