mirror of
https://github.com/neovim/neovim.git
synced 2025-09-12 14:28:18 +00:00
luaref: simplify handling of table callables and fix leak in vim.fn.call(table)
I AM THE TABLE
This commit is contained in:
@@ -931,19 +931,11 @@ void nlua_pushref(lua_State *lstate, LuaRef ref)
|
||||
lua_rawgeti(lstate, LUA_REGISTRYINDEX, ref);
|
||||
}
|
||||
|
||||
|
||||
/// Gets a new reference to an object stored at original_ref
|
||||
///
|
||||
/// NOTE: It does not copy the value, it creates a new ref to the lua object.
|
||||
/// Leaves the stack unchanged.
|
||||
LuaRef nlua_newref(lua_State *lstate, LuaRef original_ref)
|
||||
{
|
||||
nlua_pushref(lstate, original_ref);
|
||||
LuaRef new_ref = nlua_ref(lstate, -1);
|
||||
lua_pop(lstate, 1);
|
||||
|
||||
return new_ref;
|
||||
}
|
||||
|
||||
LuaRef api_new_luaref(LuaRef original_ref)
|
||||
{
|
||||
if (original_ref == LUA_NOREF) {
|
||||
@@ -951,7 +943,10 @@ LuaRef api_new_luaref(LuaRef original_ref)
|
||||
}
|
||||
|
||||
lua_State *const lstate = nlua_enter();
|
||||
return nlua_newref(lstate, original_ref);
|
||||
nlua_pushref(lstate, original_ref);
|
||||
LuaRef new_ref = nlua_ref(lstate, -1);
|
||||
lua_pop(lstate, 1);
|
||||
return new_ref;
|
||||
}
|
||||
|
||||
|
||||
@@ -1061,25 +1056,13 @@ int typval_exec_lua_callable(
|
||||
typval_T *rettv
|
||||
)
|
||||
{
|
||||
int offset = 0;
|
||||
LuaRef cb = lua_cb.func_ref;
|
||||
|
||||
if (cb == LUA_NOREF) {
|
||||
// This shouldn't happen.
|
||||
luaL_error(lstate, "Invalid function passed to VimL");
|
||||
return ERROR_OTHER;
|
||||
}
|
||||
|
||||
nlua_pushref(lstate, cb);
|
||||
|
||||
if (lua_cb.table_ref != LUA_NOREF) {
|
||||
offset += 1;
|
||||
nlua_pushref(lstate, lua_cb.table_ref);
|
||||
}
|
||||
|
||||
PUSH_ALL_TYPVALS(lstate, argvars, argcount, false);
|
||||
|
||||
if (lua_pcall(lstate, argcount + offset, 1, 0)) {
|
||||
if (lua_pcall(lstate, argcount, 1, 0)) {
|
||||
nlua_print(lstate);
|
||||
return ERROR_OTHER;
|
||||
}
|
||||
@@ -1546,6 +1529,8 @@ static int regex_match_line(lua_State *lstate)
|
||||
return nret;
|
||||
}
|
||||
|
||||
// Required functions for lua c functions as VimL callbacks
|
||||
|
||||
int nlua_CFunction_func_call(
|
||||
int argcount,
|
||||
typval_T *argvars,
|
||||
@@ -1555,53 +1540,40 @@ int nlua_CFunction_func_call(
|
||||
lua_State *const lstate = nlua_enter();
|
||||
LuaCFunctionState *funcstate = (LuaCFunctionState *)state;
|
||||
|
||||
return typval_exec_lua_callable(
|
||||
lstate,
|
||||
funcstate->lua_callable,
|
||||
argcount,
|
||||
argvars,
|
||||
rettv);
|
||||
return typval_exec_lua_callable(lstate, funcstate->lua_callable,
|
||||
argcount, argvars, rettv);
|
||||
}
|
||||
/// Required functions for lua c functions as VimL callbacks
|
||||
|
||||
void nlua_CFunction_func_free(void *state)
|
||||
{
|
||||
lua_State *const lstate = nlua_enter();
|
||||
LuaCFunctionState *funcstate = (LuaCFunctionState *)state;
|
||||
|
||||
nlua_unref(lstate, funcstate->lua_callable.func_ref);
|
||||
nlua_unref(lstate, funcstate->lua_callable.table_ref);
|
||||
xfree(funcstate);
|
||||
}
|
||||
|
||||
bool nlua_is_table_from_lua(typval_T *const arg)
|
||||
{
|
||||
if (arg->v_type != VAR_DICT && arg->v_type != VAR_LIST) {
|
||||
if (arg->v_type == VAR_DICT) {
|
||||
return arg->vval.v_dict->lua_table_ref != LUA_NOREF;
|
||||
} else if (arg->v_type == VAR_LIST) {
|
||||
return arg->vval.v_list->lua_table_ref != LUA_NOREF;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arg->v_type == VAR_DICT) {
|
||||
return arg->vval.v_dict->lua_table_ref > 0
|
||||
&& arg->vval.v_dict->lua_table_ref != LUA_NOREF;
|
||||
} else if (arg->v_type == VAR_LIST) {
|
||||
return arg->vval.v_list->lua_table_ref > 0
|
||||
&& arg->vval.v_list->lua_table_ref != LUA_NOREF;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char_u *nlua_register_table_as_callable(typval_T *const arg)
|
||||
{
|
||||
if (!nlua_is_table_from_lua(arg)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LuaRef table_ref;
|
||||
LuaRef table_ref = LUA_NOREF;
|
||||
if (arg->v_type == VAR_DICT) {
|
||||
table_ref = arg->vval.v_dict->lua_table_ref;
|
||||
} else if (arg->v_type == VAR_LIST) {
|
||||
table_ref = arg->vval.v_list->lua_table_ref;
|
||||
} else {
|
||||
}
|
||||
|
||||
if (table_ref == LUA_NOREF) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1611,55 +1583,34 @@ char_u *nlua_register_table_as_callable(typval_T *const arg)
|
||||
int top = lua_gettop(lstate);
|
||||
#endif
|
||||
|
||||
nlua_pushref(lstate, table_ref);
|
||||
nlua_pushref(lstate, table_ref); // [table]
|
||||
if (!lua_getmetatable(lstate, -1)) {
|
||||
lua_pop(lstate, 1);
|
||||
assert(top == lua_gettop(lstate));
|
||||
return NULL;
|
||||
}
|
||||
} // [table, mt]
|
||||
|
||||
lua_getfield(lstate, -1, "__call");
|
||||
lua_getfield(lstate, -1, "__call"); // [table, mt, mt.__call]
|
||||
if (!lua_isfunction(lstate, -1)) {
|
||||
lua_pop(lstate, 3);
|
||||
assert(top == lua_gettop(lstate));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LuaRef new_table_ref = nlua_newref(lstate, table_ref);
|
||||
lua_pop(lstate, 2); // [table]
|
||||
|
||||
LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState));
|
||||
state->lua_callable.func_ref = nlua_ref(lstate, -1);
|
||||
state->lua_callable.table_ref = new_table_ref;
|
||||
|
||||
char_u *name = register_cfunc(
|
||||
&nlua_CFunction_func_call,
|
||||
&nlua_CFunction_func_free,
|
||||
state);
|
||||
char_u *name = register_cfunc(&nlua_CFunction_func_call,
|
||||
&nlua_CFunction_func_free, state);
|
||||
|
||||
|
||||
lua_pop(lstate, 3);
|
||||
lua_pop(lstate, 1); // []
|
||||
assert(top == lua_gettop(lstate));
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/// Helper function to free a list_T
|
||||
void nlua_free_typval_list(list_T *const l)
|
||||
{
|
||||
if (l->lua_table_ref != LUA_NOREF && l->lua_table_ref > 0) {
|
||||
lua_State *const lstate = nlua_enter();
|
||||
nlua_unref(lstate, l->lua_table_ref);
|
||||
l->lua_table_ref = LUA_NOREF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Helper function to free a dict_T
|
||||
void nlua_free_typval_dict(dict_T *const d)
|
||||
{
|
||||
if (d->lua_table_ref != LUA_NOREF && d->lua_table_ref > 0) {
|
||||
lua_State *const lstate = nlua_enter();
|
||||
nlua_unref(lstate, d->lua_table_ref);
|
||||
d->lua_table_ref = LUA_NOREF;
|
||||
}
|
||||
}
|
||||
|
||||
void nlua_execute_log_keystroke(int c)
|
||||
{
|
||||
char_u buf[NUMBUFLEN];
|
||||
|
Reference in New Issue
Block a user