diff src/if_py_both.h @ 3618:c052f3b79b99 v7.3.569

updated for version 7.3.569 Problem: Evaluating Vim expression in Python is insufficient. Solution: Add vim.bindeval(). Also add pyeval() and py3eval(). (ZyX)
author Bram Moolenaar <bram@vim.org>
date Fri, 29 Jun 2012 12:54:53 +0200
parents e34c620007be
children 0e9b2622c94a
line wrap: on
line diff
--- a/src/if_py_both.h
+++ b/src/if_py_both.h
@@ -1,4 +1,4 @@
-/* vi:set ts=8 sts=4 sw=4:
+/* vi:set ts=8 sts=4 sw=4 noet:
  *
  * VIM - Vi IMproved	by Bram Moolenaar
  *
@@ -105,7 +105,8 @@ OutputWritelines(PyObject *self, PyObjec
 	return NULL;
     Py_INCREF(list);
 
-    if (!PyList_Check(list)) {
+    if (!PyList_Check(list))
+    {
 	PyErr_SetString(PyExc_TypeError, _("writelines() requires list of strings"));
 	Py_DECREF(list);
 	return NULL;
@@ -119,7 +120,8 @@ OutputWritelines(PyObject *self, PyObjec
 	char *str = NULL;
 	PyInt len;
 
-	if (!PyArg_Parse(line, "et#", ENC_OPT, &str, &len)) {
+	if (!PyArg_Parse(line, "et#", ENC_OPT, &str, &len))
+	{
 	    PyErr_SetString(PyExc_TypeError, _("writelines() requires list of strings"));
 	    Py_DECREF(list);
 	    return NULL;
@@ -297,7 +299,7 @@ VimToPython(typval_T *our_tv, int depth,
 {
     PyObject	*result;
     PyObject	*newObj;
-    char	ptrBuf[NUMBUFLEN];
+    char	ptrBuf[sizeof(void *) * 2 + 3];
 
     /* Avoid infinite recursion */
     if (depth > 100)
@@ -312,9 +314,9 @@ VimToPython(typval_T *our_tv, int depth,
     if ((our_tv->v_type == VAR_LIST && our_tv->vval.v_list != NULL)
 	    || (our_tv->v_type == VAR_DICT && our_tv->vval.v_dict != NULL))
     {
-	sprintf(ptrBuf, PRINTF_DECIMAL_LONG_U,
-		our_tv->v_type == VAR_LIST ? (long_u)our_tv->vval.v_list
-					   : (long_u)our_tv->vval.v_dict);
+	sprintf(ptrBuf, "%p",
+		our_tv->v_type == VAR_LIST ? (void *)our_tv->vval.v_list
+					   : (void *)our_tv->vval.v_dict);
 	result = PyDict_GetItemString(lookupDict, ptrBuf);
 	if (result != NULL)
 	{
@@ -445,6 +447,57 @@ VimEval(PyObject *self UNUSED, PyObject 
 #endif
 }
 
+static PyObject *ConvertToPyObject(typval_T *);
+
+    static PyObject *
+VimEvalPy(PyObject *self UNUSED, PyObject *args UNUSED)
+{
+#ifdef FEAT_EVAL
+    char	*expr;
+    typval_T	*our_tv;
+    PyObject	*result;
+
+    if (!PyArg_ParseTuple(args, "s", &expr))
+	return NULL;
+
+    Py_BEGIN_ALLOW_THREADS
+    Python_Lock_Vim();
+    our_tv = eval_expr((char_u *)expr, NULL);
+
+    Python_Release_Vim();
+    Py_END_ALLOW_THREADS
+
+    if (our_tv == NULL)
+    {
+	PyErr_SetVim(_("invalid expression"));
+	return NULL;
+    }
+
+    result = ConvertToPyObject(our_tv);
+    Py_BEGIN_ALLOW_THREADS
+    Python_Lock_Vim();
+    free_tv(our_tv);
+    Python_Release_Vim();
+    Py_END_ALLOW_THREADS
+
+    return result;
+#else
+    PyErr_SetVim(_("expressions disabled at compile time"));
+    return NULL;
+#endif
+}
+
+    static PyObject *
+VimStrwidth(PyObject *self UNUSED, PyObject *args)
+{
+    char	*expr;
+
+    if (!PyArg_ParseTuple(args, "s", &expr))
+	return NULL;
+
+    return PyLong_FromLong(mb_string2cells((char_u *)expr, STRLEN(expr)));
+}
+
 /*
  * Vim module - Definitions
  */
@@ -453,6 +506,8 @@ static struct PyMethodDef VimMethods[] =
     /* name,	     function,		calling,    documentation */
     {"command",	     VimCommand,	1,	    "Execute a Vim ex-mode command" },
     {"eval",	     VimEval,		1,	    "Evaluate an expression using Vim evaluator" },
+    {"bindeval",     VimEvalPy,         1,          "Like eval(), but returns objects attached to vim ones"},
+    {"strwidth",     VimStrwidth,       1,          "Screen string width, counts <Tab> as having width 1"},
     { NULL,	     NULL,		0,	    NULL }
 };
 
@@ -460,8 +515,7 @@ typedef struct
 {
     PyObject_HEAD
     buf_T *buf;
-}
-BufferObject;
+} BufferObject;
 
 #define INVALID_BUFFER_VALUE ((buf_T *)(-1))
 
@@ -505,6 +559,768 @@ typedef struct
     win_T	*win;
 } WindowObject;
 
