diff options
author | Bram Moolenaar <Bram@vim.org> | 2012-06-29 12:54:53 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2012-06-29 12:54:53 +0200 |
commit | db91395312a02527ed973c8376d8e26e5b63ff53 (patch) | |
tree | 90f069389936dc2f2c8eb9ae8885ed68d1c336fb /src | |
parent | a7014df97532a4171276aa7e3b878e80e88e513c (diff) |
updated for version 7.3.569v7.3.569
Problem: Evaluating Vim expression in Python is insufficient.
Solution: Add vim.bindeval(). Also add pyeval() and py3eval(). (ZyX)
Diffstat (limited to 'src')
-rw-r--r-- | src/eval.c | 153 | ||||
-rw-r--r-- | src/if_lua.c | 148 | ||||
-rw-r--r-- | src/if_py_both.h | 1087 | ||||
-rw-r--r-- | src/if_python.c | 336 | ||||
-rw-r--r-- | src/if_python3.c | 391 | ||||
-rw-r--r-- | src/proto/eval.pro | 12 | ||||
-rw-r--r-- | src/proto/if_python.pro | 2 | ||||
-rw-r--r-- | src/proto/if_python3.pro | 2 | ||||
-rw-r--r-- | src/testdir/Make_amiga.mak | 1 | ||||
-rw-r--r-- | src/testdir/Make_dos.mak | 2 | ||||
-rw-r--r-- | src/testdir/Make_ming.mak | 2 | ||||
-rw-r--r-- | src/testdir/Make_os2.mak | 1 | ||||
-rw-r--r-- | src/testdir/Makefile | 2 | ||||
-rw-r--r-- | src/testdir/test86.in | 211 | ||||
-rw-r--r-- | src/testdir/test86.ok | 47 | ||||
-rw-r--r-- | src/testdir/test87.in | 211 | ||||
-rw-r--r-- | src/testdir/test87.ok | 47 | ||||
-rw-r--r-- | src/version.c | 2 |
18 files changed, 2413 insertions, 244 deletions
diff --git a/src/eval.c b/src/eval.c index 1b28200664..b2ab0adf06 100644 --- a/src/eval.c +++ b/src/eval.c @@ -424,30 +424,21 @@ static int get_string_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate)); static int get_lit_string_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate)); static int get_list_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate)); static int rettv_list_alloc __ARGS((typval_T *rettv)); -static listitem_T *listitem_alloc __ARGS((void)); static void listitem_free __ARGS((listitem_T *item)); -static void listitem_remove __ARGS((list_T *l, listitem_T *item)); static long list_len __ARGS((list_T *l)); static int list_equal __ARGS((list_T *l1, list_T *l2, int ic, int recursive)); static int dict_equal __ARGS((dict_T *d1, dict_T *d2, int ic, int recursive)); static int tv_equal __ARGS((typval_T *tv1, typval_T *tv2, int ic, int recursive)); -static listitem_T *list_find __ARGS((list_T *l, long n)); static long list_find_nr __ARGS((list_T *l, long idx, int *errorp)); static long list_idx_of_item __ARGS((list_T *l, listitem_T *item)); -static void list_append __ARGS((list_T *l, listitem_T *item)); static int list_append_number __ARGS((list_T *l, varnumber_T n)); -static int list_insert_tv __ARGS((list_T *l, typval_T *tv, listitem_T *item)); static int list_extend __ARGS((list_T *l1, list_T *l2, listitem_T *bef)); static int list_concat __ARGS((list_T *l1, list_T *l2, typval_T *tv)); static list_T *list_copy __ARGS((list_T *orig, int deep, int copyID)); -static void list_remove __ARGS((list_T *l, listitem_T *item, listitem_T *item2)); static char_u *list2string __ARGS((typval_T *tv, int copyID)); static int list_join_inner __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo_style, int copyID, garray_T *join_gap)); static int list_join __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo, int copyID)); static int free_unref_items __ARGS((int copyID)); -static void set_ref_in_ht __ARGS((hashtab_T *ht, int copyID)); -static void set_ref_in_list __ARGS((list_T *l, int copyID)); -static void set_ref_in_item __ARGS((typval_T *tv, int copyID)); static int rettv_dict_alloc __ARGS((typval_T *rettv)); static void dict_free __ARGS((dict_T *d, int recurse)); static dictitem_T *dictitem_copy __ARGS((dictitem_T *org)); @@ -654,6 +645,12 @@ static void f_pow __ARGS((typval_T *argvars, typval_T *rettv)); static void f_prevnonblank __ARGS((typval_T *argvars, typval_T *rettv)); static void f_printf __ARGS((typval_T *argvars, typval_T *rettv)); static void f_pumvisible __ARGS((typval_T *argvars, typval_T *rettv)); +#ifdef FEAT_PYTHON3 +static void f_py3eval __ARGS((typval_T *argvars, typval_T *rettv)); +#endif +#ifdef FEAT_PYTHON +static void f_pyeval __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_range __ARGS((typval_T *argvars, typval_T *rettv)); static void f_readfile __ARGS((typval_T *argvars, typval_T *rettv)); static void f_reltime __ARGS((typval_T *argvars, typval_T *rettv)); @@ -824,8 +821,6 @@ static int script_autoload __ARGS((char_u *name, int reload)); static char_u *autoload_name __ARGS((char_u *name)); static void cat_func_name __ARGS((char_u *buf, ufunc_T *fp)); static void func_free __ARGS((ufunc_T *fp)); -static void func_unref __ARGS((char_u *name)); -static void func_ref __ARGS((char_u *name)); static void call_user_func __ARGS((ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, linenr_T firstline, linenr_T lastline, dict_T *selfdict)); static int can_free_funccal __ARGS((funccall_T *fc, int copyID)) ; static void free_funccal __ARGS((funccall_T *fc, int free_val)); @@ -5927,7 +5922,7 @@ list_free(l, recurse) /* * Allocate a list item. */ - static listitem_T * + listitem_T * listitem_alloc() { return (listitem_T *)alloc(sizeof(listitem_T)); @@ -5947,7 +5942,7 @@ listitem_free(item) /* * Remove a list item from a List and free it. Also clears the value. */ - static void + void listitem_remove(l, item) list_T *l; listitem_T *item; @@ -6123,7 +6118,7 @@ tv_equal(tv1, tv2, ic, recursive) * A negative index is counted from the end; -1 is the last item. * Returns NULL when "n" is out of range. */ - static listitem_T * + listitem_T * list_find(l, n) list_T *l; long n; @@ -6265,7 +6260,7 @@ list_idx_of_item(l, item) /* * Append item "item" to the end of list "l". */ - static void + void list_append(l, item) list_T *l; listitem_T *item; @@ -6378,7 +6373,7 @@ list_append_number(l, n) * If "item" is NULL append at the end. * Return FAIL when out of memory. */ - static int + int list_insert_tv(l, tv, item) list_T *l; typval_T *tv; @@ -6523,7 +6518,7 @@ list_copy(orig, deep, copyID) * Remove items "item" to "item2" from list "l". * Does not free the listitem or the value! */ - static void + void list_remove(l, item, item2) list_T *l; listitem_T *item; @@ -6785,6 +6780,14 @@ garbage_collect() set_ref_in_lua(copyID); #endif +#ifdef FEAT_PYTHON + set_ref_in_python(copyID); +#endif + +#ifdef FEAT_PYTHON3 + set_ref_in_python3(copyID); +#endif + /* * 2. Free lists and dictionaries that are not referenced. */ @@ -6870,7 +6873,7 @@ free_unref_items(copyID) /* * Mark all lists and dicts referenced through hashtab "ht" with "copyID". */ - static void + void set_ref_in_ht(ht, copyID) hashtab_T *ht; int copyID; @@ -6890,7 +6893,7 @@ set_ref_in_ht(ht, copyID) /* * Mark all lists and dicts referenced through list "l" with "copyID". */ - static void + void set_ref_in_list(l, copyID) list_T *l; int copyID; @@ -6904,7 +6907,7 @@ set_ref_in_list(l, copyID) /* * Mark all lists and dicts referenced through typval "tv" with "copyID". */ - static void + void set_ref_in_item(tv, copyID) typval_T *tv; int copyID; @@ -7986,6 +7989,12 @@ static struct fst {"prevnonblank", 1, 1, f_prevnonblank}, {"printf", 2, 19, f_printf}, {"pumvisible", 0, 0, f_pumvisible}, +#ifdef FEAT_PYTHON3 + {"py3eval", 1, 1, f_py3eval}, +#endif +#ifdef FEAT_PYTHON + {"pyeval", 1, 1, f_pyeval}, +#endif {"range", 1, 3, f_range}, {"readfile", 1, 3, f_readfile}, {"reltime", 0, 2, f_reltime}, @@ -9150,6 +9159,45 @@ f_byteidx(argvars, rettv) #endif } + int +func_call(name, args, selfdict, rettv) + char_u *name; + typval_T *args; + dict_T *selfdict; + typval_T *rettv; +{ + listitem_T *item; + typval_T argv[MAX_FUNC_ARGS + 1]; + int argc = 0; + int dummy; + int r = 0; + + for (item = args->vval.v_list->lv_first; item != NULL; + item = item->li_next) + { + if (argc == MAX_FUNC_ARGS) + { + EMSG(_("E699: Too many arguments")); + break; + } + /* Make a copy of each argument. This is needed to be able to set + * v_lock to VAR_FIXED in the copy without changing the original list. + */ + copy_tv(&item->li_tv, &argv[argc++]); + } + + if (item == NULL) + r = call_func(name, (int)STRLEN(name), rettv, argc, argv, + curwin->w_cursor.lnum, curwin->w_cursor.lnum, + &dummy, TRUE, selfdict); + + /* Free the arguments. */ + while (argc > 0) + clear_tv(&argv[--argc]); + + return r; +} + /* * "call(func, arglist)" function */ @@ -9159,10 +9207,6 @@ f_call(argvars, rettv) typval_T *rettv; { char_u *func; - typval_T argv[MAX_FUNC_ARGS + 1]; - int argc = 0; - listitem_T *item; - int dummy; dict_T *selfdict = NULL; if (argvars[1].v_type != VAR_LIST) @@ -9190,28 +9234,7 @@ f_call(argvars, rettv) selfdict = argvars[2].vval.v_dict; } - for (item = argvars[1].vval.v_list->lv_first; item != NULL; - item = item->li_next) - { - if (argc == MAX_FUNC_ARGS) - { - EMSG(_("E699: Too many arguments")); - break; - } - /* Make a copy of each argument. This is needed to be able to set - * v_lock to VAR_FIXED in the copy without changing the original list. - */ - copy_tv(&item->li_tv, &argv[argc++]); - } - - if (item == NULL) - (void)call_func(func, (int)STRLEN(func), rettv, argc, argv, - curwin->w_cursor.lnum, curwin->w_cursor.lnum, - &dummy, TRUE, selfdict); - - /* Free the arguments. */ - while (argc > 0) - clear_tv(&argv[--argc]); + (void)func_call(func, &argvars[1], selfdict, rettv); } #ifdef FEAT_FLOAT @@ -14424,6 +14447,40 @@ f_pumvisible(argvars, rettv) #endif } +#ifdef FEAT_PYTHON3 +/* + * "py3eval()" function + */ + static void +f_py3eval(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + char_u *str; + char_u buf[NUMBUFLEN]; + + str = get_tv_string_buf(&argvars[0], buf); + do_py3eval(str, rettv); +} +#endif + +#ifdef FEAT_PYTHON +/* + * "pyeval()" function + */ + static void +f_pyeval(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + char_u *str; + char_u buf[NUMBUFLEN]; + + str = get_tv_string_buf(&argvars[0], buf); + do_pyeval(str, rettv); +} +#endif + /* * "range()" function */ @@ -22139,7 +22196,7 @@ func_free(fp) * Unreference a Function: decrement the reference count and free it when it * becomes zero. Only for numbered functions. */ - static void + void func_unref(name) char_u *name; { @@ -22163,7 +22220,7 @@ func_unref(name) /* * Count a reference to a Function. */ - static void + void func_ref(name) char_u *name; { diff --git a/src/if_lua.c b/src/if_lua.c index ea6d1bd504..e873b6bf77 100644 --- a/src/if_lua.c +++ b/src/if_lua.c @@ -199,9 +199,9 @@ int (*dll_lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); lua_Number (*dll_lua_tonumberx) (lua_State *L, int idx, int *isnum); lua_Integer (*dll_lua_tointegerx) (lua_State *L, int idx, int *isnum); void (*dll_lua_callk) (lua_State *L, int nargs, int nresults, int ctx, - lua_CFunction k); + lua_CFunction k); int (*dll_lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, - int ctx, lua_CFunction k); + int ctx, lua_CFunction k); void (*dll_lua_getglobal) (lua_State *L, const char *var); void (*dll_lua_setglobal) (lua_State *L, const char *var); #endif @@ -394,7 +394,7 @@ lua_enabled(int verbose) luaL_typeerror (lua_State *L, int narg, const char *tname) { const char *msg = lua_pushfstring(L, "%s expected, got %s", - tname, luaL_typename(L, narg)); + tname, luaL_typename(L, narg)); return luaL_argerror(L, narg, msg); } #endif @@ -646,141 +646,6 @@ luaV_msgfunc(lua_State *L, msgfunc_T mf) return 1; \ } - -/* adapted from eval.c */ - -#define listitem_alloc() (listitem_T *)alloc(sizeof(listitem_T)) - - static listitem_T * -list_find (list_T *l, long n) -{ - listitem_T *li; - if (l == NULL || n < -l->lv_len || n >= l->lv_len) - return NULL; - if (n < 0) /* search backward? */ - for (li = l->lv_last; n < -1; li = li->li_prev) - n++; - else /* search forward */ - for (li = l->lv_first; n > 0; li = li->li_next) - n--; - return li; -} - - static void -list_remove (list_T *l, listitem_T *li) -{ - listwatch_T *lw; - --l->lv_len; - /* fix watchers */ - for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next) - if (lw->lw_item == li) - lw->lw_item = li->li_next; - /* fix list pointers */ - if (li->li_next == NULL) /* last? */ - l->lv_last = li->li_prev; - else - li->li_next->li_prev = li->li_prev; - if (li->li_prev == NULL) /* first? */ - l->lv_first = li->li_next; - else - li->li_prev->li_next = li->li_next; - l->lv_idx_item = NULL; -} - - static void -list_append(list_T *l, listitem_T *item) -{ - if (l->lv_last == NULL) /* empty list? */ - l->lv_first = item; - else - l->lv_last->li_next = item; - item->li_prev = l->lv_last; - item->li_next = NULL; - l->lv_last = item; - ++l->lv_len; -} - - static int -list_insert_tv(list_T *l, typval_T *tv, listitem_T *item) -{ - listitem_T *ni = listitem_alloc(); - - if (ni == NULL) - return FAIL; - copy_tv(tv, &ni->li_tv); - if (item == NULL) - list_append(l, ni); - else - { - ni->li_prev = item->li_prev; - ni->li_next = item; - if (item->li_prev == NULL) - { - l->lv_first = ni; - ++l->lv_idx; - } - else - { - item->li_prev->li_next = ni; - l->lv_idx_item = NULL; - } - item->li_prev = ni; - ++l->lv_len; - } - return OK; -} - -/* set references */ - -static void set_ref_in_tv (typval_T *tv, int copyID); - - static void -set_ref_in_dict(dict_T *d, int copyID) -{ - hashtab_T *ht = &d->dv_hashtab; - int n = ht->ht_used; - hashitem_T *hi; - for (hi = ht->ht_array; n > 0; ++hi) - if (!HASHITEM_EMPTY(hi)) - { - dictitem_T *di = dict_lookup(hi); - set_ref_in_tv(&di->di_tv, copyID); - --n; - } -} - - static void -set_ref_in_list(list_T *l, int copyID) -{ - listitem_T *li; - for (li = l->lv_first; li != NULL; li = li->li_next) - set_ref_in_tv(&li->li_tv, copyID); -} - - static void -set_ref_in_tv(typval_T *tv, int copyID) -{ - if (tv->v_type == VAR_LIST) - { - list_T *l = tv->vval.v_list; - if (l != NULL && l->lv_copyID != copyID) - { - l->lv_copyID = copyID; - set_ref_in_list(l, copyID); - } - } - else if (tv->v_type == VAR_DICT) - { - dict_T *d = tv->vval.v_dict; - if (d != NULL && d->dv_copyID != copyID) - { - d->dv_copyID = copyID; - set_ref_in_dict(d, copyID); - } - } -} - - /* ======= List type ======= */ static luaV_List * @@ -876,7 +741,7 @@ luaV_list_newindex (lua_State *L) if (li == NULL) return 0; if (lua_isnil(L, 3)) /* remove? */ { - list_remove(l, li); + list_remove(l, li, li); clear_tv(&li->li_tv); vim_free(li); } @@ -904,8 +769,7 @@ luaV_list_add (lua_State *L) typval_T v; lua_settop(L, 2); luaV_totypval(L, 2, &v); - copy_tv(&v, &li->li_tv); - list_append(l, li); + list_append_tv(l, &v); } lua_settop(L, 1); return 1; @@ -1682,7 +1546,7 @@ luaV_setref (lua_State *L) tv.vval.v_dict = (dict_T *) lua_touserdata(L, 4); /* key */ } lua_pop(L, 2); /* metatable and value */ - set_ref_in_tv(&tv, copyID); + set_ref_in_item(&tv, copyID); } return 0; } diff --git a/src/if_py_both.h b/src/if_py_both.h index cbfbaa7673..f627f67af8 100644 --- 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, PyObject *args) 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, PyObject *args) 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 *lookupDict) { 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, PyObject *lookupDict) 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 *args UNUSED) #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) |