0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -04:00

patch 7.4.1731

Problem:    Python: turns partial into simple funcref.
Solution:   Use partials like partials. (Nikolai Pavlov, closes #734)
This commit is contained in:
Bram Moolenaar
2016-04-14 15:56:09 +02:00
parent 58de0e2dcc
commit 8110a091bc
11 changed files with 923 additions and 62 deletions

View File

@@ -72,6 +72,7 @@ typedef void (*runner)(const char *, void *
static int ConvertFromPyObject(PyObject *, typval_T *);
static int _ConvertFromPyObject(PyObject *, typval_T *, PyObject *);
static int ConvertFromPyMapping(PyObject *, typval_T *);
static int ConvertFromPySequence(PyObject *, typval_T *);
static PyObject *WindowNew(win_T *, tabpage_T *);
static PyObject *BufferNew (buf_T *);
static PyObject *LineToString(const char *);
@@ -1433,6 +1434,7 @@ typedef struct pylinkedlist_S {
static pylinkedlist_T *lastdict = NULL;
static pylinkedlist_T *lastlist = NULL;
static pylinkedlist_T *lastfunc = NULL;
static void
pyll_remove(pylinkedlist_T *ref, pylinkedlist_T **last)
@@ -2828,14 +2830,20 @@ typedef struct
{
PyObject_HEAD
char_u *name;
int argc;
typval_T *argv;
dict_T *self;
pylinkedlist_T ref;
} FunctionObject;
static PyTypeObject FunctionType;
#define NEW_FUNCTION(name) FunctionNew(&FunctionType, name)
#define NEW_FUNCTION(name, argc, argv, self) \
FunctionNew(&FunctionType, name, argc, argv, self)
static PyObject *
FunctionNew(PyTypeObject *subtype, char_u *name)
FunctionNew(PyTypeObject *subtype, char_u *name, int argc, typval_T *argv,
dict_T *selfdict)
{
FunctionObject *self;
@@ -2865,6 +2873,13 @@ FunctionNew(PyTypeObject *subtype, char_u *name)
return NULL;
}
self->argc = argc;
self->argv = argv;
self->self = selfdict;
if (self->argv || self->self)
pyll_add((PyObject *)(self), &self->ref, &lastfunc);
return (PyObject *)(self);
}
@@ -2872,19 +2887,59 @@ FunctionNew(PyTypeObject *subtype, char_u *name)
FunctionConstructor(PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
{
PyObject *self;
PyObject *selfdictObject;
PyObject *argsObject = NULL;
char_u *name;
typval_T selfdicttv;
typval_T argstv;
list_T *argslist = NULL;
dict_T *selfdict = NULL;
int argc = 0;
typval_T *argv = NULL;
typval_T *curtv;
listitem_T *li;
if (kwargs)
if (kwargs != NULL)
{
PyErr_SET_STRING(PyExc_TypeError,
N_("function constructor does not accept keyword arguments"));
return NULL;
selfdictObject = PyDict_GetItemString(kwargs, "self");
if (selfdictObject != NULL)
{
if (ConvertFromPyMapping(selfdictObject, &selfdicttv) == -1)
return NULL;
selfdict = selfdicttv.vval.v_dict;
}
argsObject = PyDict_GetItemString(kwargs, "args");
if (argsObject != NULL)
{
if (ConvertFromPySequence(argsObject, &argstv) == -1)
{
dict_unref(selfdict);
return NULL;
}
argslist = argstv.vval.v_list;
argc = argslist->lv_len;
if (argc != 0)
{
argv = PyMem_New(typval_T, (size_t) argc);
curtv = argv;
for (li = argslist->lv_first; li != NULL; li = li->li_next)
copy_tv(&li->li_tv, curtv++);
}
list_unref(argslist);
}
}
if (!PyArg_ParseTuple(args, "et", "ascii", &name))
{
dict_unref(selfdict);
while (argc--)
clear_tv(&argv[argc]);
PyMem_Free(argv);
return NULL;
}
self = FunctionNew(subtype, name);
self = FunctionNew(subtype, name, argc, argv, selfdict);
PyMem_Free(name);
@@ -2894,14 +2949,21 @@ FunctionConstructor(PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
static void
FunctionDestructor(FunctionObject *self)
{
int i;
func_unref(self->name);
vim_free(self->name);
for (i = 0; i < self->argc; ++i)
clear_tv(&self->argv[i]);
PyMem_Free(self->argv);
dict_unref(self->self);
if (self->argv || self->self)
pyll_remove(&self->ref, &lastfunc);
DESTRUCTOR_FINISH(self);
}
static char *FunctionAttrs[] = {
"softspace",
"softspace", "args", "self",
NULL
};
@@ -2911,6 +2973,69 @@ FunctionDir(PyObject *self)
return ObjectDir(self, FunctionAttrs);
}
static PyObject *
FunctionAttr(FunctionObject *self, char *name)
{
list_T *list;
int i;
if (strcmp(name, "name") == 0)
return PyString_FromString((char *)(self->name));
else if (strcmp(name, "args") == 0)
{
if (self->argv == NULL)
return AlwaysNone(NULL);
list = list_alloc();
for (i = 0; i < self->argc; ++i)
list_append_tv(list, &self->argv[i]);
return NEW_LIST(list);
}
else if (strcmp(name, "self") == 0)
return self->self == NULL
? AlwaysNone(NULL)
: NEW_DICTIONARY(self->self);
else if (strcmp(name, "__members__") == 0)
return ObjectDir(NULL, FunctionAttrs);
return NULL;
}
/* Populate partial_T given function object.
*
* "exported" should be set to true when it is needed to construct a partial
* that may be stored in a variable (i.e. may be freed by Vim).
*/
static void
set_partial(FunctionObject *self, partial_T *pt, int exported)
{
typval_T *curtv;
int i;
pt->pt_name = self->name;
if (self->argv)
{
pt->pt_argc = self->argc;
if (exported)
{
pt->pt_argv = (typval_T *)alloc_clear(
sizeof(typval_T) * self->argc);
for (i = 0; i < pt->pt_argc; ++i)
copy_tv(&self->argv[i], &pt->pt_argv[i]);
}
else
pt->pt_argv = self->argv;
}
else
{
pt->pt_argc = 0;
pt->pt_argv = NULL;
}
pt->pt_dict = self->self;
if (exported && self->self)
++pt->pt_dict->dv_refcount;
if (exported)
pt->pt_name = vim_strsave(pt->pt_name);
pt->pt_refcount = 1;
}
static PyObject *
FunctionCall(FunctionObject *self, PyObject *argsObject, PyObject *kwargs)
{
@@ -2922,8 +3047,10 @@ FunctionCall(FunctionObject *self, PyObject *argsObject, PyObject *kwargs)
PyObject *selfdictObject;
PyObject *ret;
int error;
partial_T pt;
partial_T *pt_ptr = NULL;
if (ConvertFromPyObject(argsObject, &args) == -1)
if (ConvertFromPySequence(argsObject, &args) == -1)
return NULL;
if (kwargs != NULL)
@@ -2940,11 +3067,17 @@ FunctionCall(FunctionObject *self, PyObject *argsObject, PyObject *kwargs)
}
}
if (self->argv || self->self)
{
set_partial(self, &pt, FALSE);
pt_ptr = &pt;
}
Py_BEGIN_ALLOW_THREADS
Python_Lock_Vim();
VimTryStart();
error = func_call(name, &args, NULL, selfdict, &rettv);
error = func_call(name, &args, pt_ptr, selfdict, &rettv);
Python_Release_Vim();
Py_END_ALLOW_THREADS
@@ -2970,14 +3103,49 @@ FunctionCall(FunctionObject *self, PyObject *argsObject, PyObject *kwargs)
static PyObject *
FunctionRepr(FunctionObject *self)
{
#ifdef Py_TRACE_REFS
/* For unknown reason self->name may be NULL after calling
* Finalize */
return PyString_FromFormat("<vim.Function '%s'>",
(self->name == NULL ? "<NULL>" : (char *)self->name));
#else
return PyString_FromFormat("<vim.Function '%s'>", (char *)self->name);
#endif
PyObject *ret;
garray_T repr_ga;
int i;
char_u *tofree = NULL;
typval_T tv;
char_u numbuf[NUMBUFLEN];
ga_init2(&repr_ga, (int)sizeof(char), 70);
ga_concat(&repr_ga, (char_u *)"<vim.Function '");
if (self->name)
ga_concat(&repr_ga, self->name);
else
ga_concat(&repr_ga, (char_u *)"<NULL>");
ga_append(&repr_ga, '\'');
if (self->argv)
{
ga_concat(&repr_ga, (char_u *)", args=[");
++emsg_silent;
for (i = 0; i < self->argc; i++)
{
if (i != 0)
ga_concat(&repr_ga, (char_u *)", ");
ga_concat(&repr_ga, tv2string(&self->argv[i], &tofree, numbuf,
get_copyID()));
vim_free(tofree);
}
--emsg_silent;
ga_append(&repr_ga, ']');
}
if (self->self)
{
ga_concat(&repr_ga, (char_u *)", self=");
tv.v_type = VAR_DICT;
tv.vval.v_dict = self->self;
++emsg_silent;
ga_concat(&repr_ga, tv2string(&tv, &tofree, numbuf, get_copyID()));
--emsg_silent;
vim_free(tofree);
}
ga_append(&repr_ga, '>');
ret = PyString_FromString((char *)repr_ga.ga_data);
ga_clear(&repr_ga);
return ret;
}
static struct PyMethodDef FunctionMethods[] = {
@@ -5551,11 +5719,13 @@ set_ref_in_py(const int copyID)
pylinkedlist_T *cur;
dict_T *dd;
list_T *ll;
int i;
int abort = FALSE;
FunctionObject *func;
if (lastdict != NULL)
{
for(cur = lastdict ; !abort && cur != NULL ; cur = cur->pll_prev)
for (cur = lastdict ; !abort && cur != NULL ; cur = cur->pll_prev)
{
dd = ((DictionaryObject *) (cur->pll_obj))->dict;
if (dd->dv_copyID != copyID)
@@ -5568,7 +5738,7 @@ set_ref_in_py(const int copyID)
if (lastlist != NULL)
{
for(cur = lastlist ; !abort && cur != NULL ; cur = cur->pll_prev)
for (cur = lastlist ; !abort && cur != NULL ; cur = cur->pll_prev)
{
ll = ((ListObject *) (cur->pll_obj))->list;
if (ll->lv_copyID != copyID)
@@ -5579,6 +5749,24 @@ set_ref_in_py(const int copyID)
}
}
if (lastfunc != NULL)
{
for (cur = lastfunc ; !abort && cur != NULL ; cur = cur->pll_prev)
{
func = (FunctionObject *) cur->pll_obj;
if (func->self != NULL && func->self->dv_copyID != copyID)
{
func->self->dv_copyID = copyID;
abort = abort || set_ref_in_ht(
&func->self->dv_hashtab, copyID, NULL);
}
if (func->argc)
for (i = 0; !abort && i < func->argc; ++i)
abort = abort
|| set_ref_in_item(&func->argv[i], copyID, NULL, NULL);
}
}
return abort;
}
@@ -5879,6 +6067,34 @@ ConvertFromPyMapping(PyObject *obj, typval_T *tv)
return ret;
}
static int
ConvertFromPySequence(PyObject *obj, typval_T *tv)
{
PyObject *lookup_dict;
int ret;
if (!(lookup_dict = PyDict_New()))
return -1;
if (PyType_IsSubtype(obj->ob_type, &ListType))
{
tv->v_type = VAR_LIST;
tv->vval.v_list = (((ListObject *)(obj))->list);
++tv->vval.v_list->lv_refcount;
}
else if (PyIter_Check(obj) || PySequence_Check(obj))
return convert_dl(obj, tv, pyseq_to_tv, lookup_dict);
else
{
PyErr_FORMAT(PyExc_TypeError,
N_("unable to convert %s to vim list"),
Py_TYPE_NAME(obj));
ret = -1;
}
Py_DECREF(lookup_dict);
return ret;
}
static int
ConvertFromPyObject(PyObject *obj, typval_T *tv)
{
@@ -5909,11 +6125,22 @@ _ConvertFromPyObject(PyObject *obj, typval_T *tv, PyObject *lookup_dict)
}
else if (PyType_IsSubtype(obj->ob_type, &FunctionType))
{
if (set_string_copy(((FunctionObject *) (obj))->name, tv) == -1)
return -1;
FunctionObject *func = (FunctionObject *) obj;
if (func->self != NULL || func->argv != NULL)
{
partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
set_partial(func, pt, TRUE);
tv->vval.v_partial = pt;
tv->v_type = VAR_PARTIAL;
}
else
{
if (set_string_copy(func->name, tv) == -1)
return -1;
tv->v_type = VAR_FUNC;
func_ref(tv->vval.v_string);
tv->v_type = VAR_FUNC;
}
func_ref(func->name);
}
else if (PyBytes_Check(obj))
{
@@ -6009,6 +6236,8 @@ _ConvertFromPyObject(PyObject *obj, typval_T *tv, PyObject *lookup_dict)
static PyObject *
ConvertToPyObject(typval_T *tv)
{
typval_T *argv;
int i;
if (tv == NULL)
{
PyErr_SET_VIM(N_("internal error: NULL reference passed"));
@@ -6031,10 +6260,23 @@ ConvertToPyObject(typval_T *tv)
return NEW_DICTIONARY(tv->vval.v_dict);
case VAR_FUNC:
return NEW_FUNCTION(tv->vval.v_string == NULL
? (char_u *)"" : tv->vval.v_string);
? (char_u *)"" : tv->vval.v_string,
0, NULL, NULL);
case VAR_PARTIAL:
if (tv->vval.v_partial->pt_argc)
{
argv = PyMem_New(typval_T, (size_t)tv->vval.v_partial->pt_argc);
for (i = 0; i < tv->vval.v_partial->pt_argc; i++)
copy_tv(&tv->vval.v_partial->pt_argv[i], &argv[i]);
}
else
argv = NULL;
if (tv->vval.v_partial->pt_dict != NULL)
tv->vval.v_partial->pt_dict->dv_refcount++;
return NEW_FUNCTION(tv->vval.v_partial == NULL
? (char_u *)"" : tv->vval.v_partial->pt_name);
? (char_u *)"" : tv->vval.v_partial->pt_name,
tv->vval.v_partial->pt_argc, argv,
tv->vval.v_partial->pt_dict);
case VAR_UNKNOWN:
case VAR_CHANNEL:
case VAR_JOB: