diff options
author | Bram Moolenaar <Bram@vim.org> | 2012-04-05 16:54:08 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2012-04-05 16:54:08 +0200 |
commit | 1dced5727f8f4f51fd623d9f6e672e70e1793d13 (patch) | |
tree | e1c77c699008f7096d30aef926bf4265615ba597 | |
parent | e0ebfd75077c5010f31fcecefb87f9fe06889131 (diff) |
updated for version 7.3.490v7.3.490
Problem: Member confusion in Lua interface.
Solution: Fix it. Add luaeval(). (Taro Muraoka, Luis Carvalho)
-rw-r--r-- | runtime/doc/if_lua.txt | 134 | ||||
-rw-r--r-- | src/eval.c | 27 | ||||
-rw-r--r-- | src/if_lua.c | 1137 | ||||
-rw-r--r-- | src/proto/if_lua.pro | 2 | ||||
-rw-r--r-- | src/version.c | 2 |
5 files changed, 1024 insertions, 278 deletions
diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt index 65148224c2..718a229ebf 100644 --- a/runtime/doc/if_lua.txt +++ b/runtime/doc/if_lua.txt @@ -1,4 +1,4 @@ -*if_lua.txt* For Vim version 7.3. Last change: 2010 Jul 22 +*if_lua.txt* For Vim version 7.3. Last change: 2012 Jan 16 VIM REFERENCE MANUAL by Luis Carvalho @@ -8,8 +8,11 @@ The Lua Interface to Vim *lua* *Lua* 1. Commands |lua-commands| 2. The vim module |lua-vim| -3. Buffer userdata |lua-buffer| -4. Window userdata |lua-window| +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| {Vi does not have any of these commands} @@ -88,11 +91,9 @@ Examples: All these commands execute a Lua chunk from either the command line (:lua and :luado) or a file (:luafile) with the given line [range]. Similarly to the Lua interpreter, each chunk has its own scope and so only global variables are -shared between command calls. Lua default libraries "table", "string", "math", -and "package" are available, "io" and "debug" are not, and "os" is restricted -to functions "date", "clock", "time", "difftime", and "getenv". In addition, -Lua "print" function has its output redirected to the Vim message area, with -arguments separated by a white space instead of a tab. +shared between command calls. All Lua default libraries are available. In +addition, Lua "print" function has its output redirected to the Vim message +area, with arguments separated by a white space instead of a tab. Lua uses the "vim" module (see |lua-vim|) to issue commands to Vim and manage buffers (|lua-buffer|) and windows (|lua-window|). However, @@ -108,9 +109,9 @@ input range are stored in "vim.firstline" and "vim.lastline" respectively. The module also includes routines for buffer, window, and current line queries, Vim evaluation and command execution, and others. - vim.isbuffer(value) Returns 'true' (boolean, not string) if - "value" is a buffer userdata and 'false' - otherwise (see |lua-buffer|). + vim.list() Returns an empty list (see |List|). + + vim.dict() Returns an empty dictionary (see |Dictionary|). vim.buffer([arg]) If "arg" is a number, returns buffer with number "arg" in the buffer list or, if "arg" @@ -121,16 +122,21 @@ Vim evaluation and command execution, and others. 'true' returns the first buffer in the buffer list or else the current buffer. - vim.iswindow(value) Returns 'true' (boolean, not string) if - "value" is a window userdata and - 'false' otherwise (see |lua-window|). - vim.window([arg]) If "arg" is a number, returns window with number "arg" or 'nil' (nil value, not string) if not found. Otherwise, if "toboolean(arg)" is 'true' returns the first window or else the current window. + 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: > + :lua l = vim.list() + :lua print(type(l), vim.type(l)) + :" userdata list +< vim.command({cmd}) Executes the vim (ex-mode) command {cmd}. Examples: > :lua vim.command"set tw=60" @@ -141,7 +147,7 @@ Vim evaluation and command execution, and others. Vim strings and numbers are directly converted to Lua strings and numbers respectively. Vim lists and dictionaries are converted to Lua - tables (lists become integer-keyed tables). + userdata (see |lua-list| and |lua-dict|). Examples: > :lua tw = vim.eval"&tw" :lua print(vim.eval"{'a': 'one'}".a) @@ -157,7 +163,72 @@ Vim evaluation and command execution, and others. ============================================================================== -3. Buffer userdata *lua-buffer* +3. List userdata *lua-list* + +List userdata represent vim lists, and the interface tries to follow closely +Vim's syntax for lists. Since lists are objects, changes in list references in +Lua are reflected in Vim and vice-versa. A list "l" has the following +properties and methods: + +Properties +---------- + o "#l" is the number of items in list "l", equivalent to "len(l)" + in Vim. + o "l[k]" returns the k-th item in "l"; "l" is zero-indexed, as in Vim. + To modify the k-th item, simply do "l[k] = newitem"; in + particular, "l[k] = nil" removes the k-th item from "l". + o "l()" returns an iterator for "l". + +Methods +------- + o "l:add(item)" appends "item" to the end of "l". + o "l:insert(item[, pos])" inserts "item" at (optional) + position "pos" in the list. The default value for "pos" is 0. + +Examples: +> + :let l = [1, 'item'] + :lua l = vim.eval('l') -- same 'l' + :lua l:add(vim.list()) + :lua l[0] = math.pi + :echo l[0] " 3.141593 + :lua l[0] = nil -- remove first item + :lua l:insert(true, 1) + :lua print(l, #l, l[0], l[1], l[-1]) + :lua for item in l() do print(item) end +< + +============================================================================== +4. Dict userdata *lua-dict* + +Similarly to list userdata, dict userdata represent vim dictionaries; since +dictionaries are also objects, references are kept between Lua and Vim. A dict +"d" has the following properties: + +Properties +---------- + o "#d" is the number of items in dict "d", equivalent to "len(d)" + in Vim. + o "d.key" or "d['key']" returns the value at entry "key" in "d". + To modify the entry at this key, simply do "d.key = newvalue"; in + particular, "d.key = nil" removes the entry from "d". + o "d()" returns an iterator for "d" and is equivalent to "items(d)" in + Vim. + +Examples: +> + :let d = {'n':10} + :lua d = vim.eval('d') -- same 'd' + :lua print(d, d.n, #d) + :let d.self = d + :lua for k, v in d() do print(d, k, v) end + :lua d.x = math.pi + :lua d.self = nil -- remove entry + :echo d +< + +============================================================================== +5. Buffer userdata *lua-buffer* Buffer userdata represent vim buffers. A buffer userdata "b" has the following properties and methods: @@ -209,7 +280,7 @@ Examples: < ============================================================================== -4. Window userdata *lua-window* +6. Window userdata *lua-window* Window objects represent vim windows. A window userdata "w" has the following properties and methods: @@ -241,4 +312,29 @@ Examples: < ============================================================================== - vim:tw=78:ts=8:ft=help:norl: +7. The luaeval function *lua-luaeval* + +The (dual) equivalent of "vim.eval" for passing Lua values to Vim is +"luaeval". "luaeval" takes an expression string and an optional argument and +returns the result of the expression. It is semantically equivalent in Lua to: +> + local chunkheader = "local _A = select(1, ...) return " + function luaeval (expstr, arg) + local chunk = assert(loadstring(chunkheader .. expstr, "luaeval")) + return chunk(arg) -- return typval + end +< +Note that "_A" receives the argument to "luaeval". Examples: > + + :echo luaeval('math.pi') + :lua a = vim.list():add('newlist') + :let a = luaeval('a') + :echo a[0] " 'newlist' + :function Rand(x,y) " random uniform between x and y + : return luaeval('(_A.y-_A.x)*math.random()+_A.x', {'x':a:x,'y':a:y}) + : endfunction + :echo Rand(1,10) + + +============================================================================== + vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/src/eval.c b/src/eval.c index bf0363ab51..d460a83be9 100644 --- a/src/eval.c +++ b/src/eval.c @@ -622,6 +622,9 @@ static void f_localtime __ARGS((typval_T *argvars, typval_T *rettv)); static void f_log __ARGS((typval_T *argvars, typval_T *rettv)); static void f_log10 __ARGS((typval_T *argvars, typval_T *rettv)); #endif +#ifdef FEAT_LUA +static void f_luaeval __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_map __ARGS((typval_T *argvars, typval_T *rettv)); static void f_maparg __ARGS((typval_T *argvars, typval_T *rettv)); static void f_mapcheck __ARGS((typval_T *argvars, typval_T *rettv)); @@ -6777,6 +6780,10 @@ garbage_collect() /* v: vars */ set_ref_in_ht(&vimvarht, copyID); +#ifdef FEAT_LUA + set_ref_in_lua(copyID); +#endif + /* * 2. Free lists and dictionaries that are not referenced. */ @@ -7946,6 +7953,9 @@ static struct fst {"log", 1, 1, f_log}, {"log10", 1, 1, f_log10}, #endif +#ifdef FEAT_LUA + {"luaeval", 1, 2, f_luaeval}, +#endif {"map", 2, 2, f_map}, {"maparg", 1, 4, f_maparg}, {"mapcheck", 1, 3, f_mapcheck}, @@ -13626,6 +13636,23 @@ f_log10(argvars, rettv) } #endif +#ifdef FEAT_LUA +/* + * "luaeval()" function + */ + static void +f_luaeval(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + char_u *str; + char_u buf[NUMBUFLEN]; + + str = get_tv_string_buf(&argvars[0], buf); + do_luaeval(str, argvars + 1, rettv); +} +#endif + /* * "map()" function */ diff --git a/src/if_lua.c b/src/if_lua.c index 0a7ba46e86..da88aab780 100644 --- a/src/if_lua.c +++ b/src/if_lua.c @@ -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 * @@ -21,15 +21,33 @@ #define LUAVIM_CHUNKNAME "vim chunk" #define LUAVIM_NAME "vim" +#define LUAVIM_EVALNAME "luaeval" +#define LUAVIM_EVALHEADER "local _A=select(1,...) return " typedef buf_T *luaV_Buffer; typedef win_T *luaV_Window; +typedef dict_T *luaV_Dict; +typedef list_T *luaV_List; typedef void (*msgfunc_T)(char_u *); +static const char LUAVIM_DICT[] = "dict"; +static const char LUAVIM_LIST[] = "list"; static const char LUAVIM_BUFFER[] = "buffer"; static const char LUAVIM_WINDOW[] = "window"; static const char LUAVIM_FREE[] = "luaV_free"; - +static const char LUAVIM_LUAEVAL[] = "luaV_luaeval"; +static const char LUAVIM_SETREF[] = "luaV_setref"; + +/* most functions are closures with a cache table as first upvalue; + * get/setudata manage references to vim userdata in cache table through + * object pointers (light userdata) */ +#define luaV_getudata(L, v) \ + lua_pushlightuserdata((L), (void *) (v)); \ + lua_rawget((L), lua_upvalueindex(1)) +#define luaV_setudata(L, v) \ + lua_pushlightuserdata((L), (void *) (v)); \ + lua_pushvalue((L), -2); \ + lua_rawset((L), lua_upvalueindex(1)) #define luaV_getfield(L, s) \ lua_pushlightuserdata((L), (void *)(s)); \ lua_rawget((L), LUA_REGISTRYINDEX) @@ -38,6 +56,15 @@ static const char LUAVIM_FREE[] = "luaV_free"; #define luaV_msg(L) luaV_msgfunc((L), (msgfunc_T) msg) #define luaV_emsg(L) luaV_msgfunc((L), (msgfunc_T) emsg) +static luaV_List *luaV_pushlist (lua_State *L, list_T *lis); +static luaV_Dict *luaV_pushdict (lua_State *L, dict_T *dic); + +#if LUA_VERSION_NUM <= 501 +#define luaV_openlib(L, l, n) luaL_openlib(L, NULL, l, n) +#define luaL_typeerror luaL_typerror +#else +#define luaV_openlib luaL_setfuncs +#endif #ifdef DYNAMIC_LUA @@ -54,32 +81,54 @@ static const char LUAVIM_FREE[] = "luaV_free"; #endif /* lauxlib */ +#if LUA_VERSION_NUM <= 501 #define luaL_register dll_luaL_register +#define luaL_prepbuffer dll_luaL_prepbuffer +#define luaL_openlib dll_luaL_openlib #define luaL_typerror dll_luaL_typerror +#define luaL_loadfile dll_luaL_loadfile +#define luaL_loadbuffer dll_luaL_loadbuffer +#else +#define luaL_prepbuffsize dll_luaL_prepbuffsize +#define luaL_setfuncs dll_luaL_setfuncs +#define luaL_loadfilex dll_luaL_loadfilex +#define luaL_loadbufferx dll_luaL_loadbufferx +#define luaL_argerror dll_luaL_argerror +#endif #define luaL_checklstring dll_luaL_checklstring #define luaL_checkinteger dll_luaL_checkinteger #define luaL_optinteger dll_luaL_optinteger #define luaL_checktype dll_luaL_checktype #define luaL_error dll_luaL_error -#define luaL_loadfile dll_luaL_loadfile -#define luaL_loadbuffer dll_luaL_loadbuffer #define luaL_newstate dll_luaL_newstate #define luaL_buffinit dll_luaL_buffinit -#define luaL_prepbuffer dll_luaL_prepbuffer #define luaL_addlstring dll_luaL_addlstring #define luaL_pushresult dll_luaL_pushresult /* lua */ +#if LUA_VERSION_NUM <= 501 +#define lua_tonumber dll_lua_tonumber +#define lua_tointeger dll_lua_tointeger +#define lua_call dll_lua_call +#define lua_pcall dll_lua_pcall +#else +#define lua_tonumberx dll_lua_tonumberx +#define lua_tointegerx dll_lua_tointegerx +#define lua_callk dll_lua_callk +#define lua_pcallk dll_lua_pcallk +#define lua_getglobal dll_lua_getglobal +#define lua_setglobal dll_lua_setglobal +#define lua_typename dll_lua_typename +#endif #define lua_close dll_lua_close #define lua_gettop dll_lua_gettop #define lua_settop dll_lua_settop #define lua_pushvalue dll_lua_pushvalue #define lua_replace dll_lua_replace +#define lua_remove dll_lua_remove #define lua_isnumber dll_lua_isnumber #define lua_isstring dll_lua_isstring #define lua_type dll_lua_type #define lua_rawequal dll_lua_rawequal -#define lua_tonumber dll_lua_tonumber -#define lua_tointeger dll_lua_tointeger #define lua_toboolean dll_lua_toboolean #define lua_tolstring dll_lua_tolstring #define lua_touserdata dll_lua_touserdata @@ -94,16 +143,14 @@ static const char LUAVIM_FREE[] = "luaV_free"; #define lua_pushlightuserdata dll_lua_pushlightuserdata #define lua_getfield dll_lua_getfield #define lua_rawget dll_lua_rawget +#define lua_rawgeti dll_lua_rawgeti #define lua_createtable dll_lua_createtable #define lua_newuserdata dll_lua_newuserdata #define lua_getmetatable dll_lua_getmetatable #define lua_setfield dll_lua_setfield #define lua_rawset dll_lua_rawset #define lua_rawseti dll_lua_rawseti -#define lua_remove dll_lua_remove #define lua_setmetatable dll_lua_setmetatable -#define lua_call dll_lua_call -#define lua_pcall dll_lua_pcall /* libs */ #define luaopen_base dll_luaopen_base #define luaopen_table dll_luaopen_table @@ -116,32 +163,56 @@ static const char LUAVIM_FREE[] = "luaV_free"; #define luaL_openlibs dll_luaL_openlibs /* lauxlib */ +#if LUA_VERSION_NUM <= 501 void (*dll_luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l); +char *(*dll_luaL_prepbuffer) (luaL_Buffer *B); +void (*dll_luaL_openlib) (lua_State *L, const char *libname, const luaL_Reg *l, int nup); int (*dll_luaL_typerror) (lua_State *L, int narg, const char *tname); +int (*dll_luaL_loadfile) (lua_State *L, const char *filename); +int (*dll_luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name); +#else +char *(*dll_luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); +void (*dll_luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); +int (*dll_luaL_loadfilex) (lua_State *L, const char *filename, const char *mode); +int (*dll_luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode); +int (*dll_luaL_argerror) (lua_State *L, int numarg, const char *extramsg); +#endif const char *(*dll_luaL_checklstring) (lua_State *L, int numArg, size_t *l); lua_Integer (*dll_luaL_checkinteger) (lua_State *L, int numArg); lua_Integer (*dll_luaL_optinteger) (lua_State *L, int nArg, lua_Integer def); void (*dll_luaL_checktype) (lua_State *L, int narg, int t); int (*dll_luaL_error) (lua_State *L, const char *fmt, ...); -int (*dll_luaL_loadfile) (lua_State *L, const char *filename); -int (*dll_luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name); lua_State *(*dll_luaL_newstate) (void); void (*dll_luaL_buffinit) (lua_State *L, luaL_Buffer *B); -char *(*dll_luaL_prepbuffer) (luaL_Buffer *B); void (*dll_luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); void (*dll_luaL_pushresult) (luaL_Buffer *B); /* lua */ +#if LUA_VERSION_NUM <= 501 +lua_Number (*dll_lua_tonumber) (lua_State *L, int idx); +lua_Integer (*dll_lua_tointeger) (lua_State *L, int idx); +void (*dll_lua_call) (lua_State *L, int nargs, int nresults); +int (*dll_lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); +#else +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); +int (*dll_lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, + 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); +const char *(*dll_lua_typename) (lua_State *L, int tp); +#endif void (*dll_lua_close) (lua_State *L); int (*dll_lua_gettop) (lua_State *L); void (*dll_lua_settop) (lua_State *L, int idx); void (*dll_lua_pushvalue) (lua_State *L, int idx); void (*dll_lua_replace) (lua_State *L, int idx); +void (*dll_lua_remove) (lua_State *L, int idx); int (*dll_lua_isnumber) (lua_State *L, int idx); int (*dll_lua_isstring) (lua_State *L, int idx); int (*dll_lua_type) (lua_State *L, int idx); int (*dll_lua_rawequal) (lua_State *L, int idx1, int idx2); -lua_Number (*dll_lua_tonumber) (lua_State *L, int idx); -lua_Integer (*dll_lua_tointeger) (lua_State *L, int idx); int (*dll_lua_toboolean) (lua_State *L, int idx); const char *(*dll_lua_tolstring) (lua_State *L, int idx, size_t *len); void *(*dll_lua_touserdata) (lua_State *L, int idx); @@ -156,16 +227,14 @@ void (*dll_lua_pushboolean) (lua_State *L, int b); void (*dll_lua_pushlightuserdata) (lua_State *L, void *p); void (*dll_lua_getfield) (lua_State *L, int idx, const char *k); void (*dll_lua_rawget) (lua_State *L, int idx); +void (*dll_lua_rawgeti) (lua_State *L, int idx, int n); void (*dll_lua_createtable) (lua_State *L, int narr, int nrec); void *(*dll_lua_newuserdata) (lua_State *L, size_t sz); int (*dll_lua_getmetatable) (lua_State *L, int objindex); void (*dll_lua_setfield) (lua_State *L, int idx, const char *k); void (*dll_lua_rawset) (lua_State *L, int idx); void (*dll_lua_rawseti) (lua_State *L, int idx, int n); -void (*dll_lua_remove) (lua_State *L, int idx); int (*dll_lua_setmetatable) (lua_State *L, int objindex); -void (*dll_lua_call) (lua_State *L, int nargs, int nresults); -int (*dll_lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); /* libs */ int (*dll_luaopen_base) (lua_State *L); int (*dll_luaopen_table) (lua_State *L); @@ -185,32 +254,54 @@ typedef struct { static const luaV_Reg luaV_dll[] = { /* lauxlib */ +#if LUA_VERSION_NUM <= 501 {"luaL_register", (luaV_function) &dll_luaL_register}, + {"luaL_prepbuffer", (luaV_function) &dll_luaL_prepbuffer}, + {"luaL_openlib", (luaV_function) &dll_luaL_openlib}, {"luaL_typerror", (luaV_function) &dll_luaL_typerror}, + {"luaL_loadfile", (luaV_function) &dll_luaL_loadfile}, + {"luaL_loadbuffer", (luaV_function) &dll_luaL_loadbuffer}, +#else + {"luaL_prepbuffsize", (luaV_function) &dll_luaL_prepbuffsize}, + {"luaL_setfuncs", (luaV_function) &dll_luaL_setfuncs}, + {"luaL_loadfilex", (luaV_function) &dll_luaL_loadfilex}, + {"luaL_loadbufferx", (luaV_function) &dll_luaL_loadbufferx}, + {"luaL_argerror", (luaV_function) &dll_luaL_argerror}, +#endif {"luaL_checklstring", (luaV_function) &dll_luaL_checklstring}, {"luaL_checkinteger", (luaV_function) &dll_luaL_checkinteger}, {"luaL_optinteger", (luaV_function) &dll_luaL_optinteger}, {"luaL_checktype", (luaV_function) &dll_luaL_checktype}, {"luaL_error", (luaV_function) &dll_luaL_error}, - {"luaL_loadfile", (luaV_function) &dll_luaL_loadfile}, - {"luaL_loadbuffer", (luaV_function) &dll_luaL_loadbuffer}, {"luaL_newstate", (luaV_function) &dll_luaL_newstate}, {"luaL_buffinit", (luaV_function) &dll_luaL_buffinit}, - {"luaL_prepbuffer", (luaV_function) &dll_luaL_prepbuffer}, {"luaL_addlstring", (luaV_function) &dll_luaL_addlstring}, {"luaL_pushresult", (luaV_function) &dll_luaL_pushresult}, /* lua */ +#if LUA_VERSION_NUM <= 501 + {"lua_tonumber", (luaV_function) &dll_lua_tonumber}, + {"lua_tointeger", (luaV_function) &dll_lua_tointeger}, + {"lua_call", (luaV_function) &dll_lua_call}, + {"lua_pcall", (luaV_function) &dll_lua_pcall}, +#else + {"lua_tonumberx", (luaV_function) &dll_lua_tonumberx}, + {"lua_tointegerx", (luaV_function) &dll_lua_tointegerx}, + {"lua_callk", (luaV_function) &dll_lua_callk}, + {"lua_pcallk", (luaV_function) &dll_lua_pcallk}, + {"lua_getglobal", (luaV_function) &dll_lua_getglobal}, + {"lua_setglobal", (luaV_function) &dll_lua_setglobal}, + {"lua_typename", (luaV_function) &dll_lua_typename}, +#endif {"lua_close", (luaV_function) &dll_lua_close}, {"lua_gettop", (luaV_function) &dll_lua_gettop}, {"lua_settop", (luaV_function) &dll_lua_settop}, {"lua_pushvalue", (luaV_function) &dll_lua_pushvalue}, {"lua_replace", (luaV_function) &dll_lua_replace}, + {"lua_remove", (luaV_function) &dll_lua_remove}, {"lua_isnumber", (luaV_function) &dll_lua_isnumber}, {"lua_isstring", (luaV_function) &dll_lua_isstring}, {"lua_type", (luaV_function) &dll_lua_type}, {"lua_rawequal", (luaV_function) &dll_lua_rawequal}, - {"lua_tonumber", (luaV_function) &dll_lua_tonumber}, - {"lua_tointeger", (luaV_function) &dll_lua_tointeger}, {"lua_toboolean", (luaV_function) &dll_lua_toboolean}, {"lua_tolstring", (luaV_function) &dll_lua_tolstring}, {"lua_touserdata", (luaV_function) &dll_lua_touserdata}, @@ -225,16 +316,14 @@ static const luaV_Reg luaV_dll[] = { {"lua_pushlightuserdata", (luaV_function) &dll_lua_pushlightuserdata}, {"lua_getfield", (luaV_function) &dll_lua_getfield}, {"lua_rawget", (luaV_function) &dll_lua_rawget}, + {"lua_rawgeti", (luaV_function) &dll_lua_rawgeti}, {"lua_createtable", (luaV_function) &dll_lua_createtable}, {"lua_newuserdata", (luaV_function) &dll_lua_newuserdata}, {"lua_getmetatable", (luaV_function) &dll_lua_getmetatable}, {"lua_setfield", (luaV_function) &dll_lua_setfield}, {"lua_rawset", (luaV_function) &dll_lua_rawset}, {"lua_rawseti", (luaV_function) &dll_lua_rawseti}, - {"lua_remove", (luaV_function) &dll_lua_remove}, {"lua_setmetatable", (luaV_function) &dll_lua_setmetatable}, - {"lua_call", (luaV_function) &dll_lua_call}, - {"lua_pcall", (luaV_function) &dll_lua_pcall}, /* libs */ {"luaopen_base", (luaV_function) &dll_luaopen_base}, {"luaopen_table", (luaV_function) &dll_luaopen_table}, @@ -294,6 +383,16 @@ lua_enabled(int verbose) #endif /* DYNAMIC_LUA */ +#if LUA_VERSION_NUM > 501 + static int +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)); + return luaL_argerror(L, narg, msg); +} +#endif + /* ======= Internal ======= */ @@ -327,17 +426,35 @@ luaV_toudata(lua_State *L, int ud, const char *tname) } static void * +luaV_checkcache(lua_State *L, void *p) +{ + luaV_getudata(L, p); + if (lua_isnil(L, -1)) luaL_error(L, "invalid object"); + lua_pop(L, 1); + return p; +} + +#define luaV_unbox(L,luatyp,ud) (*((luatyp *) lua_touserdata((L),(ud)))) + +#define luaV_checkvalid(L,luatyp,ud) \ + luaV_checkcache((L), (void *) luaV_unbox((L),luatyp,(ud))) + + static void * luaV_checkudata(lua_State *L, int ud, const char *tname) { void *p = luaV_toudata(L, ud, tname); - if (p == NULL) luaL_typerror(L, ud, tname); + if (p == NULL) luaL_typeerror(L, ud, tname); return p; } static void luaV_pushtypval(lua_State *L, typval_T *tv) { - if (tv == NULL) luaL_error(L, "null type"); + if (tv == NULL) + { + lua_pushnil(L); + return; + } switch (tv->v_type) { case VAR_STRING: @@ -351,68 +468,70 @@ luaV_pushtypval(lua_State *L, typval_T *tv) lua_pushnumber(L, (lua_Number) tv->vval.v_float); break; #endif - case VAR_LIST: { - list_T *l = tv->vval.v_list; + case VAR_LIST: + luaV_pushlist(L, tv->vval.v_list); + break; + case VAR_DICT: + luaV_pushdict(L, tv->vval.v_dict); + break; + default: + lua_pushnil(L); + } +} - if (l != NULL) +/* converts lua value at 'pos' to typval 'tv' */ + static void +luaV_totypval (lua_State *L, int pos, typval_T *tv) +{ + switch(lua_type(L, pos)) { + case LUA_TBOOLEAN: + tv->v_type = VAR_NUMBER; + tv->vval.v_number = (varnumber_T) lua_toboolean(L, pos); + break; + case LUA_TSTRING: + tv->v_type = VAR_STRING; + tv->vval.v_string = vim_strsave((char_u *) lua_tostring(L, pos)); + break; + case LUA_TNUMBER: +#ifdef FEAT_FLOAT + tv->v_type = VAR_FLOAT; + tv->vval.v_float = (float_T) lua_tonumber(L, pos); +#else + tv->v_type = VAR_NUMBER; + tv->vval.v_number = (varnumber_T) lua_tointeger(L, pos); +#endif + break; + case LUA_TUSERDATA: { + void *p = lua_touserdata(L, pos); + if (lua_getmetatable(L, pos)) /* has metatable? */ { - /* check cache */ - lua_pushlightuserdata(L, (void *) l); - lua_rawget(L, LUA_ENVIRONINDEX); - if (lua_isnil(L, -1)) /* not interned? */ + /* check list */ + luaV_getfield(L, LUAVIM_LIST); + if (lua_rawequal(L, -1, -2)) { - listitem_T *li; - int n = 0; - lua_pop(L, 1); /* nil */ - lua_newtable(L); - lua_pushlightuserdata(L, (void *) l); - lua_pushvalue(L, -2); - lua_rawset(L, LUA_ENVIRONINDEX); - for (li = l->lv_first; li != NULL; li = li->li_next) - { - luaV_pushtypval(L, &li->li_tv); - lua_rawseti(L, -2, ++n); - } + tv->v_type = VAR_LIST; + tv->vval.v_list = *((luaV_List *) p); + ++tv->vval.v_list->lv_refcount; + lua_pop(L, 2); /* MTs */ + return; } - } - else lua_pushnil(L); - break; - } - case VAR_DICT: { - dict_T *d = tv->vval.v_dict; - - if (d != NULL) - { - /* check cache */ - lua_pushlightuserdata(L, (void *) d); - lua_rawget(L, LUA_ENVIRONINDEX); - if (lua_isnil(L, -1)) /* not interned? */ + /* check dict */ + luaV_getfield(L, LUAVIM_DICT); + if (lua_rawequal(L, -1, -3)) { - hashtab_T *ht = &d->dv_hashtab; - hashitem_T *hi; - int n = ht->ht_used; /* remaining items */ - lua_pop(L, 1); /* nil */ - lua_newtable(L); - lua_pushlightuserdata(L, (void *) d); - lua_pushvalue(L, -2); - lua_rawset(L, LUA_ENVIRONINDEX); - for (hi = ht->ht_array; n > 0; hi++) - { - if (!HASHITEM_EMPTY(hi)) - { - dictitem_T *di = dict_lookup(hi); - luaV_pushtypval(L, &di->di_tv); - lua_setfield(L, -2, (char *) hi->hi_key); - n--; - } - } + tv->v_type = VAR_DICT; + tv->vval.v_dict = *((luaV_Dict *) p); + ++tv->vval.v_dict->dv_refcount; + lua_pop(L, 3); /* MTs */ + return; } + lua_pop(L, 3); /* MTs */ } - else lua_pushnil(L); break; } default: - luaL_error(L, "invalid type"); + tv->v_type = VAR_NUMBER; + tv->vval.v_number = 0; } } @@ -481,89 +600,508 @@ luaV_msgfunc(lua_State *L, msgfunc_T mf) lua_pop(L, 2); /* original and modified strings */ } +#define luaV_newtype(typ,tname,luatyp,luatname) \ + static luatyp * \ + luaV_new##tname (lua_State *L, typ *obj) \ + { \ + luatyp *o = (luatyp *) lua_newuserdata(L, sizeof(luatyp)); \ + *o = obj; \ + luaV_setudata(L, obj); /* cache[obj] = udata */ \ + luaV_getfield(L, luatname); \ + lua_setmetatable(L, -2); \ + return o; \ + } -/* ======= Buffer type ======= */ +#define luaV_pushtype(typ,tname,luatyp) \ + static luatyp * \ + luaV_push##tname (lua_State *L, typ *obj) \ + { \ + luatyp *o = NULL; \ + if (obj == NULL) \ + lua_pushnil(L); \ + else { \ + luaV_getudata(L, obj); \ + if (lua_isnil(L, -1)) /* not interned? */ \ + { \ + lua_pop(L, 1); \ + o = luaV_new##tname(L, obj); \ + } \ + else \ + o = (luatyp *) lua_touserdata(L, -1); \ + } \ + return o; \ + } + +#define luaV_type_tostring(tname,luatname) \ + static int \ + luaV_##tname##_tostring (lua_State *L) \ + { \ + lua_pushfstring(L, "%s: %p", luatname, lua_touserdata(L, 1)); \ + return 1; \ + } + + +/* adapted from eval.c */ - static luaV_Buffer * -luaV_newbuffer(lua_State *L, buf_T *buf) +#define listitem_alloc() (listitem_T *)alloc(sizeof(listitem_T)) + + static listitem_T * +list_find (list_T *l, long n) { - luaV_Buffer *b = (luaV_Buffer *) lua_newuserdata(L, sizeof(luaV_Buffer)); - *b = buf; - lua_pushlightuserdata(L, (void *) buf); - lua_pushvalue(L, -2); - lua_rawset(L, LUA_ENVIRONINDEX); /* env[buf] = udata */ - /* to avoid GC, store as key in env */ - lua_pushvalue(L, -1); - lua_pushboolean(L, 1); - lua_rawset(L, LUA_ENVIRONINDEX); /* env[udata] = true */ - /* set metatable */ - luaV_getfield(L, LUAVIM_BUFFER); + 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 * +luaV_newlist (lua_State *L, list_T *lis) +{ + luaV_List *l = (luaV_List *) lua_newuserdata(L, sizeof(luaV_List)); + *l = lis; + lis->lv_refcount++; /* reference in Lua */ + luaV_setudata(L, lis); /* cache[lis] = udata */ + luaV_getfield(L, LUAVIM_LIST); lua_setmetatable(L, -2); - return b; + return l; } - static luaV_Buffer * -luaV_pushbuffer (lua_State *L, buf_T *buf) +luaV_pushtype(list_T, list, luaV_List) +luaV_type_tostring(list, LUAVIM_LIST) + + static int +luaV_list_gc (lua_State *L) { - luaV_Buffer *b = NULL; - if (buf == NULL) - lua_pushnil(L); - else { - lua_pushlightuserdata(L, (void *) buf); - lua_rawget(L, LUA_ENVIRONINDEX); - if (lua_isnil(L, -1)) /* not interned? */ + list_unref(luaV_unbox(L, luaV_List, 1)); + return 0; +} + + static int +luaV_list_len (lua_State *L) +{ + list_T *l = luaV_unbox(L, luaV_List, 1); + lua_pushinteger(L, (l == NULL) ? 0 : (int) l->lv_len); + return 1; +} + + static int +luaV_list_iter (lua_State *L) +{ + listitem_T *li = (listitem_T *) lua_touserdata(L, lua_upvalueindex(2)); + if (li == NULL) return 0; + luaV_pushtypval(L, &li->li_tv); + lua_pushlightuserdata(L, (void *) li->li_next); + lua_replace(L, lua_upvalueindex(2)); + return 1; +} + + static int +luaV_list_call (lua_State *L) +{ + list_T *l = luaV_unbox(L, luaV_List, 1); + lua_pushvalue(L, lua_upvalueindex(1)); /* pass cache table along */ + lua_pushlightuserdata(L, (void *) l->lv_first); + lua_pushcclosure(L, luaV_list_iter, 2); + return 1; +} + + static int +luaV_list_index (lua_State *L) +{ + list_T *l = luaV_unbox(L, luaV_List, 1); + if (lua_isnumber(L, 2)) /* list item? */ + { + listitem_T *li = list_find(l, (long) luaL_checkinteger(L, 2)); + if (li == NULL) + lua_pushnil(L); + else + luaV_pushtypval(L, &li->li_tv); + } + else if (lua_isstring(L, 2)) /* method? */ + { + const char *s = lua_tostring(L, 2); + if (strncmp(s, "add", 3) == 0 + || strncmp(s, "insert", 6) == 0 + || strncmp(s, "extend", 6) == 0) { - lua_pop(L, 1); - b = luaV_newbuffer(L, buf); + lua_getmetatable(L, 1); + lua_getfield(L, -1, s); } else - b = (luaV_Buffer *) lua_touserdata(L, -1); + lua_pushnil(L); } - return b; + else + lua_pushnil(L); + return 1; } -/* Buffer metamethods */ + static int |