+static int ConvertFromPyObject(PyObject *, typval_T *);
+static int _ConvertFromPyObject(PyObject *, typval_T *, PyObject *);
+
+typedef struct pylinkedlist_S {
+    struct pylinkedlist_S	*pll_next;
+    struct pylinkedlist_S	*pll_prev;
+    PyObject			*pll_obj;
+} pylinkedlist_T;
+
+static pylinkedlist_T *lastdict = NULL;
+static pylinkedlist_T *lastlist = NULL;
+
+    static void
+pyll_remove(pylinkedlist_T *ref, pylinkedlist_T **last)
+{
+    if (ref->pll_prev == NULL)
+    {
+	if (ref->pll_next == NULL)
+	{
+	    *last = NULL;
+	    return;
+	}
+    }
+    else
+	ref->pll_prev->pll_next = ref->pll_next;
+
+    if (ref->pll_next == NULL)
+	*last = ref->pll_prev;
+    else
+	ref->pll_next->pll_prev = ref->pll_prev;
+}
+
+    static void
+pyll_add(PyObject *self, pylinkedlist_T *ref, pylinkedlist_T **last)
+{
+    if (*last == NULL)
+	ref->pll_prev = NULL;
+    else
+    {
+	(*last)->pll_next = ref;
+	ref->pll_prev = *last;
+    }
+    ref->pll_next = NULL;
+    ref->pll_obj = self;
+    *last = ref;
+}
+
+static PyTypeObject DictionaryType;
+
+typedef struct
+{
+    PyObject_HEAD
+    dict_T	*dict;
+    pylinkedlist_T	ref;
+} DictionaryObject;
+
+    static PyObject *
+DictionaryNew(dict_T *dict)
+{
+    DictionaryObject	*self;
+
+    self = PyObject_NEW(DictionaryObject, &DictionaryType);
+    if (self == NULL)
+	return NULL;
+    self->dict = dict;
+    ++dict->dv_refcount;
+
+    pyll_add((PyObject *)(self), &self->ref, &lastdict);
+
+    return (PyObject *)(self);
+}
+
+    static int
+pydict_to_tv(PyObject *obj, typval_T *tv, PyObject *lookupDict)
+{
+    dict_T	*d;
+    char_u	*key;
+    dictitem_T	*di;
+    PyObject	*keyObject;
+    PyObject	*valObject;
+    Py_ssize_t	iter = 0;
+
+    d = dict_alloc();
+    if (d == NULL)
+    {
+	PyErr_NoMemory();
+	return -1;
+    }
+
+    tv->v_type = VAR_DICT;
+    tv->vval.v_dict = d;
+
+    while (PyDict_Next(obj, &iter, &keyObject, &valObject))
+    {
+	DICTKEY_DECL
+
+	if (keyObject == NULL)
+	    return -1;
+	if (valObject == NULL)
+	    return -1;
+
+	DICTKEY_GET(-1)
+
+	di = dictitem_alloc(key);
+
+	DICTKEY_UNREF
+
+	if (di == NULL)
+	{
+	    PyErr_NoMemory();
+	    return -1;
+	}
+	di->di_tv.v_lock = 0;
+
+	if (_ConvertFromPyObject(valObject, &di->di_tv, lookupDict) == -1)
+	{
+	    vim_free(di);
+	    return -1;
+	}
+	if (dict_add(d, di) == FAIL)
+	{
+	    vim_free(di);
+	    PyErr_SetVim(_("failed to add key to dictionary"));
+	    return -1;
+	}
+    }
+    return 0;
+}
+
+    static int
+pymap_to_tv(PyObject *obj, typval_T *tv, PyObject *lookupDict)
+{
+    dict_T	*d;
+    char_u	*key;
+    dictitem_T	*di;
+    PyObject	*list;
+    PyObject	*litem;
+    PyObject	*keyObject;
+    PyObject	*valObject;
+    Py_ssize_t	lsize;
+
+    d = dict_alloc();
+    if (d == NULL)
+    {
+	PyErr_NoMemory();
+	return -1;
+    }
+
+    tv->v_type = VAR_DICT;
+    tv->vval.v_dict = d;
+
+    list = PyMapping_Items(obj);
+    lsize = PyList_Size(list);
+    while (lsize--)
+    {
+	DICTKEY_DECL
+
+	litem = PyList_GetItem(list, lsize);
+	if (litem == NULL)
+	{
+	    Py_DECREF(list);
+	    return -1;
+	}
+
+	keyObject = PyTuple_GetItem(litem, 0);
+	if (keyObject == NULL)
+	{
+	    Py_DECREF(list);
+	    Py_DECREF(litem);
+	    return -1;
+	}
+
+	DICTKEY_GET(-1)
+
+	valObject = PyTuple_GetItem(litem, 1);
+	if (valObject == NULL)
+	{
+	    Py_DECREF(list);
+	    Py_DECREF(litem);
+	    return -1;
+	}
+
+	di = dictitem_alloc(key);
+
+	DICTKEY_UNREF
+
+	if (di == NULL)
+	{
+	    Py_DECREF(list);
+	    Py_DECREF(litem);
+	    PyErr_NoMemory();
+	    return -1;
+	}
+	di->di_tv.v_lock = 0;
+
+	if (_ConvertFromPyObject(valObject, &di->di_tv, lookupDict) == -1)
+	{
+	    vim_free(di);
+	    Py_DECREF(list);
+	    Py_DECREF(litem);
+	    return -1;
+	}
+	if (dict_add(d, di) == FAIL)
+	{
+	    vim_free(di);
+	    Py_DECREF(list);
+	    Py_DECREF(litem);
+	    PyErr_SetVim(_("failed to add key to dictionary"));
+	    return -1;
+	}
+	Py_DECREF(litem);
+    }
+    Py_DECREF(list);
+    return 0;
+}
+
+    static PyInt
+DictionaryLength(PyObject *self)
+{
+    return ((PyInt) ((((DictionaryObject *)(self))->dict->dv_hashtab.ht_used)));
+}
+
+    static PyObject *
+DictionaryItem(PyObject *self, PyObject *keyObject)
+{
+    char_u	*key;
+    dictitem_T	*val;
+    DICTKEY_DECL
+
+    DICTKEY_GET(NULL)
+
+    val = dict_find(((DictionaryObject *) (self))->dict, key, -1);
+
+    DICTKEY_UNREF
+
+    return ConvertToPyObject(&val->di_tv);
+}
+
+    static PyInt
+DictionaryAssItem(PyObject *self, PyObject *keyObject, PyObject *valObject)
+{
+    char_u	*key;
+    typval_T	tv;
+    dict_T	*d = ((DictionaryObject *)(self))->dict;
+    dictitem_T	*di;
+    DICTKEY_DECL
+
+    if (d->dv_lock)
+    {
+	PyErr_SetVim(_("dict is locked"));
+	return -1;
+    }
+
+    DICTKEY_GET(-1)
+
+    di = dict_find(d, key, -1);
+
+    if (valObject == NULL)
+    {
+	if (di == NULL)
+	{
+	    PyErr_SetString(PyExc_IndexError, _("no such key in dictionary"));
+	    return -1;
+	}
+	hashitem_T	*hi = hash_find(&d->dv_hashtab, di->di_key);
+	hash_remove(&d->dv_hashtab, hi);
+	dictitem_free(di);
+	return 0;
+    }
+
+    if (ConvertFromPyObject(valObject, &tv) == -1)
+    {
+	return -1;
+    }
+
+    if (di == NULL)
+    {
+	di = dictitem_alloc(key);
+	if (di == NULL)
+	{
+	    PyErr_NoMemory();
+	    return -1;
+	}
+	di->di_tv.v_lock = 0;
+
+	if (dict_add(d, di) == FAIL)
+	{
+	    vim_free(di);
+	    PyErr_SetVim(_("failed to add key to dictionary"));
+	    return -1;
+	}
+    }
+    else
+	clear_tv(&di->di_tv);
+
+    DICTKEY_UNREF
+
+    copy_tv(&tv, &di->di_tv);
+    return 0;
+}
+
+    static PyObject *
+DictionaryListKeys(PyObject *self)
+{
+    dict_T	*dict = ((DictionaryObject *)(self))->dict;
+    long_u	todo = dict->dv_hashtab.ht_used;
+    Py_ssize_t	i = 0;
+    PyObject	*r;
+    hashitem_T	*hi;
+
+    r = PyList_New(todo);
+    for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
+    {
+	if (!HASHITEM_EMPTY(hi))
+	{
+	    PyList_SetItem(r, i, PyBytes_FromString((char *)(hi->hi_key)));
+	    --todo;
+	    ++i;
+	}
+    }
+    return r;
+}
+
+static struct PyMethodDef DictionaryMethods[] = {
+    {"keys", (PyCFunction)DictionaryListKeys, METH_NOARGS, ""},
+    { NULL,	    NULL,		0,	    NULL }
+};
+
+static PyTypeObject ListType;
+
+typedef struct
+{
+    PyObject_HEAD
+    list_T	*list;
+    pylinkedlist_T	ref;
+} ListObject;
+
+    static PyObject *
+ListNew(list_T *list)
+{
+    ListObject	*self;
+
+    self = PyObject_NEW(ListObject, &ListType);
+    if (self == NULL)
+	return NULL;
+    self->list = list;
+    ++list->lv_refcount;
+
+    pyll_add((PyObject *)(self), &self->ref, &lastlist);
+
+    return (PyObject *)(self);
+}
+
+    static int
+list_py_concat(list_T *l, PyObject *obj, PyObject *lookupDict)
+{
+    Py_ssize_t	i;
+    Py_ssize_t	lsize = PySequence_Size(obj);
+    PyObject	*litem;
+    listitem_T	*li;
+
+    for(i=0; i<lsize; i++)
+    {
+	li = listitem_alloc();
+	if (li == NULL)
+	{
+	    PyErr_NoMemory();
+	    return -1;
+	}
+	li->li_tv.v_lock = 0;
+
+	litem = PySequence_GetItem(obj, i);
+	if (litem == NULL)
+	    return -1;
+	if (_ConvertFromPyObject(litem, &li->li_tv, lookupDict) == -1)
+	    return -1;
+
+	list_append(l, li);
+    }
+    return 0;
+}
+
+    static int
+pyseq_to_tv(PyObject *obj, typval_T *tv, PyObject *lookupDict)
+{
+    list_T	*l;
+
+    l = list_alloc();
+    if (l == NULL)
+    {
+	PyErr_NoMemory();
+	return -1;
+    }
+
+    tv->v_type = VAR_LIST;
+    tv->vval.v_list = l;
+
+    if (list_py_concat(l, obj, lookupDict) == -1)
+	return -1;
+
+    return 0;
+}
+
+    static int
+pyiter_to_tv(PyObject *obj, typval_T *tv, PyObject *lookupDict)
+{
+    PyObject	*iterator = PyObject_GetIter(obj);
+    PyObject	*item;
+    list_T	*l;
+    listitem_T	*li;
+
+    l = list_alloc();
+
+    if (l == NULL)
+    {
+	PyErr_NoMemory();
+	return -1;
+    }
+
+    tv->vval.v_list = l;
+    tv->v_type = VAR_LIST;
+
+
+    if (iterator == NULL)
+	return -1;
+
+    while ((item = PyIter_Next(obj)))
+    {
+	li = listitem_alloc();
+	if (li == NULL)
+	{
+	    PyErr_NoMemory();
+	    return -1;
+	}
+	li->li_tv.v_lock = 0;
+
+	if (_ConvertFromPyObject(item, &li->li_tv, lookupDict) == -1)
+	    return -1;
+
+	list_append(l, li);
+
+	Py_DECREF(item);
+    }
+
+    Py_DECREF(iterator);
+    return 0;
+}
+
+    static PyInt
+ListLength(PyObject *self)
+{
+    return ((PyInt) (((ListObject *) (self))->list->lv_len));
+}
+
+    static PyObject *
+ListItem(PyObject *self, Py_ssize_t index)
+{
+    listitem_T	*li;
+
+    if (index>=ListLength(self))
+    {
+	PyErr_SetString(PyExc_IndexError, "list index out of range");
+	return NULL;
+    }
+    li = list_find(((ListObject *) (self))->list, (long) index);
+    if (li == NULL)
+    {
+	PyErr_SetVim(_("internal error: failed to get vim list item"));
+	return NULL;
+    }
+    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(PyObject *self, Py_ssize_t first, Py_ssize_t last)
+{
+    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 (list == NULL)
+	return NULL;
+
+    for (i = 0; i < n; ++i)
+    {
+	PyObject	*item = ListItem(self, i);
+	if (item == NULL)
+	{
+	    Py_DECREF(list);
+	    return NULL;
+	}
+
+	if ((PyList_SetItem(list, ((reversed)?(n-i-1):(i)), item)))
+	{
+	    Py_DECREF(item);
+	    Py_DECREF(list);
+	    return NULL;
+	}
+    }
+
+    return list;
+}
+
+    static int
+ListAssItem(PyObject *self, Py_ssize_t index, PyObject *obj)
+{
+    typval_T	tv;
+    list_T	*l = ((ListObject *) (self))->list;
+    listitem_T	*li;
+    Py_ssize_t	length = ListLength(self);
+
+    if (l->lv_lock)
+    {
+	PyErr_SetVim(_("list is locked"));
+	return -1;
+    }
+    if (index>length || (index==length && obj==NULL))
+    {
+	PyErr_SetString(PyExc_IndexError, "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)
+	{
+	    PyErr_SetVim(_("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);
+    }
+    return 0;
+}
+
+    static int
+ListAssSlice(PyObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *obj)
+{
+    PyInt	size = ListLength(self);
+    Py_ssize_t	i;
+    Py_ssize_t	lsize;
+    PyObject	*litem;
+    listitem_T	*li;
+    listitem_T	*next;
+    typval_T	v;
+    list_T	*l = ((ListObject *) (self))->list;
+
+    if (l->lv_lock)
+    {
+	PyErr_SetVim(_("list is locked"));
+	return -1;
+    }
+
+    PROC_RANGE
+
+    if (first == size)
+	li = NULL;
+    else
+    {
+	li = list_find(l, (long) first);
+	if (li == NULL)
+	{
+	    PyErr_SetVim(_("internal error: no vim list item"));
+	    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 (!PyList_Check(obj))
+    {
+	PyErr_SetString(PyExc_TypeError, _("can only assign lists to slice"));
+	return -1;
+    }
+
+    lsize = PyList_Size(obj);
+
+    for(i=0; i<lsize; i++)
+    {
+	litem = PyList_GetItem(obj, i);
+	if (litem == NULL)
+	    return -1;
+	if (ConvertFromPyObject(litem, &v) == -1)
+	    return -1;
+	if (list_insert_tv(l, &v, li) == FAIL)
+	{
+	    PyErr_SetVim(_("internal error: failed to add item to list"));
+	    return -1;
+	}
+    }
+    return 0;
+}
+
+    static PyObject *
+ListConcatInPlace(PyObject *self, PyObject *obj)
+{
+    list_T	*l = ((ListObject *) (self))->list;
+    PyObject	*lookup_dict;
+
+    if (l->lv_lock)
+    {
+	PyErr_SetVim(_("list is locked"));
+	return NULL;
+    }
+
+    if (!PySequence_Check(obj))
+    {
+	PyErr_SetString(PyExc_TypeError, _("can only concatenate with lists"));
+	return NULL;
+    }
+
+    lookup_dict = PyDict_New();
+    if (list_py_concat(l, obj, lookup_dict) == -1)
+    {
+	Py_DECREF(lookup_dict);
+	return NULL;
+    }
+    Py_DECREF(lookup_dict);
+
+    Py_INCREF(self);
+    return self;
+}
+
+static struct PyMethodDef ListMethods[] = {
+    {"extend", (PyCFunction)ListConcatInPlace, METH_O, ""},
+    { NULL,	    NULL,		0,	    NULL }
+};
+
+typedef struct
+{
+    PyObject_HEAD
+    char_u	*name;
+} FunctionObject;
+
+static PyTypeObject FunctionType;
+
+    static PyObject *
+FunctionNew(char_u *name)
+{
+    FunctionObject	*self;
+
+    self = PyObject_NEW(FunctionObject, &FunctionType);
+    if (self == NULL)
+	return NULL;
+    self->name = PyMem_New(char_u, STRLEN(name) + 1);
+    if (self->name == NULL)
+    {
+	PyErr_NoMemory();
+	return NULL;
+    }
+    STRCPY(self->name, name);
+    func_ref(name);
+    return (PyObject *)(self);
+}
+
+    static PyObject *
+FunctionCall(PyObject *self, PyObject *argsObject, PyObject *kwargs)
+{
+    FunctionObject	*this = (FunctionObject *)(self);
+    char_u	*name = this->name;
+    typval_T	args;
+    typval_T	selfdicttv;
+    typval_T	rettv;
+    dict_T	*selfdict = NULL;
+    PyObject	*selfdictObject;
+    PyObject	*result;
+    int		error;
+
+    if (ConvertFromPyObject(argsObject, &args) == -1)
+	return NULL;
+
+    if (kwargs != NULL)
+    {
+	selfdictObject = PyDict_GetItemString(kwargs, "self");
+	if (selfdictObject != NULL)
+	{
+	    if (!PyDict_Check(selfdictObject))
+	    {
+		PyErr_SetString(PyExc_TypeError, _("'self' argument must be a dictionary"));
+		clear_tv(&args);
+		return NULL;
+	    }
+	    if (ConvertFromPyObject(selfdictObject, &selfdicttv) == -1)
+		return NULL;
+	    selfdict = selfdicttv.vval.v_dict;
+	}
+    }
+
+    error = func_call(name, &args, selfdict, &rettv);
+    if (error != OK)
+    {
+	result = NULL;
+	PyErr_SetVim(_("failed to run function"));
+    }
+    else
+	result = ConvertToPyObject(&rettv);
+
+    /* FIXME Check what should really be cleared. */
+    clear_tv(&args);
+    clear_tv(&rettv);
+    /*
+     * if (selfdict!=NULL)
+     *     clear_tv(selfdicttv);
+     */
+
+    return result;
+}
+
+static struct PyMethodDef FunctionMethods[] = {
+    {"__call__",    (PyCFunction)FunctionCall, METH_VARARGS|METH_KEYWORDS, ""},
+    { NULL,	    NULL,		0,	    NULL }
+};
+
 #define INVALID_WINDOW_VALUE ((win_T *)(-1))
 
     static int
@@ -1567,3 +2383,256 @@ static struct PyMethodDef RangeMethods[]
     { NULL,	    NULL,		0,	    NULL }
 };
 
+    static void
+set_ref_in_py(const int copyID)
+{
+    pylinkedlist_T	*cur;
+    dict_T	*dd;
+    list_T	*ll;
+
+    if (lastdict != NULL)
+	for(cur = lastdict ; cur != NULL ; cur = cur->pll_prev)
+	{
+	    dd = ((DictionaryObject *) (cur->pll_obj))->dict;
+	    if (dd->dv_copyID != copyID)
+	    {
+		dd->dv_copyID = copyID;
+		set_ref_in_ht(&dd->dv_hashtab, copyID);
+	    }
+	}
+
+    if (lastlist != NULL)
+	for(cur = lastlist ; cur != NULL ; cur = cur->pll_prev)
+	{
+	    ll = ((ListObject *) (cur->pll_obj))->list;
+	    if (ll->lv_copyID != copyID)
+	    {
+		ll->lv_copyID = copyID;
+		set_ref_in_list(ll, copyID);
+	    }
+	}
+}
+
+    static int
+set_string_copy(char_u *str, typval_T *tv)
+{
+    tv->vval.v_string = vim_strsave(str);
+    if (tv->vval.v_string == NULL)
+    {
+	PyErr_NoMemory();
+	return -1;
+    }
+    return 0;
+}
+
+#ifdef FEAT_EVAL
+typedef int (*pytotvfunc)(PyObject *, typval_T *, PyObject *);
+
+    static int
+convert_dl(PyObject *obj, typval_T *tv,
+				    pytotvfunc py_to_tv, PyObject *lookupDict)
+{
+    PyObject	*capsule;
+    char	hexBuf[sizeof(void *) * 2 + 3];
+
+    sprintf(hexBuf, "%p", obj);
+
+    capsule = PyDict_GetItemString(lookupDict, hexBuf);
+    if (capsule == NULL)
+    {
+	capsule = PyCapsule_New(tv, NULL, NULL);
+	PyDict_SetItemString(lookupDict, hexBuf, capsule);
+	Py_DECREF(capsule);
+	if (py_to_tv(obj, tv, lookupDict) == -1)
+	{
+	    tv->v_type = VAR_UNKNOWN;
+	    return -1;
+	}
+	/* As we are not using copy_tv which increments reference count we must
+	 * do it ourself. */
+	switch(tv->v_type)
+	{
+	    case VAR_DICT: ++tv->vval.v_dict->dv_refcount; break;
+	    case VAR_LIST: ++tv->vval.v_list->lv_refcount; break;
+	}
+    }
+    else
+    {
+	typval_T	*v = PyCapsule_GetPointer(capsule, NULL);
+	copy_tv(v, tv);
+    }
+    return 0;
+}
+
+    static int
+ConvertFromPyObject(PyObject *obj, typval_T *tv)
+{
+    PyObject	*lookup_dict;
+    int		r;
+
+    lookup_dict = PyDict_New();
+    r = _ConvertFromPyObject(obj, tv, lookup_dict);
+    Py_DECREF(lookup_dict);
+    return r;
+}
+
+    static int
+_ConvertFromPyObject(PyObject *obj, typval_T *tv, PyObject *lookupDict)
+{
+    if (obj->ob_type == &DictionaryType)
+    {
+	tv->v_type = VAR_DICT;
+	tv->vval.v_dict = (((DictionaryObject *)(obj))->dict);
+	++tv->vval.v_dict->dv_refcount;
+    }
+    else if (obj->ob_type == &ListType)
+    {
+	tv->v_type = VAR_LIST;
+	tv->vval.v_list = (((ListObject *)(obj))->list);
+	++tv->vval.v_list->lv_refcount;
+    }
+    else if (obj->ob_type == &FunctionType)
+    {
+	if (set_string_copy(((FunctionObject *) (obj))->name, tv) == -1)
+	    return -1;
+
+	tv->v_type = VAR_FUNC;
+	func_ref(tv->vval.v_string);
+    }
+#if PY_MAJOR_VERSION >= 3
+    else if (PyBytes_Check(obj))
+    {
+	char_u	*result = (char_u *) PyBytes_AsString(obj);
+
+	if (result == NULL)
+	    return -1;
+
+	if (set_string_copy(result, tv) == -1)
+	    return -1;
+
+	tv->v_type = VAR_STRING;
+    }
+    else if (PyUnicode_Check(obj))
+    {
+	PyObject	*bytes;
+	char_u	*result;
+
+	bytes = PyString_AsBytes(obj);
+	if (bytes == NULL)
+	    return -1;
+
+	result = (char_u *) PyBytes_AsString(bytes);
+	if (result == NULL)
+	    return -1;
+
+	if (set_string_copy(result, tv) == -1)
+	{
+	    Py_XDECREF(bytes);
+	    return -1;
+	}
+	Py_XDECREF(bytes);
+
+	tv->v_type = VAR_STRING;
+    }
+#else
+    else if (PyUnicode_Check(obj))
+    {
+	PyObject	*bytes;
+	char_u	*result;
+
+	bytes = PyUnicode_AsEncodedString(obj, (char *)ENC_OPT, NULL);
+	if (bytes == NULL)
+	    return -1;
+
+	result=(char_u *) PyString_AsString(bytes);
+	if (result == NULL)
+	    return -1;
+
+	if (set_string_copy(result, tv) == -1)
+	{
+	    Py_XDECREF(bytes);
+	    return -1;
+	}
+	Py_XDECREF(bytes);
+
+	tv->v_type = VAR_STRING;
+    }
+    else if (PyString_Check(obj))
+    {
+	char_u	*result = (char_u *) PyString_AsString(obj);
+
+	if (result == NULL)
+	    return -1;
+
+	if (set_string_copy(result, tv) == -1)
+	    return -1;
+
+	tv->v_type = VAR_STRING;
+    }
+    else if (PyInt_Check(obj))
+    {
+	tv->v_type = VAR_NUMBER;
+	tv->vval.v_number = (varnumber_T) PyInt_AsLong(obj);
+    }
+#endif
+    else if (PyLong_Check(obj))
+    {
+	tv->v_type = VAR_NUMBER;
+	tv->vval.v_number = (varnumber_T) PyLong_AsLong(obj);
+    }
+    else if (PyDict_Check(obj))
+	return convert_dl(obj, tv, pydict_to_tv, lookupDict);
+#ifdef FEAT_FLOAT
+    else if (PyFloat_Check(obj))
+    {
+	tv->v_type = VAR_FLOAT;
+	tv->vval.v_float = (float_T) PyFloat_AsDouble(obj);
+    }
+#endif
+    else if (PyIter_Check(obj))
+	return convert_dl(obj, tv, pyiter_to_tv, lookupDict);
+    else if (PySequence_Check(obj))
+	return convert_dl(obj, tv, pyseq_to_tv, lookupDict);
+    else if (PyMapping_Check(obj))
+	return convert_dl(obj, tv, pymap_to_tv, lookupDict);
+    else
+    {
+	PyErr_SetString(PyExc_TypeError, _("unable to convert to vim structure"));
+	return -1;
+    }
+    return 0;
+}
+
+    static PyObject *
+ConvertToPyObject(typval_T *tv)
+{
+    if (tv == NULL)
+    {
+	PyErr_SetVim(_("NULL reference passed"));
+	return NULL;
+    }
+    switch (tv->v_type)
+    {
+	case VAR_STRING:
+	    return PyBytes_FromString((char *) tv->vval.v_string);
+	case VAR_NUMBER:
+	    return PyLong_FromLong((long) tv->vval.v_number);
+#ifdef FEAT_FLOAT
+	case VAR_FLOAT:
+	    return PyFloat_FromDouble((double) tv->vval.v_float);
+#endif
+	case VAR_LIST:
+	    return ListNew(tv->vval.v_list);
+	case VAR_DICT:
+	    return DictionaryNew(tv->vval.v_dict);
+	case VAR_FUNC:
+	    return FunctionNew(tv->vval.v_string);
+	case VAR_UNKNOWN:
+	    Py_INCREF(Py_None);
+	    return Py_None;
+	default:
+	    PyErr_SetVim(_("internal error: invalid value type"));
+	    return NULL;
+    }
+}
+#endif