ZyX wrote:
> > No, since the patches are few and far between.
> 
> Pulling patches from the repository and saving them there is
> convenient. When I was adding third argument to sort() patch was also
> not big but I still cloned vim to bitbucket. This decision appeared to
> be right when I started to extend python interface.
> 
> Even if you don’t want to create commits, do use “hg diff”. Two
> patches for two files with requirement to switch to another directory
> before applying each one is very inconvenient.

OK, thanks for the suggestion. I'm attaching a patch generated by 'hg diff'.
To summarize the main changes:

- New funcref type, including new vim.funcref() function
- vim.dict() and vim.list() now accept an initializer table as argument
- Updated docs
- A few bug fixes (following this thread)


> > I don't think that's an error in if_lua: the documentation doesn't say
> > anything about dictionaries not allowing empty strings as keys -- :help
> > Dictionary only says that 'a key is always a String' -- and hence the 
> > absence
> > of error when printing d in your example. What is not allowed is for you to
> > read or set empty keys in Vim (using 'let'), but I don't want to replicate
> > that in if_lua. For instance, you can do this:
> >
> >   vim -u NONE -c 'let d={} | lua vim.eval("d")[""] = "empty"'
> >     -c 'for [k,v] in items(d) | echo "|".k."| -> ".v | endfor'
> >
> > So, to be consistent, if you set an empty key in if_lua, you can read or 
> > reset
> > it there.
> 
> Yes, you can do “for [k, v] in items(d)”. But you can’t do “for k in
> keys(d) | let v=d[k]”. I can’t prove that this won’t break anything,
> maybe you can?
> 
> Help does not mention this probably because error message is clear
> enough, I constantly see such things in a doc: “:h E???” exists, but
> in the text there is nothing concerning error message.

I agree that there must be a reason for the parser to avoid empty strings, but
then the documentation should change to reflect this behavior. Ideally this
behavior should be coded in the API, probably making dict_add check the
dictitem argument. While I still maintain that that's not an if_lua issue,
I've updated the code to check for empty keys when setting dict entries, just
in case it breaks something and for consistency.
 
> >> And you have missed another error:
> >>
> >>     vim -u NONE -c 'lua vim.eval("g:")["input"]=vim.funcref("tr")' -c 
> >> 'call input("Yes?")'
> >>
> >> results in an error “not enough arguments to tr” while it should result in 
> >> an error “funcref variables must start with a capital” (see my patch to 
> >> python interface [1] and extend() function [2]).
> >
> > There's no error here either. The problem is that tr() expects three
> > arguments, and not that the variable must start with a capital letter 
> > (g:input
> > already exists.) Try this:
> >
> >   vim -u NONE -c 'lua vim.eval("g:").input=vim.funcref("tolower")'
> >     -c 'echo input("Yes?")'
> 
> It is just an example. Vim has very weird way of disallowing
> overriding built-in and user functions: a check everywhere you can add
> a value to a dictionary. The fact that you *allow overriding built-in
> functions* is an error. Not the fact that “tr” expects three arguments
> or something else.
> 
> Existence of your behavior in lua interface and my in python (unlike
> my patch to extend() patch to if_py* was not merged) defeats the
> purpose of such checks.

Again, the issue here is not that funcref variables must start with a capital
letter -- only the parser should check that, not if_lua -- but that if_lua is
assigning funcrefs to a "builtin" scope dictionary (g: or l:). The fix is
straightforward: if_lua now checks if dict->dv_scope == VAR_DEF_SCOPE and if
the value is a funcref and complains if that's the case.

> > I think you're mixing the fact that Vim Funcref variables should start with 
> > a
> > capital letter. Funcrefs in lua are just a value; for instance, this should
> > work:
> >
> >   :lua print(vim.funcref"tr"("<tag>", "<>", "{}"))
> >   " {tag}
> 
> No, I am not. I do not care how you can name funcrefs in lua, you must
> not allow using lua to override built-in or user functions by adding
> something to scope dictionary. The proper way of fixing this all is
> modifying parser, but modifying lua interface is much simpler. If you

As I said, you shouldn't really care about Lua "naming" funcrefs, since that's
a moot point (funcrefs in Lua are just values, they have no names.) But you're
right that the issue is checking for the dictionary to be a scope; see comment
above.

