mirror of
https://github.com/neovim/neovim.git
synced 2025-09-17 16:58:17 +00:00
viml/executor: Directly generate typval_T values
Note: this will *still* crash when using API in cases similar to the one described in first commit. Just it needs different code to reproduce.
This commit is contained in:
@@ -36,7 +36,19 @@ typedef struct {
|
||||
lua_pushcfunction(lstate, &function); \
|
||||
lua_call(lstate, 0, numret); \
|
||||
} while (0)
|
||||
/// Call C function which expects four arguments
|
||||
/// Call C function which expects two arguments
|
||||
///
|
||||
/// @param function Called function
|
||||
/// @param numret Number of returned arguments
|
||||
/// @param a… Supplied argument (should be a void* pointer)
|
||||
#define NLUA_CALL_C_FUNCTION_2(lstate, function, numret, a1, a2) \
|
||||
do { \
|
||||
lua_pushcfunction(lstate, &function); \
|
||||
lua_pushlightuserdata(lstate, a1); \
|
||||
lua_pushlightuserdata(lstate, a2); \
|
||||
lua_call(lstate, 2, numret); \
|
||||
} while (0)
|
||||
/// Call C function which expects three arguments
|
||||
///
|
||||
/// @param function Called function
|
||||
/// @param numret Number of returned arguments
|
||||
@@ -64,15 +76,19 @@ typedef struct {
|
||||
lua_call(lstate, 4, numret); \
|
||||
} while (0)
|
||||
|
||||
static void set_lua_error(lua_State *lstate, LuaError *lerr)
|
||||
/// Convert lua error into a Vim error message
|
||||
///
|
||||
/// @param lstate Lua interpreter state.
|
||||
/// @param[in] msg Message base, must contain one `%s`.
|
||||
static void nlua_error(lua_State *const lstate, const char *const msg)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
const char *const str = lua_tolstring(lstate, -1, &lerr->lua_err_str.size);
|
||||
lerr->lua_err_str.data = xmemdupz(str, lerr->lua_err_str.size);
|
||||
lua_pop(lstate, 1);
|
||||
size_t len;
|
||||
const char *const str = lua_tolstring(lstate, -1, &len);
|
||||
|
||||
// FIXME? More specific error?
|
||||
set_api_error("Error while executing lua code", &lerr->err);
|
||||
EMSG2(msg, str);
|
||||
|
||||
lua_pop(lstate, 1);
|
||||
}
|
||||
|
||||
/// Compare two strings, ignoring case
|
||||
@@ -94,25 +110,26 @@ static int nlua_stricmp(lua_State *lstate) FUNC_ATTR_NONNULL_ALL
|
||||
|
||||
/// Evaluate lua string
|
||||
///
|
||||
/// Expects three values on the stack: string to evaluate, pointer to the
|
||||
/// location where result is saved, pointer to the location where error is
|
||||
/// saved. Always returns nothing (from the lua point of view).
|
||||
/// Expects two values on the stack: string to evaluate, pointer to the
|
||||
/// location where result is saved. Always returns nothing (from the lua point
|
||||
/// of view).
|
||||
static int nlua_exec_lua_string(lua_State *lstate) FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
String *str = (String *) lua_touserdata(lstate, 1);
|
||||
Object *obj = (Object *) lua_touserdata(lstate, 2);
|
||||
LuaError *lerr = (LuaError *) lua_touserdata(lstate, 3);
|
||||
lua_pop(lstate, 3);
|
||||
String *str = (String *)lua_touserdata(lstate, 1);
|
||||
typval_T *ret_tv = (typval_T *)lua_touserdata(lstate, 2);
|
||||
lua_pop(lstate, 2);
|
||||
|
||||
if (luaL_loadbuffer(lstate, str->data, str->size, NLUA_EVAL_NAME)) {
|
||||
set_lua_error(lstate, lerr);
|
||||
nlua_error(lstate, _("E5104: Error while creating lua chunk: %s"));
|
||||
return 0;
|
||||
}
|
||||
if (lua_pcall(lstate, 0, 1, 0)) {
|
||||
set_lua_error(lstate, lerr);
|
||||
nlua_error(lstate, _("E5105: Error while calling lua chunk: %s"));
|
||||
return 0;
|
||||
}
|
||||
if (!nlua_pop_typval(lstate, ret_tv)) {
|
||||
return 0;
|
||||
}
|
||||
*obj = nlua_pop_Object(lstate, &lerr->err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -124,8 +141,7 @@ static int nlua_state_init(lua_State *lstate) FUNC_ATTR_NONNULL_ALL
|
||||
lua_pushcfunction(lstate, &nlua_stricmp);
|
||||
lua_setglobal(lstate, "stricmp");
|
||||
if (luaL_dostring(lstate, (char *) &vim_module[0])) {
|
||||
LuaError lerr;
|
||||
set_lua_error(lstate, &lerr);
|
||||
nlua_error(lstate, _("E5106: Error while creating vim module: %s"));
|
||||
return 1;
|
||||
}
|
||||
nlua_add_api_functions(lstate);
|
||||
@@ -150,14 +166,6 @@ static lua_State *init_lua(void)
|
||||
return lstate;
|
||||
}
|
||||
|
||||
static Object exec_lua_string(lua_State *lstate, String str, LuaError *lerr)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
Object ret = { kObjectTypeNil, { false } };
|
||||
NLUA_CALL_C_FUNCTION_3(lstate, nlua_exec_lua_string, 0, &str, &ret, lerr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static lua_State *global_lstate = NULL;
|
||||
|
||||
/// Execute lua string
|
||||
@@ -165,28 +173,17 @@ static lua_State *global_lstate = NULL;
|
||||
/// Used for :lua.
|
||||
///
|
||||
/// @param[in] str String to execute.
|
||||
/// @param[out] err Location where error will be saved.
|
||||
/// @param[out] err_str Location where lua error string will be saved, if any.
|
||||
/// @param[out] ret_tv Location where result will be saved.
|
||||
///
|
||||
/// @return Result of the execution.
|
||||
Object executor_exec_lua(String str, Error *err, String *err_str)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
void executor_exec_lua(String str, typval_T *ret_tv)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
if (global_lstate == NULL) {
|
||||
global_lstate = init_lua();
|
||||
}
|
||||
|
||||
LuaError lerr = {
|
||||
.err = { .set = false },
|
||||
.lua_err_str = STRING_INIT,
|
||||
};
|
||||
|
||||
Object ret = exec_lua_string(global_lstate, str, &lerr);
|
||||
|
||||
*err = lerr.err;
|
||||
*err_str = lerr.lua_err_str;
|
||||
|
||||
return ret;
|
||||
NLUA_CALL_C_FUNCTION_2(global_lstate, nlua_exec_lua_string, 0, &str, ret_tv);
|
||||
}
|
||||
|
||||
/// Evaluate lua string
|
||||
@@ -196,75 +193,73 @@ Object executor_exec_lua(String str, Error *err, String *err_str)
|
||||
/// 1. String to evaluate.
|
||||
/// 2. _A value.
|
||||
/// 3. Pointer to location where result is saved.
|
||||
/// 4. Pointer to location where error will be saved.
|
||||
///
|
||||
/// @param[in,out] lstate Lua interpreter state.
|
||||
static int nlua_eval_lua_string(lua_State *lstate)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
String *str = (String *) lua_touserdata(lstate, 1);
|
||||
Object *arg = (Object *) lua_touserdata(lstate, 2);
|
||||
Object *ret = (Object *) lua_touserdata(lstate, 3);
|
||||
LuaError *lerr = (LuaError *) lua_touserdata(lstate, 4);
|
||||
String *str = (String *)lua_touserdata(lstate, 1);
|
||||
typval_T *arg = (typval_T *)lua_touserdata(lstate, 2);
|
||||
typval_T *ret_tv = (typval_T *)lua_touserdata(lstate, 3);
|
||||
lua_pop(lstate, 3);
|
||||
|
||||
garray_T str_ga;
|
||||
ga_init(&str_ga, 1, 80);
|
||||
#define EVALHEADER "local _A=select(1,...) return "
|
||||
ga_concat_len(&str_ga, EVALHEADER, sizeof(EVALHEADER) - 1);
|
||||
#define EVALHEADER "local _A=select(1,...) return ("
|
||||
const size_t lcmd_len = sizeof(EVALHEADER) - 1 + str->size + 1;
|
||||
char *lcmd;
|
||||
if (lcmd_len < IOSIZE) {
|
||||
lcmd = (char *)IObuff;
|
||||
} else {
|
||||
lcmd = xmalloc(lcmd_len);
|
||||
}
|
||||
memcpy(lcmd, EVALHEADER, sizeof(EVALHEADER) - 1);
|
||||
memcpy(lcmd + sizeof(EVALHEADER) - 1, str->data, str->size);
|
||||
lcmd[lcmd_len - 1] = ')';
|
||||
#undef EVALHEADER
|
||||
ga_concat_len(&str_ga, str->data, str->size);
|
||||
if (luaL_loadbuffer(lstate, str_ga.ga_data, (size_t) str_ga.ga_len,
|
||||
NLUA_EVAL_NAME)) {
|
||||
set_lua_error(lstate, lerr);
|
||||
if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) {
|
||||
nlua_error(lstate,
|
||||
_("E5107: Error while creating lua chunk for luaeval(): %s"));
|
||||
return 0;
|
||||
}
|
||||
ga_clear(&str_ga);
|
||||
if (lcmd != (char *)IObuff) {
|
||||
xfree(lcmd);
|
||||
}
|
||||
|
||||
nlua_push_Object(lstate, *arg);
|
||||
if (arg == NULL || arg->v_type == VAR_UNKNOWN) {
|
||||
lua_pushnil(lstate);
|
||||
} else {
|
||||
nlua_push_typval(lstate, arg);
|
||||
}
|
||||
if (lua_pcall(lstate, 1, 1, 0)) {
|
||||
set_lua_error(lstate, lerr);
|
||||
nlua_error(lstate,
|
||||
_("E5108: Error while calling lua chunk for luaeval(): %s"));
|
||||
return 0;
|
||||
}
|
||||
if (!nlua_pop_typval(lstate, ret_tv)) {
|
||||
return 0;
|
||||
}
|
||||
*ret = nlua_pop_Object(lstate, &lerr->err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Object eval_lua_string(lua_State *lstate, String str, Object arg,
|
||||
LuaError *lerr)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
Object ret = { kObjectTypeNil, { false } };
|
||||
NLUA_CALL_C_FUNCTION_4(lstate, nlua_eval_lua_string, 0,
|
||||
&str, &arg, &ret, lerr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Evaluate lua string
|
||||
///
|
||||
/// Used for luaeval().
|
||||
///
|
||||
/// @param[in] str String to execute.
|
||||
/// @param[out] err Location where error will be saved.
|
||||
/// @param[out] err_str Location where lua error string will be saved, if any.
|
||||
/// @param[in] arg Second argument to `luaeval()`.
|
||||
/// @param[out] ret_tv Location where result will be saved.
|
||||
///
|
||||
/// @return Result of the execution.
|
||||
Object executor_eval_lua(String str, Object arg, Error *err, String *err_str)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
void executor_eval_lua(const String str, typval_T *const arg,
|
||||
typval_T *const ret_tv)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
if (global_lstate == NULL) {
|
||||
global_lstate = init_lua();
|
||||
}
|
||||
|
||||
LuaError lerr = {
|
||||
.err = { .set = false },
|
||||
.lua_err_str = STRING_INIT,
|
||||
};
|
||||
|
||||
Object ret = eval_lua_string(global_lstate, str, arg, &lerr);
|
||||
|
||||
*err = lerr.err;
|
||||
*err_str = lerr.lua_err_str;
|
||||
|
||||
return ret;
|
||||
NLUA_CALL_C_FUNCTION_3(global_lstate, nlua_eval_lua_string, 0,
|
||||
(void *)&str, arg, ret_tv);
|
||||
}
|
||||
|
Reference in New Issue
Block a user