diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/vim.c | 16 | ||||
-rw-r--r-- | src/nvim/eval.c | 2 | ||||
-rw-r--r-- | src/nvim/viml/executor/converter.c | 547 | ||||
-rw-r--r-- | src/nvim/viml/executor/executor.c | 1 |
4 files changed, 362 insertions, 204 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 413456c615..24959e9a59 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -197,7 +197,21 @@ Object nvim_eval(String expr, Error *err) return rv; } -/// Calls a VimL function with the given arguments. +/// Returns object given as argument +/// +/// This API function is used for testing. One should not rely on its presence +/// in plugins. +/// +/// @param[in] obj Object to return. +/// +/// @return its argument. +Object _vim_id(Object obj) +{ + return obj; +} + +/// Calls a VimL function with the given arguments +/// /// On VimL error: Returns a generic error; v:errmsg is not updated. /// /// @param fname Function to call diff --git a/src/nvim/eval.c b/src/nvim/eval.c index c349a601c6..de82f8a145 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -13402,7 +13402,7 @@ static void f_luaeval(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - executor_eval_lua(cstr_as_string(str), &argvars[1], rettv); + executor_eval_lua(cstr_as_string((char *)str), &argvars[1], rettv); } /* diff --git a/src/nvim/viml/executor/converter.c b/src/nvim/viml/executor/converter.c index fb7bbd51eb..c127b87738 100644 --- a/src/nvim/viml/executor/converter.c +++ b/src/nvim/viml/executor/converter.c @@ -24,10 +24,121 @@ #include "nvim/viml/executor/converter.h" #include "nvim/viml/executor/executor.h" +/// Determine, which keys lua table contains +typedef struct { + size_t maxidx; ///< Maximum positive integral value found. + size_t string_keys_num; ///< Number of string keys. + bool has_string_with_nul; ///< True if there is string key with NUL byte. + ObjectType type; ///< If has_type_key is true then attached value. Otherwise + ///< either kObjectTypeNil, kObjectTypeDictionary or + ///< kObjectTypeArray, depending on other properties. + lua_Number val; ///< If has_val_key and val_type == LUA_TNUMBER: value. +} LuaTableProps; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "viml/executor/converter.c.generated.h" #endif +#define TYPE_IDX_VALUE true +#define VAL_IDX_VALUE false + +#define LUA_PUSH_STATIC_STRING(lstate, s) \ + lua_pushlstring(lstate, s, sizeof(s) - 1) + +static LuaTableProps nlua_traverse_table(lua_State *const lstate) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + bool has_type_key = false; // True if type key was found, + // @see nlua_push_type_idx(). + size_t tsize = 0; // Total number of keys. + int val_type = 0; // If has_val_key: lua type of the value. + bool has_val_key = false; // True if val key was found, + // @see nlua_push_val_idx(). + bool has_other = false; // True if there are keys that are not strings + // or positive integral values. + LuaTableProps ret; + memset(&ret, 0, sizeof(ret)); + if (!lua_checkstack(lstate, lua_gettop(lstate) + 2)) { + emsgf(_("E1502: Lua failed to grow stack to %i"), lua_gettop(lstate) + 2); + ret.type = kObjectTypeNil; + return ret; + } + lua_pushnil(lstate); + while (lua_next(lstate, -2)) { + switch (lua_type(lstate, -2)) { + case LUA_TSTRING: { + size_t len; + const char *s = lua_tolstring(lstate, -2, &len); + if (memchr(s, NUL, len) != NULL) { + ret.has_string_with_nul = true; + } + ret.string_keys_num++; + break; + } + case LUA_TNUMBER: { + const lua_Number n = lua_tonumber(lstate, -2); + if (n > (lua_Number)SIZE_MAX || n <= 0 + || ((lua_Number)((size_t)n)) != n) { + has_other = true; + } else { + const size_t idx = (size_t)n; + if (idx > ret.maxidx) { + ret.maxidx = idx; + } + } + break; + } + case LUA_TBOOLEAN: { + const bool b = lua_toboolean(lstate, -2); + if (b == TYPE_IDX_VALUE) { + if (lua_type(lstate, -1) == LUA_TNUMBER) { + lua_Number n = lua_tonumber(lstate, -1); + if (n == (lua_Number)kObjectTypeFloat + || n == (lua_Number)kObjectTypeArray + || n == (lua_Number)kObjectTypeDictionary) { + has_type_key = true; + ret.type = (ObjectType)n; + } else { + has_other = true; + } + } else { + has_other = true; + } + } else { + has_val_key = true; + val_type = lua_type(lstate, -1); + if (val_type == LUA_TNUMBER) { + ret.val = lua_tonumber(lstate, -1); + } + } + break; + } + default: { + has_other = true; + break; + } + } + tsize++; + lua_pop(lstate, 1); + } + if (has_type_key) { + if (ret.type == kObjectTypeFloat + && (!has_val_key || val_type != LUA_TNUMBER)) { + ret.type = kObjectTypeNil; + } + } else { + if (tsize == 0 + || (tsize == ret.maxidx && !has_other && ret.string_keys_num == 0)) { + ret.type = kObjectTypeArray; + } else if (ret.string_keys_num == tsize) { + ret.type = kObjectTypeDictionary; + } else { + ret.type = kObjectTypeNil; + } + } + return ret; +} + /// Helper structure for nlua_pop_typval typedef struct { typval_T *tv; ///< Location where conversion result is saved. @@ -63,8 +174,15 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) if (cur.container) { if (cur.special || cur.tv->v_type == VAR_DICT) { assert(cur.tv->v_type == (cur.special ? VAR_LIST : VAR_DICT)); - if (lua_next(lstate, -2)) { - assert(lua_type(lstate, -2) == LUA_TSTRING); + bool next_key_found = false; + while (lua_next(lstate, -2)) { + if (lua_type(lstate, -2) == LUA_TSTRING) { + next_key_found = true; + break; + } + lua_pop(lstate, 1); + } + if (next_key_found) { size_t len; const char *s = lua_tolstring(lstate, -2, &len); if (cur.special) { @@ -109,7 +227,11 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) } } assert(!cur.container); - memset(cur.tv, 0, sizeof(*cur.tv)); + *cur.tv = (typval_T) { + .v_type = VAR_NUMBER, + .v_lock = VAR_UNLOCKED, + .vval = { .v_number = 0 }, + }; switch (lua_type(lstate, -1)) { case LUA_TNIL: { cur.tv->v_type = VAR_SPECIAL; @@ -145,81 +267,64 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) break; } case LUA_TTABLE: { - bool has_string = false; - bool has_string_with_nul = false; - bool has_other = false; - size_t maxidx = 0; - size_t tsize = 0; - lua_pushnil(lstate); - while (lua_next(lstate, -2)) { - switch (lua_type(lstate, -2)) { - case LUA_TSTRING: { - size_t len; - const char *s = lua_tolstring(lstate, -2, &len); - if (memchr(s, NUL, len) != NULL) { - has_string_with_nul = true; - } - has_string = true; - break; + const LuaTableProps table_props = nlua_traverse_table(lstate); + + switch (table_props.type) { + case kObjectTypeArray: { + if (table_props.maxidx == 0) { + cur.tv->v_type = VAR_LIST; + cur.tv->vval.v_list = list_alloc(); + cur.tv->vval.v_list->lv_refcount++; + } else { + cur.tv->v_type = VAR_LIST; + cur.tv->vval.v_list = list_alloc(); + cur.tv->vval.v_list->lv_refcount++; + cur.container = true; + kv_push(stack, cur); } - case LUA_TNUMBER: { - const lua_Number n = lua_tonumber(lstate, -2); - if (n > (lua_Number)SIZE_MAX || n <= 0 - || ((lua_Number)((size_t)n)) != n) { - has_other = true; + break; + } + case kObjectTypeDictionary: { + if (table_props.string_keys_num == 0) { + cur.tv->v_type = VAR_DICT; + cur.tv->vval.v_dict = dict_alloc(); + cur.tv->vval.v_dict->dv_refcount++; + } else { + cur.special = table_props.has_string_with_nul; + if (table_props.has_string_with_nul) { + decode_create_map_special_dict(cur.tv); + assert(cur.tv->v_type = VAR_DICT); + dictitem_T *const val_di = dict_find(cur.tv->vval.v_dict, + (char_u *)"_VAL", 4); + assert(val_di != NULL); + cur.tv = &val_di->di_tv; + assert(cur.tv->v_type == VAR_LIST); } else { - const size_t idx = (size_t)n; - if (idx > maxidx) { - maxidx = idx; - } + cur.tv->v_type = VAR_DICT; + cur.tv->vval.v_dict = dict_alloc(); + cur.tv->vval.v_dict->dv_refcount++; } - break; - } - default: { - has_other = true; - break; + cur.container = true; + kv_push(stack, cur); + lua_pushnil(lstate); } + break; } - tsize++; - lua_pop(lstate, 1); - } - - if (tsize == 0) { - // Assuming empty list - cur.tv->v_type = VAR_LIST; - cur.tv->vval.v_list = list_alloc(); - cur.tv->vval.v_list->lv_refcount++; - } else if (tsize == maxidx && !has_other && !has_string) { - // Assuming array - cur.tv->v_type = VAR_LIST; - cur.tv->vval.v_list = list_alloc(); - cur.tv->vval.v_list->lv_refcount++; - cur.container = true; - kv_push(stack, cur); - } else if (has_string && !has_other && maxidx == 0) { - // Assuming dictionary - cur.special = has_string_with_nul; - if (has_string_with_nul) { - decode_create_map_special_dict(cur.tv); - assert(cur.tv->v_type = VAR_DICT); - dictitem_T *const val_di = dict_find(cur.tv->vval.v_dict, - (char_u *)"_VAL", 4); - assert(val_di != NULL); - cur.tv = &val_di->di_tv; - assert(cur.tv->v_type == VAR_LIST); - } else { - cur.tv->v_type = VAR_DICT; - cur.tv->vval.v_dict = dict_alloc(); - cur.tv->vval.v_dict->dv_refcount++; + case kObjectTypeFloat: { + cur.tv->v_type = VAR_FLOAT; + cur.tv->vval.v_float = (float_T)table_props.val; + break; + } + case kObjectTypeNil: { + EMSG(_("E5100: Cannot convert given lua table: table " + "should either have a sequence of positive integer keys " + "or contain only string keys")); + ret = false; + break; + } + default: { + assert(false); } - cur.container = true; - kv_push(stack, cur); - lua_pushnil(lstate); - } else { - EMSG(_("E5100: Cannot convert given lua table: table " - "should either have a sequence of positive integer keys " - "or contain only string keys")); - ret = false; } break; } @@ -236,7 +341,11 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) kv_destroy(stack); if (!ret) { clear_tv(ret_tv); - memset(ret_tv, 0, sizeof(*ret_tv)); + *ret_tv = (typval_T) { + .v_type = VAR_NUMBER, + .v_lock = VAR_UNLOCKED, + .vval = { .v_number = 0 }, + }; lua_pop(lstate, lua_gettop(lstate) - initial_size + 1); } assert(lua_gettop(lstate) == initial_size - 1); @@ -281,7 +390,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) lua_createtable(lstate, 0, 0) #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ - TYPVAL_ENCODE_CONV_EMPTY_LIST() + nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary) #define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ do { \ @@ -432,16 +541,7 @@ bool nlua_push_typval(lua_State *lstate, typval_T *const tv) static inline void nlua_push_type_idx(lua_State *lstate) FUNC_ATTR_NONNULL_ALL { - lua_pushboolean(lstate, true); -} - -/// Push value which is a locks index -/// -/// Used for containers tables. -static inline void nlua_push_locks_idx(lua_State *lstate) - FUNC_ATTR_NONNULL_ALL -{ - lua_pushboolean(lstate, false); + lua_pushboolean(lstate, TYPE_IDX_VALUE); } /// Push value which is a value index @@ -450,7 +550,7 @@ static inline void nlua_push_locks_idx(lua_State *lstate) static inline void nlua_push_val_idx(lua_State *lstate) FUNC_ATTR_NONNULL_ALL { - lua_pushnumber(lstate, (lua_Number)0); + lua_pushboolean(lstate, VAL_IDX_VALUE); } /// Push type @@ -458,14 +558,11 @@ static inline void nlua_push_val_idx(lua_State *lstate) /// Type is a value in vim.types table. /// /// @param[out] lstate Lua state. -/// @param[in] type Type to push (key in vim.types table). -static inline void nlua_push_type(lua_State *lstate, const char *const type) +/// @param[in] type Type to push. +static inline void nlua_push_type(lua_State *lstate, ObjectType type) + FUNC_ATTR_NONNULL_ALL { - lua_getglobal(lstate, "vim"); - lua_getfield(lstate, -1, "types"); - lua_remove(lstate, -2); - lua_getfield(lstate, -1, type); - lua_remove(lstate, -2); + lua_pushnumber(lstate, (lua_Number)type); } /// Create lua table which has an entry that determines its VimL type @@ -477,7 +574,7 @@ static inline void nlua_push_type(lua_State *lstate, const char *const type) static inline void nlua_create_typed_table(lua_State *lstate, const size_t narr, const size_t nrec, - const char *const type) + const ObjectType type) FUNC_ATTR_NONNULL_ALL { lua_createtable(lstate, (int)narr, (int)(1 + nrec)); @@ -511,7 +608,7 @@ void nlua_push_Integer(lua_State *lstate, const Integer n) void nlua_push_Float(lua_State *lstate, const Float f) FUNC_ATTR_NONNULL_ALL { - nlua_create_typed_table(lstate, 0, 1, "float"); + nlua_create_typed_table(lstate, 0, 1, kObjectTypeFloat); nlua_push_val_idx(lstate); lua_pushnumber(lstate, (lua_Number)f); lua_rawset(lstate, -3); @@ -526,21 +623,17 @@ void nlua_push_Boolean(lua_State *lstate, const Boolean b) lua_pushboolean(lstate, b); } -static inline void nlua_add_locks_table(lua_State *lstate) -{ - nlua_push_locks_idx(lstate); - lua_newtable(lstate); - lua_rawset(lstate, -3); -} - /// Convert given Dictionary to lua table /// /// Leaves converted table on top of the stack. void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict) FUNC_ATTR_NONNULL_ALL { - nlua_create_typed_table(lstate, 0, 1 + dict.size, "dict"); - nlua_add_locks_table(lstate); + if (dict.size == 0) { + nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); + } else { + lua_createtable(lstate, 0, (int)dict.size); + } for (size_t i = 0; i < dict.size; i++) { nlua_push_String(lstate, dict.items[i].key); nlua_push_Object(lstate, dict.items[i].value); @@ -554,11 +647,10 @@ void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict) void nlua_push_Array(lua_State *lstate, const Array array) FUNC_ATTR_NONNULL_ALL { - nlua_create_typed_table(lstate, array.size, 1, "float"); - nlua_add_locks_table(lstate); + lua_createtable(lstate, (int)array.size, 0); for (size_t i = 0; i < array.size; i++) { nlua_push_Object(lstate, array.items[i]); - lua_rawseti(lstate, -3, (int)i + 1); + lua_rawseti(lstate, -2, (int)i + 1); } } @@ -663,26 +755,33 @@ Boolean nlua_pop_Boolean(lua_State *lstate, Error *err) return ret; } -static inline bool nlua_check_type(lua_State *lstate, Error *err, - const char *const type) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +/// Check whether typed table on top of the stack has given type +/// +/// @param[in] lstate Lua state. +/// @param[out] err Location where error will be saved. May be NULL. +/// @param[in] type Type to check. +/// +/// @return @see nlua_traverse_table(). +static inline LuaTableProps nlua_check_type(lua_State *const lstate, + Error *const err, + const ObjectType type) + FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT { if (lua_type(lstate, -1) != LUA_TTABLE) { - set_api_error("Expected lua table", err); - return true; + if (err) { + set_api_error("Expected lua table", err); + } + return (LuaTableProps) { .type = kObjectTypeNil }; } + const LuaTableProps table_props = nlua_traverse_table(lstate); - nlua_push_type_idx(lstate); - lua_rawget(lstate, -2); - nlua_push_type(lstate, type); - if (!lua_rawequal(lstate, -2, -1)) { - lua_pop(lstate, 2); - set_api_error("Expected lua table with float type", err); - return true; + if (table_props.type != type) { + if (err) { + set_api_error("Unexpected type", err); + } } - lua_pop(lstate, 2); - return false; + return table_props; } /// Convert lua table to float @@ -691,49 +790,32 @@ static inline bool nlua_check_type(lua_State *lstate, Error *err, Float nlua_pop_Float(lua_State *lstate, Error *err) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - Float ret = 0; - - if (nlua_check_type(lstate, err, "float")) { + if (lua_type(lstate, -1) == LUA_TNUMBER) { + const Float ret = (Float)lua_tonumber(lstate, -1); lua_pop(lstate, 1); - return 0; - } - - nlua_push_val_idx(lstate); - lua_rawget(lstate, -2); - - if (!lua_isnumber(lstate, -1)) { - lua_pop(lstate, 2); - set_api_error("Value field should be lua number", err); return ret; } - ret = lua_tonumber(lstate, -1); - lua_pop(lstate, 2); - return ret; + const LuaTableProps table_props = nlua_check_type(lstate, err, + kObjectTypeFloat); + lua_pop(lstate, 1); + if (table_props.type != kObjectTypeFloat) { + return 0; + } else { + return (Float)table_props.val; + } } -/// Convert lua table to array +/// Convert lua table to array without determining whether it is array /// -/// Always pops one value from the stack. -Array nlua_pop_Array(lua_State *lstate, Error *err) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +/// @param lstate Lua state. +/// @param[in] table_props nlua_traverse_table() output. +/// @param[out] err Location where error will be saved. +static Array nlua_pop_Array_unchecked(lua_State *const lstate, + const LuaTableProps table_props, + Error *const err) { - Array ret = { .size = 0, .items = NULL }; - - if (nlua_check_type(lstate, err, "list")) { - lua_pop(lstate, 1); - return ret; - } - - for (int i = 1; ; i++, ret.size++) { - lua_rawgeti(lstate, -1, i); - - if (lua_isnil(lstate, -1)) { - lua_pop(lstate, 1); - break; - } - lua_pop(lstate, 1); - } + Array ret = { .size = table_props.maxidx, .items = NULL }; if (ret.size == 0) { lua_pop(lstate, 1); @@ -748,7 +830,7 @@ Array nlua_pop_Array(lua_State *lstate, Error *err) val = nlua_pop_Object(lstate, err); if (err->set) { - ret.size = i; + ret.size = i - 1; lua_pop(lstate, 1); api_free_array(ret); return (Array) { .size = 0, .items = NULL }; @@ -760,24 +842,35 @@ Array nlua_pop_Array(lua_State *lstate, Error *err) return ret; } -/// Convert lua table to dictionary +/// Convert lua table to array /// -/// Always pops one value from the stack. Does not check whether -/// `vim.is_dict(table[type_idx])` or whether topmost value on the stack is -/// a table. -Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate, Error *err) +/// Always pops one value from the stack. +Array nlua_pop_Array(lua_State *lstate, Error *err) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - Dictionary ret = { .size = 0, .items = NULL }; - - lua_pushnil(lstate); - - while (lua_next(lstate, -2)) { - if (lua_type(lstate, -2) == LUA_TSTRING) { - ret.size++; - } - lua_pop(lstate, 1); + const LuaTableProps table_props = nlua_check_type(lstate, err, + kObjectTypeArray); + lua_pop(lstate, 1); + if (table_props.type != kObjectTypeArray) { + return (Array) { .size = 0, .items = NULL }; } + return nlua_pop_Array_unchecked(lstate, table_props, err); +} + +/// Convert lua table to dictionary +/// +/// Always pops one value from the stack. Does not check whether whether topmost +/// value on the stack is a table. +/// +/// @param lstate Lua interpreter state. +/// @param[in] table_props nlua_traverse_table() output. +/// @param[out] err Location where error will be saved. +static Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate, + const LuaTableProps table_props, + Error *err) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + Dictionary ret = { .size = table_props.string_keys_num, .items = NULL }; if (ret.size == 0) { lua_pop(lstate, 1); @@ -786,7 +879,7 @@ Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate, Error *err) ret.items = xcalloc(ret.size, sizeof(*ret.items)); lua_pushnil(lstate); - for (size_t i = 0; lua_next(lstate, -2);) { + for (size_t i = 0; lua_next(lstate, -2) && i < ret.size;) { // stack: dict, key, value if (lua_type(lstate, -2) == LUA_TSTRING) { @@ -828,12 +921,14 @@ Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate, Error *err) Dictionary nlua_pop_Dictionary(lua_State *lstate, Error *err) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - if (nlua_check_type(lstate, err, "dict")) { + const LuaTableProps table_props = nlua_check_type(lstate, err, + kObjectTypeDictionary); + if (table_props.type != kObjectTypeDictionary) { lua_pop(lstate, 1); return (Dictionary) { .size = 0, .items = NULL }; } - return nlua_pop_Dictionary_unchecked(lstate, err); + return nlua_pop_Dictionary_unchecked(lstate, table_props, err); } /// Convert lua table to object @@ -856,8 +951,16 @@ Object nlua_pop_Object(lua_State *lstate, Error *err) break; } case LUA_TNUMBER: { - ret.type = kObjectTypeInteger; - ret.data.integer = nlua_pop_Integer(lstate, err); + const lua_Number n = lua_tonumber(lstate, -1); + if (n > (lua_Number)API_INTEGER_MAX || n < (lua_Number)API_INTEGER_MIN + || ((lua_Number)((Integer)n)) != n) { + ret.type = kObjectTypeFloat; + ret.data.floating = (Float)n; + } else { + ret.type = kObjectTypeInteger; + ret.data.integer = (Integer)n; + } + lua_pop(lstate, 1); break; } case LUA_TBOOLEAN: { @@ -866,33 +969,26 @@ Object nlua_pop_Object(lua_State *lstate, Error *err) break; } case LUA_TTABLE: { - lua_getglobal(lstate, "vim"); - // stack: obj, vim -#define CHECK_TYPE(Type, key, vim_type) \ - lua_getfield(lstate, -1, "is_" #vim_type); \ - /* stack: obj, vim, checker */ \ - lua_pushvalue(lstate, -3); \ - /* stack: obj, vim, checker, obj */ \ - lua_call(lstate, 1, 1); \ - /* stack: obj, vim, result */ \ - if (lua_toboolean(lstate, -1)) { \ - lua_pop(lstate, 2); \ - /* stack: obj */ \ - ret.type = kObjectType##Type; \ - ret.data.key = nlua_pop_##Type(lstate, err); \ - /* stack: */ \ - break; \ - } \ - lua_pop(lstate, 1); \ - // stack: obj, vim - CHECK_TYPE(Float, floating, float) - CHECK_TYPE(Array, array, list) - CHECK_TYPE(Dictionary, dictionary, dict) -#undef CHECK_TYPE - lua_pop(lstate, 1); - // stack: obj - ret.type = kObjectTypeDictionary; - ret.data.dictionary = nlua_pop_Dictionary_unchecked(lstate, err); + const LuaTableProps table_props = nlua_traverse_table(lstate); + ret.type = table_props.type; + switch (table_props.type) { + case kObjectTypeArray: { + ret.data.array = nlua_pop_Array_unchecked(lstate, table_props, err); + break; + } + case kObjectTypeDictionary: { + ret.data.dictionary = nlua_pop_Dictionary_unchecked(lstate, + table_props, err); + break; + } + case kObjectTypeFloat: { + ret.data.floating = (Float)table_props.val; + break; + } + default: { + assert(false); + } + } break; } default: { @@ -923,3 +1019,50 @@ GENERATE_INDEX_FUNCTION(Window) GENERATE_INDEX_FUNCTION(Tabpage) #undef GENERATE_INDEX_FUNCTION + +/// Record some auxilary values in vim module +/// +/// Assumes that module table is on top of the stack. +/// +/// Recorded values: +/// +/// `vim.type_idx`: @see nlua_push_type_idx() +/// `vim.val_idx`: @see nlua_push_val_idx() +/// `vim.types`: table mapping possible values of `vim.type_idx` to string +/// names (i.e. `array`, `float`, `dictionary`) and back. +void nlua_init_types(lua_State *const lstate) +{ + LUA_PUSH_STATIC_STRING(lstate, "type_idx"); + nlua_push_type_idx(lstate); + lua_rawset(lstate, -3); + + LUA_PUSH_STATIC_STRING(lstate, "val_idx"); + nlua_push_val_idx(lstate); + lua_rawset(lstate, -3); + + LUA_PUSH_STATIC_STRING(lstate, "types"); + lua_createtable(lstate, 0, 3); + + LUA_PUSH_STATIC_STRING(lstate, "float"); + lua_pushnumber(lstate, (lua_Number)kObjectTypeFloat); + lua_rawset(lstate, -3); + lua_pushnumber(lstate, (lua_Number)kObjectTypeFloat); + LUA_PUSH_STATIC_STRING(lstate, "float"); + lua_rawset(lstate, -3); + + LUA_PUSH_STATIC_STRING(lstate, "array"); + lua_pushnumber(lstate, (lua_Number)kObjectTypeArray); + lua_rawset(lstate, -3); + lua_pushnumber(lstate, (lua_Number)kObjectTypeArray); + LUA_PUSH_STATIC_STRING(lstate, "array"); + lua_rawset(lstate, -3); + + LUA_PUSH_STATIC_STRING(lstate, "dictionary"); + lua_pushnumber(lstate, (lua_Number)kObjectTypeDictionary); + lua_rawset(lstate, -3); + lua_pushnumber(lstate, (lua_Number)kObjectTypeDictionary); + LUA_PUSH_STATIC_STRING(lstate, "dictionary"); + lua_rawset(lstate, -3); + + lua_rawset(lstate, -3); +} diff --git a/src/nvim/viml/executor/executor.c b/src/nvim/viml/executor/executor.c index 1a7b5f8915..33b6870ea0 100644 --- a/src/nvim/viml/executor/executor.c +++ b/src/nvim/viml/executor/executor.c @@ -145,6 +145,7 @@ static int nlua_state_init(lua_State *lstate) FUNC_ATTR_NONNULL_ALL return 1; } nlua_add_api_functions(lstate); + nlua_init_types(lstate); lua_setglobal(lstate, "vim"); return 0; } |