> can modify the parser go ahead and get rid of E704 and E705: in the
> current state there is exactly no way to safely assign funcref to a
> variable, only to dictionary key/list item. I can see why parser does
> this (deref_func_name: it first tries to get a funcref variable and
> returns name as-is in case of failure), but unsure how to fix it
> properly (quick fix is returning name as-is if find_internal_func
> returned something other than -1 or find_func — other than NULL). I
> also don’t think this fix will be accepted by Bram: it only pretends
> to solve a problem as now masking functions by variables is replaced
> by masking variables by a functions:
> 
>     let input="abc"
> may work properly but
> 
>     function Input()
>         return getchar()
>     endfunction
>     let Input=function('input')
>     call Input("abc")
> won’t.

You lost me in this last example and the masking comment, but I believe I do
not need to change the parser (and shouldn't need to.)

ZyX wrote:
> > Right. I think you meant:
> > 
> >   :lua vim.eval('g:').list = vim.list{'abc'}
> > 
> > or
> > 
> >   :lua vim.eval('g:').dict = vim.dict{key = 'abc'}
> > 
> > since you forgot the key.
> 
> No, I meant exactly what I typed. Before reading docs expected behavior was 
> either converting it to “{"1": "abc"}” or an error.

Ah, I see: you wanted to check for an error since {'abc'} is not valid in Vim.
I've changed the behavior to be more in line with Lua (and Vim) since numbers
are usually converted to strings: now vim.dict{'abc'} returns {'1': 'abc'}.

Thanks once again for your feedback and thorough tests!

Cheers,
Luis

-- 
Computers are useless. They can only give you answers.
                -- Pablo Picasso

-- 
Luis Carvalho (Kozure)
lua -e 'print((("[email protected]"):gsub("(%u+%.)","")))'

-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
diff -r 8187706695fc runtime/doc/if_lua.txt
--- a/runtime/doc/if_lua.txt	Thu Aug 23 22:28:46 2012 +0200
+++ b/runtime/doc/if_lua.txt	Sat Sep 01 19:49:05 2012 -0400
@@ -10,9 +10,10 @@
 2. The vim module		|lua-vim|
 3. List userdata		|lua-list|
 4. Dict userdata		|lua-dict|
-5. Buffer userdata		|lua-buffer|
-6. Window userdata		|lua-window|
-7. The luaeval function		|lua-luaeval|
+5. Funcref userdata		|lua-funcref|
+6. Buffer userdata		|lua-buffer|
+7. Window userdata		|lua-window|
+8. The luaeval function		|lua-luaeval|
 
 {Vi does not have any of these commands}
 
@@ -110,9 +111,31 @@
 module also includes routines for buffer, window, and current line queries,
 Vim evaluation and command execution, and others.
 
-	vim.list()		Returns an empty list (see |List|).
-
-	vim.dict()		Returns an empty dictionary (see |Dictionary|).
+	vim.list([arg])		Returns an empty list or, if "arg" is a Lua
+				table with numeric keys 1, ..., n (a
+				"sequence"), returns a list l such that l[i] =
+				arg[i] for i = 1, ..., n (see |List|).
+				Non-numeric keys are not used to initialize
+				the list. See also |lua-eval| for conversion
+				rules. Example: >
+					:lua t = {math.pi, false, say = 'hi'}
+					:echo luaeval('vim.list(t)')
+					:" [3.141593, 0], 'say' is ignored
+<
+	vim.dict([arg])		Returns an empty dictionary or, if "arg" is a
+				Lua table, returns a dict d such that d[k] =
+				arg[k] for all string keys k in "arg" (see
+				|Dictionary|). Number keys are converted to
+				strings. Keys that are not strings are not
+				used to initialize the dictionary. See also
+				|lua-eval| for conversion rules. Example: >
+					:lua t = {math.pi, false, say = 'hi'}
+					:echo luaeval('vim.dict(t)')
+					:" {'say': 'hi'}, numeric keys ignored
+<
+	vim.funcref({name})	Returns a Funcref to function {name} (see
+				|Funcref|). It is equivalent to Vim's
+				"function".
 
 	vim.buffer([arg])	If "arg" is a number, returns buffer with
 				number "arg" in the buffer list or, if "arg"
@@ -131,9 +154,9 @@
 
 	vim.type({arg})		Returns the type of {arg}. It is equivalent to
 				Lua's "type" function, but returns "list",
-				"dict", "buffer", or "window" if {arg} is a
-				list, dictionary, buffer, or window,
-				respectively. Examples: >
+				"dict", "funcref", "buffer", or "window" if
+				{arg} is a list, dictionary, funcref, buffer,
+				or window, respectively. Examples: >
 					:lua l = vim.list()
 					:lua print(type(l), vim.type(l))
 					:" userdata list
@@ -229,7 +252,40 @@
 <
 
 ==============================================================================
-5. Buffer userdata					*lua-buffer*
+5. Funcref userdata					*lua-funcref*
+
+Funcref userdata represent funcref variables in Vim. Funcrefs that were
+defined with a "dict" attribute need to be obtained as a dictionary key
+in order to have "self" properly assigned to the dictionary (see examples
+below.) A funcref "f" has the following properties:
+
+Properties
+----------
+	o "#f" is the name of the function referenced by "f"
+	o "f(...)" calls the function referenced by "f" (with arguments)
+
+Examples:
+>
+	:function I(x)
+	:  return a:x
+	:  endfunction
+	:let R = function('I')
+	:lua i1 = vim.funcref('I')
+	:lua i2 = vim.eval('R')
+	:lua print(#i1, #i2) -- both 'I'
+	:lua print(i1, i2, #i2(i1) == #i1(i2))
+	:function Mylen() dict
+	:  return len(self.data)
+	:  endfunction
+	:let mydict = {'data': [0, 1, 2, 3]}
+	:lua d = vim.eval('mydict'); d.len = vim.funcref('Mylen')
+	:echo mydict.len()
+	:lua l = d.len -- assign d as 'self'
+	:lua print(l())
+<
+
+==============================================================================
+6. Buffer userdata					*lua-buffer*
 
 Buffer userdata represent vim buffers. A buffer userdata "b" has the following
 properties and methods:
@@ -281,7 +337,7 @@
 <
 
 ==============================================================================
-6. Window userdata					*lua-window*
+7. Window userdata					*lua-window*
 
 Window objects represent vim windows. A window userdata "w" has the following
 properties and methods:
@@ -313,7 +369,7 @@
 <
 
 ==============================================================================
-7. The luaeval function					*lua-luaeval* *lua-eval*
+8. The luaeval function					*lua-luaeval* *lua-eval*
 
 The (dual) equivalent of "vim.eval" for passing Lua values to Vim is
 "luaeval". "luaeval" takes an expression string and an optional argument and
@@ -325,7 +381,13 @@
 	    return chunk(arg) -- return typval
 	end
 <
-Note that "_A" receives the argument to "luaeval". Examples: >
+Note that "_A" receives the argument to "luaeval". Lua numbers, strings, and
+list, dict, and funcref userdata are converted to their Vim respective types,
+while Lua booleans are converted to numbers. An error is thrown if conversion
+of any of the remaining Lua types, including userdata other than lists, dicts,
+and funcrefs, is attempted.
+
+Examples: >
 
 	:echo luaeval('math.pi')
 	:lua a = vim.list():add('newlist')
diff -r 8187706695fc runtime/doc/tags
--- a/runtime/doc/tags	Thu Aug 23 22:28:46 2012 +0200
+++ b/runtime/doc/tags	Sat Sep 01 19:49:05 2012 -0400
@@ -6617,6 +6617,7 @@
 lua-commands	if_lua.txt	/*lua-commands*
 lua-dict	if_lua.txt	/*lua-dict*
 lua-eval	if_lua.txt	/*lua-eval*
+lua-funcref	if_lua.txt	/*lua-funcref*
 lua-list	if_lua.txt	/*lua-list*
 lua-luaeval	if_lua.txt	/*lua-luaeval*
 lua-vim	if_lua.txt	/*lua-vim*
diff -r 8187706695fc src/if_lua.c
--- a/src/if_lua.c	Thu Aug 23 22:28:46 2012 +0200
+++ b/src/if_lua.c	Sat Sep 01 19:49:05 2012 -0400
@@ -28,10 +28,16 @@
 typedef win_T *luaV_Window;
 typedef dict_T *luaV_Dict;
 typedef list_T *luaV_List;
+typedef struct {
+    typval_T tv; /* funcref */
+    typval_T args;
+    dict_T *self; /* selfdict */
+} luaV_Funcref;
 typedef void (*msgfunc_T)(char_u *);
 
 static const char LUAVIM_DICT[] = "dict";
 static const char LUAVIM_LIST[] = "list";
+static const char LUAVIM_FUNCREF[] = "funcref";
 static const char LUAVIM_BUFFER[] = "buffer";
 static const char LUAVIM_WINDOW[] = "window";
 static const char LUAVIM_FREE[] = "luaV_free";
@@ -55,9 +61,15 @@
     if (sandbox) luaL_error((L), "not allowed in sandbox")
 #define luaV_msg(L) luaV_msgfunc((L), (msgfunc_T) msg)
 #define luaV_emsg(L) luaV_msgfunc((L), (msgfunc_T) emsg)
+#define luaV_checktypval(L,a,v,msg) \
+    do { \
+        if (luaV_totypval(L, a, v) == FAIL) \
+	    luaL_error(L, msg ": cannot convert value"); \
+    } while (0)
 
 static luaV_List *luaV_pushlist (lua_State *L, list_T *lis);
 static luaV_Dict *luaV_pushdict (lua_State *L, dict_T *dic);
+static luaV_Funcref *luaV_pushfuncref (lua_State *L, typval_T *tv);
 
 #if LUA_VERSION_NUM <= 501
 #define luaV_openlib(L, l, n) luaL_openlib(L, NULL, l, n)
@@ -480,15 +492,19 @@
 	case VAR_DICT:
 	    luaV_pushdict(L, tv->vval.v_dict);
 	    break;
+	case VAR_FUNC:
+	    luaV_pushfuncref(L, tv);
+	    break;
 	default:
 	    lua_pushnil(L);
     }
 }
 
