mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
updated for version 7.4.151
Problem: Python: slices with steps are not supported. Solution: Support slices in Python vim.List. (ZyX)
This commit is contained in:
566
src/if_py_both.h
566
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,53 +2272,389 @@ 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;
|
||||
}
|
||||
|
||||
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, 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, ""},
|
||||
|
Reference in New Issue
Block a user