-/* converts lua value at 'pos' to typval 'tv' */
-    static void
+/* converts lua value at 'pos' to typval 'tv'; returns OK or FAIL */
+    static int
 luaV_totypval (lua_State *L, int pos, typval_T *tv)
 {
+    int status = OK;
     switch(lua_type(L, pos)) {
 	case LUA_TBOOLEAN:
 	    tv->v_type = VAR_NUMBER;
@@ -531,14 +547,25 @@
 		    lua_pop(L, 3); /* MTs */
 		    return;
 		}
-		lua_pop(L, 3); /* MTs */
+		/* check funcref */
+		luaV_getfield(L, LUAVIM_FUNCREF);
+		if (lua_rawequal(L, -1, -4))
+		{
+		    luaV_Funcref *f = (luaV_Funcref *) p;
+		    copy_tv(&f->tv, tv);
+		    lua_pop(L, 4); /* MTs */
+		    return;
+		}
+		lua_pop(L, 4); /* MTs */
 	    }
-	    break;
+	/* unknown userdata: fall through */
 	}
 	default:
 	    tv->v_type = VAR_NUMBER;
 	    tv->vval.v_number = 0;
+	    status = FAIL;
     }
+    return status;
 }
 
 /* similar to luaL_addlstring, but replaces \0 with \n if toline and
@@ -646,6 +673,7 @@
 	return 1; \
     }
 
+
 /* =======   List type   ======= */
 
     static luaV_List *
@@ -748,7 +776,7 @@
     else
     {
 	typval_T v;
-	luaV_totypval(L, 3, &v);
+	luaV_checktypval(L, 3, &v, "setting list item");
 	clear_tv(&li->li_tv);
 	copy_tv(&v, &li->li_tv);
     }
@@ -760,17 +788,12 @@
 {
     luaV_List *lis = luaV_checkudata(L, 1, LUAVIM_LIST);
     list_T *l = (list_T *) luaV_checkcache(L, (void *) *lis);
-    listitem_T *li;
+    typval_T v;
     if (l->lv_lock)
 	luaL_error(L, "list is locked");
-    li = listitem_alloc();
-    if (li != NULL)
-    {
-	typval_T v;
-	lua_settop(L, 2);
-	luaV_totypval(L, 2, &v);
-	list_append_tv(l, &v);
-    }
+    lua_settop(L, 2);
+    luaV_checktypval(L, 2, &v, "adding list item");
+    list_append_tv(l, &v);
     lua_settop(L, 1);
     return 1;
 }
@@ -792,7 +815,7 @@
 	    luaL_error(L, "invalid position");
     }
     lua_settop(L, 2);
-    luaV_totypval(L, 2, &v);
+    luaV_checktypval(L, 2, &v, "inserting list item");
     list_insert_tv(l, &v, li);
     lua_settop(L, 1);
     return 1;
@@ -881,8 +904,14 @@
     dictitem_T *di = dict_find(d, key, -1);
     if (di == NULL)
 	lua_pushnil(L);
-    else
+    else {
 	luaV_pushtypval(L, &di->di_tv);
+	if (di->di_tv.v_type == VAR_FUNC) { /* funcref? */
+	    luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, -1);
+	    f->self = d; /* keep "self" reference */
+	    d->dv_refcount++;
+	}
+    }
     return 1;
 }
 
@@ -892,8 +921,14 @@
     dict_T *d = luaV_unbox(L, luaV_Dict, 1);
     char_u *key = (char_u *) luaL_checkstring(L, 2);
     dictitem_T *di;
+    typval_T v;
     if (d->dv_lock)
 	luaL_error(L, "dict is locked");
+    if (key != NULL && *key == NUL)
+	luaL_error(L, "empty key");
+    luaV_checktypval(L, 3, &v, "setting dict item");
+    if (d->dv_scope == VAR_DEF_SCOPE && v.v_type == VAR_FUNC)
+	luaL_error(L, "cannot assign funcref to builtin scope");
     di = dict_find(d, key, -1);
     if (di == NULL) /* non-existing key? */
     {
@@ -914,11 +949,8 @@
 	hash_remove(&d->dv_hashtab, hi);
 	dictitem_free(di);
     }
-    else {
-	typval_T v;
-	luaV_totypval(L, 3, &v);
+    else
 	copy_tv(&v, &di->di_tv);
-    }
     return 0;
 }
 
@@ -933,6 +965,88 @@
 };
 
 
+/* =======   Funcref type   ======= */
+
+    static luaV_Funcref *
+luaV_newfuncref (lua_State *L, char_u *name)
+{
+    luaV_Funcref *f = (luaV_Funcref *) lua_newuserdata(L,
+	    sizeof(luaV_Funcref));
+    if (name != NULL) {
+	func_ref(name); /* as in copy_tv */
+	f->tv.vval.v_string = vim_strsave(name);
+    }
+    f->tv.v_type = VAR_FUNC;
+    f->args.v_type = VAR_LIST;
+    f->self = NULL;
+    luaV_getfield(L, LUAVIM_FUNCREF);
+    lua_setmetatable(L, -2);
+    return f;
+}
+
+    static luaV_Funcref *
+luaV_pushfuncref (lua_State *L, typval_T *tv)
+{
+    luaV_Funcref *f = luaV_newfuncref(L, NULL);
+    copy_tv(tv, &f->tv);
+    return f;
+}
+
+
+luaV_type_tostring(funcref, LUAVIM_FUNCREF)
+
+    static int
+luaV_funcref_gc (lua_State *L)
+{
+    luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
+    func_unref(f->tv.vval.v_string);
+    vim_free(f->tv.vval.v_string);
+    dict_unref(f->self);
+    return 0;
+}
+
+/* equivalent to string(funcref) */
+    static int
+luaV_funcref_len (lua_State *L)
+{
+    luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
+    lua_pushstring(L, (const char *) f->tv.vval.v_string);
+    return 1;
+}
+
+    static int
+luaV_funcref_call (lua_State *L)
+{
+    luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
+    int i, n = lua_gettop(L) - 1; /* #args */
+    int status;
+    typval_T v, rettv;
+    f->args.vval.v_list = list_alloc();
+    rettv.v_type = VAR_UNKNOWN; /* as in clear_tv */
+    for (i = 0; i < n; i++) {
+	luaV_checktypval(L, i + 2, &v, "calling funcref");
+	list_append_tv(f->args.vval.v_list, &v);
+    }
+    status = func_call(f->tv.vval.v_string, &f->args, f->self, &rettv);
+    if (status == OK)
+	luaV_pushtypval(L, &rettv);
+    clear_tv(&f->args);
+    clear_tv(&rettv);
+    if (status != OK)
+	luaL_error(L, "cannot call funcref");
+    return 1;
+}
+
+static const luaL_Reg luaV_Funcref_mt[] = {
+    {"__tostring", luaV_funcref_tostring},
+    {"__gc", luaV_funcref_gc},
+    {"__len", luaV_funcref_len},
+    {"__call", luaV_funcref_call},
+    {NULL, NULL}
+};
+
+
+
 /* =======   Buffer type   ======= */
 
 luaV_newtype(buf_T, buffer, luaV_Buffer, LUAVIM_BUFFER)
@@ -1354,22 +1468,77 @@
     static int
 luaV_list(lua_State *L)
 {
-    list_T *l = list_alloc();
+    list_T *l;
+    int initarg = !lua_isnoneornil(L, 1);
+    if (initarg && lua_type(L, 1) != LUA_TTABLE)
+	luaL_error(L, "table expected, got %s", luaL_typename(L, 1));
+    l = list_alloc();
     if (l == NULL)
 	lua_pushnil(L);
-    else
+    else {
 	luaV_newlist(L, l);
+	if (initarg) { /* traverse table to init dict */
+	    int notnil, i = 0;
+	    typval_T v;
+	    do {
+		lua_rawgeti(L, 1, ++i);
+		notnil = !lua_isnil(L, -1);
+		if (notnil) {
+		    luaV_checktypval(L, -1, &v, "vim.list");
+		    list_append_tv(l, &v);
+		}
+		lua_pop(L, 1); /* value */
+	    } while (notnil);
+	}
+    }
     return 1;
 }
 
     static int
 luaV_dict(lua_State *L)
 {
-    dict_T *d = dict_alloc();
+    dict_T *d;
+    int initarg = !lua_isnoneornil(L, 1);
+    if (initarg && lua_type(L, 1) != LUA_TTABLE)
+	luaL_error(L, "table expected, got %s", luaL_typename(L, 1));
+    d = dict_alloc();
     if (d == NULL)
 	lua_pushnil(L);
-    else
+    else {
 	luaV_newdict(L, d);
+	if (initarg) { /* traverse table to init dict */
+	    lua_pushnil(L);
+	    while (lua_next(L, 1)) {
+		char_u *key;
+		dictitem_T *di;
+		typval_T v;
+		lua_pushvalue(L, -2); /* dup key in case it's a number */
+		key = (char_u *) lua_tostring(L, -1);
+		if (key != NULL && *key == NUL)
+		    luaL_error(L, "table has empty key");
+		luaV_checktypval(L, -2, &v, "vim.dict"); /* value */
+		di = dictitem_alloc(key);
+		if (di == NULL || dict_add(d, di) == FAIL) {
+		    vim_free(di);
+		    lua_pushnil(L);
+		    return 1;
+		}
+		copy_tv(&v, &di->di_tv);
+		lua_pop(L, 2); /* key copy and value */
+	    }
+	}
+    }
+    return 1;
+}
+
+    static int
+luaV_funcref(lua_State *L)
+{
+    const char *name = luaL_checkstring(L, 1);
+    /* note: not checking if function exists (needs function_exists) */
+    if (name == NULL || *name == NUL || VIM_ISDIGIT(*name))
+	luaL_error(L, "invalid function name: %s", name);
+    luaV_newfuncref(L, (char_u *) name);
     return 1;
 }
 
@@ -1455,6 +1624,12 @@
 		lua_pushstring(L, "dict");
 		return 1;
 	    }
+	    luaV_getfield(L, LUAVIM_FUNCREF);
+	    if (lua_rawequal(L, -1, 2))
+	    {
+		lua_pushstring(L, "funcref");
+		return 1;
+	    }
 	    luaV_getfield(L, LUAVIM_BUFFER);
 	    if (lua_rawequal(L, -1, 2))
 	    {
@@ -1480,6 +1655,7 @@
     {"line", luaV_line},
     {"list", luaV_list},
     {"dict", luaV_dict},
+    {"funcref", luaV_funcref},
     {"buffer", luaV_buffer},
     {"window", luaV_window},
     {"open", luaV_open},
@@ -1520,7 +1696,8 @@
 	luaV_emsg(L);
 	return 0;
     }
-    luaV_totypval(L, -1, rettv);
+    if (luaV_totypval(L, -1, rettv) == FAIL)
+	emsg("luaeval: cannot convert value");
     return 0;
 }
 
@@ -1590,6 +1767,9 @@
     luaV_newmetatable(L, LUAVIM_DICT);
     lua_pushvalue(L, 1);
     luaV_openlib(L, luaV_Dict_mt, 1);
+    luaV_newmetatable(L, LUAVIM_FUNCREF);
+    lua_pushvalue(L, 1);
+    luaV_openlib(L, luaV_Funcref_mt, 1);
     luaV_newmetatable(L, LUAVIM_BUFFER);
     lua_pushvalue(L, 1); /* cache table */
     luaV_openlib(L, luaV_Buffer_mt, 1);

Raspunde prin e-mail lui