diff options
author | ZyX <kp-pav@yandex.ru> | 2017-04-11 01:09:36 +0300 |
---|---|---|
committer | ZyX <kp-pav@yandex.ru> | 2017-04-11 01:09:36 +0300 |
commit | f98a3d85ed2f34a62300097fd30b393a3b3be393 (patch) | |
tree | 41562adb208723f786454ae2ddfa0bb02521318d /src/nvim/viml | |
parent | 1751ec192d860f2591d18c4aad4248b5ab786cec (diff) | |
download | rneovim-f98a3d85ed2f34a62300097fd30b393a3b3be393.tar.gz rneovim-f98a3d85ed2f34a62300097fd30b393a3b3be393.tar.bz2 rneovim-f98a3d85ed2f34a62300097fd30b393a3b3be393.zip |
lua: Move files from src/nvim/viml/executor to src/nvim/lua
Diffstat (limited to 'src/nvim/viml')
-rw-r--r-- | src/nvim/viml/executor/converter.c | 1194 | ||||
-rw-r--r-- | src/nvim/viml/executor/converter.h | 15 | ||||
-rw-r--r-- | src/nvim/viml/executor/executor.c | 576 | ||||
-rw-r--r-- | src/nvim/viml/executor/executor.h | 25 | ||||
-rw-r--r-- | src/nvim/viml/executor/vim.lua | 2 |
5 files changed, 0 insertions, 1812 deletions
diff --git a/src/nvim/viml/executor/converter.c b/src/nvim/viml/executor/converter.c deleted file mode 100644 index 425a38538d..0000000000 --- a/src/nvim/viml/executor/converter.c +++ /dev/null @@ -1,1194 +0,0 @@ -#include <lua.h> -#include <lualib.h> -#include <lauxlib.h> -#include <assert.h> -#include <stdint.h> -#include <stdbool.h> - -#include "nvim/api/private/defs.h" -#include "nvim/api/private/helpers.h" -#include "nvim/func_attr.h" -#include "nvim/memory.h" -#include "nvim/assert.h" -// FIXME: vim.h is not actually needed, but otherwise it states MAXPATHL is -// redefined -#include "nvim/vim.h" -#include "nvim/globals.h" -#include "nvim/message.h" -#include "nvim/eval/typval.h" -#include "nvim/ascii.h" -#include "nvim/macros.h" - -#include "nvim/lib/kvec.h" -#include "nvim/eval/decode.h" - -#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. - bool has_type_key; ///< True if type key is present. -} 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 -{ - 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(). - size_t other_keys_num = 0; // Number of keys that are not string, integral - // or type keys. - LuaTableProps ret; - memset(&ret, 0, sizeof(ret)); - if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { - 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) { - other_keys_num++; - } 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) { - ret.has_type_key = true; - ret.type = (ObjectType)n; - } else { - other_keys_num++; - } - } else { - other_keys_num++; - } - } else { - has_val_key = true; - val_type = lua_type(lstate, -1); - if (val_type == LUA_TNUMBER) { - ret.val = lua_tonumber(lstate, -1); - } - } - break; - } - default: { - other_keys_num++; - break; - } - } - tsize++; - lua_pop(lstate, 1); - } - if (ret.has_type_key) { - if (ret.type == kObjectTypeFloat - && (!has_val_key || val_type != LUA_TNUMBER)) { - ret.type = kObjectTypeNil; - } else if (ret.type == kObjectTypeArray) { - // Determine what is the last number in a *sequence* of keys. - // This condition makes sure that Neovim will not crash when it gets table - // {[vim.type_idx]=vim.types.array, [SIZE_MAX]=1}: without it maxidx will - // be SIZE_MAX, with this condition it should be zero and [SIZE_MAX] key - // should be ignored. - if (ret.maxidx != 0 - && ret.maxidx != (tsize - - ret.has_type_key - - other_keys_num - - has_val_key - - ret.string_keys_num)) { - for (ret.maxidx = 0;; ret.maxidx++) { - lua_rawgeti(lstate, -1, (int)ret.maxidx + 1); - if (lua_isnil(lstate, -1)) { - lua_pop(lstate, 1); - break; - } - lua_pop(lstate, 1); - } - } - } - } else { - if (tsize == 0 - || (tsize == ret.maxidx - && other_keys_num == 0 - && 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. - bool container; ///< True if tv is a container. - bool special; ///< If true then tv is a _VAL part of special dictionary - ///< that represents mapping. - int idx; ///< Container index (used to detect self-referencing structures). -} TVPopStackItem; - -/// Convert lua object to VimL typval_T -/// -/// Should pop exactly one value from lua stack. -/// -/// @param lstate Lua state. -/// @param[out] ret_tv Where to put the result. -/// -/// @return `true` in case of success, `false` in case of failure. Error is -/// reported automatically. -bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) -{ - bool ret = true; - const int initial_size = lua_gettop(lstate); - kvec_t(TVPopStackItem) stack = KV_INITIAL_VALUE; - kv_push(stack, ((TVPopStackItem) { ret_tv, false, false, 0 })); - while (ret && kv_size(stack)) { - if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { - emsgf(_("E1502: Lua failed to grow stack to %i"), lua_gettop(lstate) + 3); - ret = false; - break; - } - TVPopStackItem cur = kv_pop(stack); - if (cur.container) { - if (cur.special || cur.tv->v_type == VAR_DICT) { - assert(cur.tv->v_type == (cur.special ? VAR_LIST : VAR_DICT)); - 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) { - list_T *const kv_pair = tv_list_alloc(); - tv_list_append_list(cur.tv->vval.v_list, kv_pair); - listitem_T *const key = tv_list_item_alloc(); - key->li_tv = decode_string(s, len, kTrue, false, false); - tv_list_append(kv_pair, key); - if (key->li_tv.v_type == VAR_UNKNOWN) { - ret = false; - tv_list_unref(kv_pair); - continue; - } - listitem_T *const val = tv_list_item_alloc(); - tv_list_append(kv_pair, val); - kv_push(stack, cur); - cur = (TVPopStackItem) { &val->li_tv, false, false, 0 }; - } else { - dictitem_T *const di = tv_dict_item_alloc_len(s, len); - if (tv_dict_add(cur.tv->vval.v_dict, di) == FAIL) { - assert(false); - } - kv_push(stack, cur); - cur = (TVPopStackItem) { &di->di_tv, false, false, 0 }; - } - } else { - lua_pop(lstate, 1); - continue; - } - } else { - assert(cur.tv->v_type == VAR_LIST); - lua_rawgeti(lstate, -1, cur.tv->vval.v_list->lv_len + 1); - if (lua_isnil(lstate, -1)) { - lua_pop(lstate, 2); - continue; - } - listitem_T *const li = tv_list_item_alloc(); - tv_list_append(cur.tv->vval.v_list, li); - kv_push(stack, cur); - cur = (TVPopStackItem) { &li->li_tv, false, false, 0 }; - } - } - assert(!cur.container); - *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; - cur.tv->vval.v_special = kSpecialVarNull; - break; - } - case LUA_TBOOLEAN: { - cur.tv->v_type = VAR_SPECIAL; - cur.tv->vval.v_special = (lua_toboolean(lstate, -1) - ? kSpecialVarTrue - : kSpecialVarFalse); - break; - } - case LUA_TSTRING: { - size_t len; - const char *s = lua_tolstring(lstate, -1, &len); - *cur.tv = decode_string(s, len, kNone, true, false); - if (cur.tv->v_type == VAR_UNKNOWN) { - ret = false; - } - break; - } - case LUA_TNUMBER: { - const lua_Number n = lua_tonumber(lstate, -1); - if (n > (lua_Number)VARNUMBER_MAX || n < (lua_Number)VARNUMBER_MIN - || ((lua_Number)((varnumber_T)n)) != n) { - cur.tv->v_type = VAR_FLOAT; - cur.tv->vval.v_float = (float_T)n; - } else { - cur.tv->v_type = VAR_NUMBER; - cur.tv->vval.v_number = (varnumber_T)n; - } - break; - } - case LUA_TTABLE: { - const LuaTableProps table_props = nlua_traverse_table(lstate); - - for (size_t i = 0; i < kv_size(stack); i++) { - const TVPopStackItem item = kv_A(stack, i); - if (item.container && lua_rawequal(lstate, -1, item.idx)) { - tv_copy(item.tv, cur.tv); - cur.container = false; - goto nlua_pop_typval_table_processing_end; - } - } - - switch (table_props.type) { - case kObjectTypeArray: { - cur.tv->v_type = VAR_LIST; - cur.tv->vval.v_list = tv_list_alloc(); - cur.tv->vval.v_list->lv_refcount++; - if (table_props.maxidx != 0) { - cur.container = true; - cur.idx = lua_gettop(lstate); - kv_push(stack, cur); - } - break; - } - case kObjectTypeDictionary: { - if (table_props.string_keys_num == 0) { - cur.tv->v_type = VAR_DICT; - cur.tv->vval.v_dict = tv_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 = tv_dict_find(cur.tv->vval.v_dict, - S_LEN("_VAL")); - 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 = tv_dict_alloc(); - cur.tv->vval.v_dict->dv_refcount++; - } - cur.container = true; - cur.idx = lua_gettop(lstate); - kv_push(stack, cur); - lua_pushnil(lstate); - } - break; - } - 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); - } - } -nlua_pop_typval_table_processing_end: - break; - } - default: { - EMSG(_("E5101: Cannot convert given lua type")); - ret = false; - break; - } - } - if (!cur.container) { - lua_pop(lstate, 1); - } - } - kv_destroy(stack); - if (!ret) { - tv_clear(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); - return ret; -} - -#define TYPVAL_ENCODE_ALLOW_SPECIALS true - -#define TYPVAL_ENCODE_CONV_NIL(tv) \ - lua_pushnil(lstate) - -#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ - lua_pushboolean(lstate, (bool)(num)) - -#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ - lua_pushnumber(lstate, (lua_Number)(num)) - -#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER TYPVAL_ENCODE_CONV_NUMBER - -#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ - TYPVAL_ENCODE_CONV_NUMBER(tv, flt) - -#define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \ - lua_pushlstring(lstate, (const char *)(str), (len)) - -#define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING - -#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, str, len, type) \ - TYPVAL_ENCODE_CONV_NIL() - -#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ - do { \ - TYPVAL_ENCODE_CONV_NIL(tv); \ - goto typval_encode_stop_converting_one_item; \ - } while (0) - -#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len) -#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len) -#define TYPVAL_ENCODE_CONV_FUNC_END(tv) - -#define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \ - lua_createtable(lstate, 0, 0) - -#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ - nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary) - -#define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ - do { \ - if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { \ - emsgf(_("E5102: Lua failed to grow stack to %i"), \ - lua_gettop(lstate) + 3); \ - return false; \ - } \ - lua_createtable(lstate, (int)(len), 0); \ - lua_pushnumber(lstate, 1); \ - } while (0) - -#define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) - -#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) \ - do { \ - lua_Number idx = lua_tonumber(lstate, -2); \ - lua_rawset(lstate, -3); \ - lua_pushnumber(lstate, idx + 1); \ - } while (0) - -#define TYPVAL_ENCODE_CONV_LIST_END(tv) \ - lua_rawset(lstate, -3) - -#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \ - do { \ - if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { \ - emsgf(_("E5102: Lua failed to grow stack to %i"), \ - lua_gettop(lstate) + 3); \ - return false; \ - } \ - lua_createtable(lstate, 0, (int)(len)); \ - } while (0) - -#define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(label, kv_pair) - -#define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv) - -#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict) - -#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) \ - lua_rawset(lstate, -3) - -#define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \ - TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) - -#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ - do { \ - for (size_t backref = kv_size(*mpstack); backref; backref--) { \ - const MPConvStackVal mpval = kv_A(*mpstack, backref - 1); \ - if (mpval.type == conv_type) { \ - if (conv_type == kMPConvDict \ - ? (void *)mpval.data.d.dict == (void *)(val) \ - : (void *)mpval.data.l.list == (void *)(val)) { \ - lua_pushvalue(lstate, \ - -((int)((kv_size(*mpstack) - backref + 1) * 2))); \ - break; \ - } \ - } \ - } \ - } while (0) - -#define TYPVAL_ENCODE_SCOPE static -#define TYPVAL_ENCODE_NAME lua -#define TYPVAL_ENCODE_FIRST_ARG_TYPE lua_State *const -#define TYPVAL_ENCODE_FIRST_ARG_NAME lstate -#include "nvim/eval/typval_encode.c.h" -#undef TYPVAL_ENCODE_SCOPE -#undef TYPVAL_ENCODE_NAME -#undef TYPVAL_ENCODE_FIRST_ARG_TYPE -#undef TYPVAL_ENCODE_FIRST_ARG_NAME - -#undef TYPVAL_ENCODE_CONV_STRING -#undef TYPVAL_ENCODE_CONV_STR_STRING -#undef TYPVAL_ENCODE_CONV_EXT_STRING -#undef TYPVAL_ENCODE_CONV_NUMBER -#undef TYPVAL_ENCODE_CONV_FLOAT -#undef TYPVAL_ENCODE_CONV_FUNC_START -#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS -#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF -#undef TYPVAL_ENCODE_CONV_FUNC_END -#undef TYPVAL_ENCODE_CONV_EMPTY_LIST -#undef TYPVAL_ENCODE_CONV_LIST_START -#undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START -#undef TYPVAL_ENCODE_CONV_EMPTY_DICT -#undef TYPVAL_ENCODE_CONV_NIL -#undef TYPVAL_ENCODE_CONV_BOOL -#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER -#undef TYPVAL_ENCODE_CONV_DICT_START -#undef TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START -#undef TYPVAL_ENCODE_CONV_DICT_END -#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY -#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS -#undef TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK -#undef TYPVAL_ENCODE_CONV_LIST_END -#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS -#undef TYPVAL_ENCODE_CONV_RECURSE -#undef TYPVAL_ENCODE_ALLOW_SPECIALS - -/// Convert VimL typval_T to lua value -/// -/// Should leave single value in lua stack. May only fail if lua failed to grow -/// stack. -/// -/// @param lstate Lua interpreter state. -/// @param[in] tv typval_T to convert. -/// -/// @return true in case of success, false otherwise. -bool nlua_push_typval(lua_State *lstate, typval_T *const tv) -{ - const int initial_size = lua_gettop(lstate); - if (!lua_checkstack(lstate, initial_size + 2)) { - emsgf(_("E1502: Lua failed to grow stack to %i"), initial_size + 4); - return false; - } - if (encode_vim_to_lua(lstate, tv, "nlua_push_typval argument") == FAIL) { - return false; - } - assert(lua_gettop(lstate) == initial_size + 1); - return true; -} - -#define NLUA_PUSH_HANDLE(lstate, type, idx) \ - do { \ - lua_pushnumber(lstate, (lua_Number)(idx)); \ - } while (0) - -#define NLUA_POP_HANDLE(lstate, type, stack_idx, idx) \ - do { \ - idx = (type)lua_tonumber(lstate, stack_idx); \ - } while (0) - -/// Push value which is a type index -/// -/// Used for all “typed” tables: i.e. for all tables which represent VimL -/// values. -static inline void nlua_push_type_idx(lua_State *lstate) - FUNC_ATTR_NONNULL_ALL -{ - lua_pushboolean(lstate, TYPE_IDX_VALUE); -} - -/// Push value which is a value index -/// -/// Used for tables which represent scalar values, like float value. -static inline void nlua_push_val_idx(lua_State *lstate) - FUNC_ATTR_NONNULL_ALL -{ - lua_pushboolean(lstate, VAL_IDX_VALUE); -} - -/// Push type -/// -/// Type is a value in vim.types table. -/// -/// @param[out] lstate Lua state. -/// @param[in] type Type to push. -static inline void nlua_push_type(lua_State *lstate, ObjectType type) - FUNC_ATTR_NONNULL_ALL -{ - lua_pushnumber(lstate, (lua_Number)type); -} - -/// Create lua table which has an entry that determines its VimL type -/// -/// @param[out] lstate Lua state. -/// @param[in] narr Number of “array” entries to be populated later. -/// @param[in] nrec Number of “dictionary” entries to be populated later. -/// @param[in] type Type of the table. -static inline void nlua_create_typed_table(lua_State *lstate, - const size_t narr, - const size_t nrec, - const ObjectType type) - FUNC_ATTR_NONNULL_ALL -{ - lua_createtable(lstate, (int)narr, (int)(1 + nrec)); - nlua_push_type_idx(lstate); - nlua_push_type(lstate, type); - lua_rawset(lstate, -3); -} - - -/// Convert given String to lua string -/// -/// Leaves converted string on top of the stack. -void nlua_push_String(lua_State *lstate, const String s) - FUNC_ATTR_NONNULL_ALL -{ - lua_pushlstring(lstate, s.data, s.size); -} - -/// Convert given Integer to lua number -/// -/// Leaves converted number on top of the stack. -void nlua_push_Integer(lua_State *lstate, const Integer n) - FUNC_ATTR_NONNULL_ALL -{ - lua_pushnumber(lstate, (lua_Number)n); -} - -/// Convert given Float to lua table -/// -/// Leaves converted table on top of the stack. -void nlua_push_Float(lua_State *lstate, const Float f) - FUNC_ATTR_NONNULL_ALL -{ - nlua_create_typed_table(lstate, 0, 1, kObjectTypeFloat); - nlua_push_val_idx(lstate); - lua_pushnumber(lstate, (lua_Number)f); - lua_rawset(lstate, -3); -} - -/// Convert given Float to lua boolean -/// -/// Leaves converted value on top of the stack. -void nlua_push_Boolean(lua_State *lstate, const Boolean b) - FUNC_ATTR_NONNULL_ALL -{ - lua_pushboolean(lstate, b); -} - -/// 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 -{ - 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); - lua_rawset(lstate, -3); - } -} - -/// Convert given Array to lua table -/// -/// Leaves converted table on top of the stack. -void nlua_push_Array(lua_State *lstate, const Array array) - FUNC_ATTR_NONNULL_ALL -{ - 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, -2, (int)i + 1); - } -} - -#define GENERATE_INDEX_FUNCTION(type) \ -void nlua_push_##type(lua_State *lstate, const type item) \ - FUNC_ATTR_NONNULL_ALL \ -{ \ - NLUA_PUSH_HANDLE(lstate, type, item); \ -} - -GENERATE_INDEX_FUNCTION(Buffer) -GENERATE_INDEX_FUNCTION(Window) -GENERATE_INDEX_FUNCTION(Tabpage) - -#undef GENERATE_INDEX_FUNCTION - -/// Convert given Object to lua value -/// -/// Leaves converted value on top of the stack. -void nlua_push_Object(lua_State *lstate, const Object obj) - FUNC_ATTR_NONNULL_ALL -{ - switch (obj.type) { - case kObjectTypeNil: { - lua_pushnil(lstate); - break; - } -#define ADD_TYPE(type, data_key) \ - case kObjectType##type: { \ - nlua_push_##type(lstate, obj.data.data_key); \ - break; \ - } - ADD_TYPE(Boolean, boolean) - ADD_TYPE(Integer, integer) - ADD_TYPE(Float, floating) - ADD_TYPE(String, string) - ADD_TYPE(Array, array) - ADD_TYPE(Dictionary, dictionary) -#undef ADD_TYPE -#define ADD_REMOTE_TYPE(type) \ - case kObjectType##type: { \ - nlua_push_##type(lstate, (type)obj.data.integer); \ - break; \ - } - ADD_REMOTE_TYPE(Buffer) - ADD_REMOTE_TYPE(Window) - ADD_REMOTE_TYPE(Tabpage) -#undef ADD_REMOTE_TYPE - } -} - - -/// Convert lua value to string -/// -/// Always pops one value from the stack. -String nlua_pop_String(lua_State *lstate, Error *err) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - if (lua_type(lstate, -1) != LUA_TSTRING) { - lua_pop(lstate, 1); - api_set_error(err, Validation, "Expected lua string"); - return (String) { .size = 0, .data = NULL }; - } - String ret; - - ret.data = (char *)lua_tolstring(lstate, -1, &(ret.size)); - assert(ret.data != NULL); - ret.data = xmemdupz(ret.data, ret.size); - lua_pop(lstate, 1); - - return ret; -} - -/// Convert lua value to integer -/// -/// Always pops one value from the stack. -Integer nlua_pop_Integer(lua_State *lstate, Error *err) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - if (lua_type(lstate, -1) != LUA_TNUMBER) { - lua_pop(lstate, 1); - api_set_error(err, Validation, "Expected lua number"); - return 0; - } - const lua_Number n = lua_tonumber(lstate, -1); - lua_pop(lstate, 1); - if (n > (lua_Number)API_INTEGER_MAX || n < (lua_Number)API_INTEGER_MIN - || ((lua_Number)((Integer)n)) != n) { - api_set_error(err, Exception, "Number is not integral"); - return 0; - } - return (Integer)n; -} - -/// Convert lua value to boolean -/// -/// Always pops one value from the stack. -Boolean nlua_pop_Boolean(lua_State *lstate, Error *err) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - const Boolean ret = lua_toboolean(lstate, -1); - lua_pop(lstate, 1); - return ret; -} - -/// 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) { - if (err) { - api_set_error(err, Validation, "Expected lua table"); - } - return (LuaTableProps) { .type = kObjectTypeNil }; - } - LuaTableProps table_props = nlua_traverse_table(lstate); - - if (type == kObjectTypeDictionary && table_props.type == kObjectTypeArray - && table_props.maxidx == 0 && !table_props.has_type_key) { - table_props.type = kObjectTypeDictionary; - } - - if (table_props.type != type) { - if (err) { - api_set_error(err, Validation, "Unexpected type"); - } - } - - return table_props; -} - -/// Convert lua table to float -/// -/// Always pops one value from the stack. -Float nlua_pop_Float(lua_State *lstate, Error *err) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - if (lua_type(lstate, -1) == LUA_TNUMBER) { - const Float ret = (Float)lua_tonumber(lstate, -1); - lua_pop(lstate, 1); - 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 without determining whether it is array -/// -/// @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 = table_props.maxidx, .items = NULL }; - - if (ret.size == 0) { - lua_pop(lstate, 1); - return ret; - } - - ret.items = xcalloc(ret.size, sizeof(*ret.items)); - for (size_t i = 1; i <= ret.size; i++) { - Object val; - - lua_rawgeti(lstate, -1, (int)i); - - val = nlua_pop_Object(lstate, err); - if (err->set) { - ret.size = i - 1; - lua_pop(lstate, 1); - api_free_array(ret); - return (Array) { .size = 0, .items = NULL }; - } - ret.items[i - 1] = val; - } - lua_pop(lstate, 1); - - return ret; -} - -/// Convert lua table to 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 -{ - const LuaTableProps table_props = nlua_check_type(lstate, err, - kObjectTypeArray); - 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); - return ret; - } - ret.items = xcalloc(ret.size, sizeof(*ret.items)); - - lua_pushnil(lstate); - for (size_t i = 0; lua_next(lstate, -2) && i < ret.size;) { - // stack: dict, key, value - - if (lua_type(lstate, -2) == LUA_TSTRING) { - lua_pushvalue(lstate, -2); - // stack: dict, key, value, key - - ret.items[i].key = nlua_pop_String(lstate, err); - // stack: dict, key, value - - if (!err->set) { - ret.items[i].value = nlua_pop_Object(lstate, err); - // stack: dict, key - } else { - lua_pop(lstate, 1); - // stack: dict, key - } - - if (err->set) { - ret.size = i; - api_free_dictionary(ret); - lua_pop(lstate, 2); - // stack: - return (Dictionary) { .size = 0, .items = NULL }; - } - i++; - } else { - lua_pop(lstate, 1); - // stack: dict, key - } - } - lua_pop(lstate, 1); - - return ret; -} - -/// Convert lua table to dictionary -/// -/// Always pops one value from the stack. -Dictionary nlua_pop_Dictionary(lua_State *lstate, Error *err) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - 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, table_props, err); -} - -/// Helper structure for nlua_pop_Object -typedef struct { - Object *obj; ///< Location where conversion result is saved. - bool container; ///< True if tv is a container. -} ObjPopStackItem; - -/// Convert lua table to object -/// -/// Always pops one value from the stack. -Object nlua_pop_Object(lua_State *const lstate, Error *const err) -{ - Object ret = NIL; - const int initial_size = lua_gettop(lstate); - kvec_t(ObjPopStackItem) stack = KV_INITIAL_VALUE; - kv_push(stack, ((ObjPopStackItem) { &ret, false })); - while (!err->set && kv_size(stack)) { - if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { - api_set_error(err, Exception, "Lua failed to grow stack"); - break; - } - ObjPopStackItem cur = kv_pop(stack); - if (cur.container) { - if (cur.obj->type == kObjectTypeDictionary) { - // stack: …, dict, key - if (cur.obj->data.dictionary.size - == cur.obj->data.dictionary.capacity) { - lua_pop(lstate, 2); - continue; - } - bool next_key_found = false; - while (lua_next(lstate, -2)) { - // stack: …, dict, new key, val - if (lua_type(lstate, -2) == LUA_TSTRING) { - next_key_found = true; - break; - } - lua_pop(lstate, 1); - // stack: …, dict, new key - } - if (next_key_found) { - // stack: …, dict, new key, val - size_t len; - const char *s = lua_tolstring(lstate, -2, &len); - const size_t idx = cur.obj->data.dictionary.size++; - cur.obj->data.dictionary.items[idx].key = (String) { - .data = xmemdupz(s, len), - .size = len, - }; - kv_push(stack, cur); - cur = (ObjPopStackItem) { - .obj = &cur.obj->data.dictionary.items[idx].value, - .container = false, - }; - } else { - // stack: …, dict - lua_pop(lstate, 1); - // stack: … - continue; - } - } else { - if (cur.obj->data.array.size == cur.obj->data.array.capacity) { - lua_pop(lstate, 1); - continue; - } - const size_t idx = cur.obj->data.array.size++; - lua_rawgeti(lstate, -1, (int)idx + 1); - if (lua_isnil(lstate, -1)) { - lua_pop(lstate, 2); - continue; - } - kv_push(stack, cur); - cur = (ObjPopStackItem) { - .obj = &cur.obj->data.array.items[idx], - .container = false, - }; - } - } - assert(!cur.container); - *cur.obj = NIL; - switch (lua_type(lstate, -1)) { - case LUA_TNIL: { - break; - } - case LUA_TBOOLEAN: { - *cur.obj = BOOLEAN_OBJ(lua_toboolean(lstate, -1)); - break; - } - case LUA_TSTRING: { - size_t len; - const char *s = lua_tolstring(lstate, -1, &len); - *cur.obj = STRING_OBJ(((String) { - .data = xmemdupz(s, len), - .size = len, - })); - break; - } - case LUA_TNUMBER: { - 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) { - *cur.obj = FLOAT_OBJ((Float)n); - } else { - *cur.obj = INTEGER_OBJ((Integer)n); - } - break; - } - case LUA_TTABLE: { - const LuaTableProps table_props = nlua_traverse_table(lstate); - - switch (table_props.type) { - case kObjectTypeArray: { - *cur.obj = ARRAY_OBJ(((Array) { - .items = NULL, - .size = 0, - .capacity = 0, - })); - if (table_props.maxidx != 0) { - cur.obj->data.array.items = - xcalloc(table_props.maxidx, - sizeof(cur.obj->data.array.items[0])); - cur.obj->data.array.capacity = table_props.maxidx; - cur.container = true; - kv_push(stack, cur); - } - break; - } - case kObjectTypeDictionary: { - *cur.obj = DICTIONARY_OBJ(((Dictionary) { - .items = NULL, - .size = 0, - .capacity = 0, - })); - if (table_props.string_keys_num != 0) { - cur.obj->data.dictionary.items = - xcalloc(table_props.string_keys_num, - sizeof(cur.obj->data.dictionary.items[0])); - cur.obj->data.dictionary.capacity = table_props.string_keys_num; - cur.container = true; - kv_push(stack, cur); - lua_pushnil(lstate); - } - break; - } - case kObjectTypeFloat: { - *cur.obj = FLOAT_OBJ((Float)table_props.val); - break; - } - case kObjectTypeNil: { - api_set_error(err, Validation, "Cannot convert given lua table"); - break; - } - default: { - assert(false); - } - } - break; - } - default: { - api_set_error(err, Validation, "Cannot convert given lua type"); - break; - } - } - if (!cur.container) { - lua_pop(lstate, 1); - } - } - kv_destroy(stack); - if (err->set) { - api_free_object(ret); - ret = NIL; - lua_pop(lstate, lua_gettop(lstate) - initial_size + 1); - } - assert(lua_gettop(lstate) == initial_size - 1); - return ret; -} - -#define GENERATE_INDEX_FUNCTION(type) \ -type nlua_pop_##type(lua_State *lstate, Error *err) \ - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \ -{ \ - type ret; \ - NLUA_POP_HANDLE(lstate, type, -1, ret); \ - lua_pop(lstate, 1); \ - return ret; \ -} - -GENERATE_INDEX_FUNCTION(Buffer) -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/converter.h b/src/nvim/viml/executor/converter.h deleted file mode 100644 index dbbaaebf6b..0000000000 --- a/src/nvim/viml/executor/converter.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef NVIM_VIML_EXECUTOR_CONVERTER_H -#define NVIM_VIML_EXECUTOR_CONVERTER_H - -#include <lua.h> -#include <stdbool.h> -#include <stdint.h> - -#include "nvim/api/private/defs.h" -#include "nvim/func_attr.h" -#include "nvim/eval.h" - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "viml/executor/converter.h.generated.h" -#endif -#endif // NVIM_VIML_EXECUTOR_CONVERTER_H diff --git a/src/nvim/viml/executor/executor.c b/src/nvim/viml/executor/executor.c deleted file mode 100644 index 826460772e..0000000000 --- a/src/nvim/viml/executor/executor.c +++ /dev/null @@ -1,576 +0,0 @@ -#include <lua.h> -#include <lualib.h> -#include <lauxlib.h> - -#include "nvim/misc1.h" -#include "nvim/getchar.h" -#include "nvim/garray.h" -#include "nvim/func_attr.h" -#include "nvim/api/private/defs.h" -#include "nvim/api/private/helpers.h" -#include "nvim/api/vim.h" -#include "nvim/vim.h" -#include "nvim/ex_getln.h" -#include "nvim/message.h" -#include "nvim/memline.h" -#include "nvim/buffer_defs.h" -#include "nvim/macros.h" -#include "nvim/screen.h" -#include "nvim/cursor.h" -#include "nvim/undo.h" -#include "nvim/ascii.h" - -#include "nvim/viml/executor/executor.h" -#include "nvim/viml/executor/converter.h" - -typedef struct { - Error err; - String lua_err_str; -} LuaError; - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "viml/executor/vim_module.generated.h" -# include "viml/executor/executor.c.generated.h" -#endif - -/// Name of the run code for use in messages -#define NLUA_EVAL_NAME "<VimL compiled string>" - -/// Call C function which does not expect any arguments -/// -/// @param function Called function -/// @param numret Number of returned arguments -#define NLUA_CALL_C_FUNCTION_0(lstate, function, numret) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_call(lstate, 0, numret); \ - } while (0) -/// Call C function which expects one argument -/// -/// @param function Called function -/// @param numret Number of returned arguments -/// @param a… Supplied argument (should be a void* pointer) -#define NLUA_CALL_C_FUNCTION_1(lstate, function, numret, a1) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_pushlightuserdata(lstate, a1); \ - lua_call(lstate, 1, numret); \ - } while (0) -/// 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 -/// @param a… Supplied argument (should be a void* pointer) -#define NLUA_CALL_C_FUNCTION_3(lstate, function, numret, a1, a2, a3) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_pushlightuserdata(lstate, a1); \ - lua_pushlightuserdata(lstate, a2); \ - lua_pushlightuserdata(lstate, a3); \ - lua_call(lstate, 3, numret); \ - } while (0) -/// Call C function which expects five 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_4(lstate, function, numret, a1, a2, a3, a4) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_pushlightuserdata(lstate, a1); \ - lua_pushlightuserdata(lstate, a2); \ - lua_pushlightuserdata(lstate, a3); \ - lua_pushlightuserdata(lstate, a4); \ - lua_call(lstate, 4, numret); \ - } while (0) - -/// 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 -{ - size_t len; - const char *const str = lua_tolstring(lstate, -1, &len); - - emsgf(msg, (int)len, str); - - lua_pop(lstate, 1); -} - -/// Compare two strings, ignoring case -/// -/// Expects two values on the stack: compared strings. Returns one of the -/// following numbers: 0, -1 or 1. -/// -/// Does no error handling: never call it with non-string or with some arguments -/// omitted. -static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL -{ - const char *s1 = luaL_checklstring(lstate, 1, NULL); - const char *s2 = luaL_checklstring(lstate, 2, NULL); - const int ret = STRICMP(s1, s2); - lua_pop(lstate, 2); - lua_pushnumber(lstate, (lua_Number)((ret > 0) - (ret < 0))); - return 1; -} - -/// Evaluate lua string -/// -/// 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 *const lstate) FUNC_ATTR_NONNULL_ALL -{ - const String *const str = (const String *)lua_touserdata(lstate, 1); - typval_T *const ret_tv = (typval_T *)lua_touserdata(lstate, 2); - lua_pop(lstate, 2); - - if (luaL_loadbuffer(lstate, str->data, str->size, NLUA_EVAL_NAME)) { - nlua_error(lstate, _("E5104: Error while creating lua chunk: %.*s")); - return 0; - } - if (lua_pcall(lstate, 0, 1, 0)) { - nlua_error(lstate, _("E5105: Error while calling lua chunk: %.*s")); - return 0; - } - if (!nlua_pop_typval(lstate, ret_tv)) { - return 0; - } - return 0; -} - -/// Evaluate lua string for each line in range -/// -/// Expects two values on the stack: string to evaluate and pointer to integer -/// array with line range. Always returns nothing (from the lua point of view). -static int nlua_exec_luado_string(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL -{ - const String *const str = (const String *)lua_touserdata(lstate, 1); - const linenr_T *const range = (const linenr_T *)lua_touserdata(lstate, 2); - lua_pop(lstate, 2); - -#define DOSTART "return function(line, linenr) " -#define DOEND " end" - const size_t lcmd_len = (str->size - + (sizeof(DOSTART) - 1) - + (sizeof(DOEND) - 1)); - char *lcmd; - if (lcmd_len < IOSIZE) { - lcmd = (char *)IObuff; - } else { - lcmd = xmalloc(lcmd_len + 1); - } - memcpy(lcmd, DOSTART, sizeof(DOSTART) - 1); - memcpy(lcmd + sizeof(DOSTART) - 1, str->data, str->size); - memcpy(lcmd + sizeof(DOSTART) - 1 + str->size, DOEND, sizeof(DOEND) - 1); -#undef DOSTART -#undef DOEND - - if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) { - nlua_error(lstate, _("E5109: Error while creating lua chunk: %.*s")); - if (lcmd_len >= IOSIZE) { - xfree(lcmd); - } - return 0; - } - if (lcmd_len >= IOSIZE) { - xfree(lcmd); - } - if (lua_pcall(lstate, 0, 1, 0)) { - nlua_error(lstate, _("E5110: Error while creating lua function: %.*s")); - return 0; - } - for (linenr_T l = range[0]; l <= range[1]; l++) { - if (l > curbuf->b_ml.ml_line_count) { - break; - } - lua_pushvalue(lstate, -1); - lua_pushstring(lstate, (const char *)ml_get_buf(curbuf, l, false)); - lua_pushnumber(lstate, (lua_Number)l); - if (lua_pcall(lstate, 2, 1, 0)) { - nlua_error(lstate, _("E5111: Error while calling lua function: %.*s")); - break; - } - if (lua_isstring(lstate, -1)) { - size_t new_line_len; - const char *const new_line = lua_tolstring(lstate, -1, &new_line_len); - char *const new_line_transformed = xmemdupz(new_line, new_line_len); - for (size_t i = 0; i < new_line_len; i++) { - if (new_line_transformed[i] == NUL) { - new_line_transformed[i] = '\n'; - } - } - ml_replace(l, (char_u *)new_line_transformed, false); - changed_bytes(l, 0); - } - lua_pop(lstate, 1); - } - lua_pop(lstate, 1); - check_cursor(); - update_screen(NOT_VALID); - return 0; -} - -/// Evaluate lua file -/// -/// Expects one value on the stack: file to evaluate. Always returns nothing -/// (from the lua point of view). -static int nlua_exec_lua_file(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL -{ - const char *const filename = (const char *)lua_touserdata(lstate, 1); - lua_pop(lstate, 1); - - if (luaL_loadfile(lstate, filename)) { - nlua_error(lstate, _("E5112: Error while creating lua chunk: %.*s")); - return 0; - } - if (lua_pcall(lstate, 0, 0, 0)) { - nlua_error(lstate, _("E5113: Error while calling lua chunk: %.*s")); - return 0; - } - return 0; -} - -/// Initialize lua interpreter state -/// -/// Called by lua interpreter itself to initialize state. -static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL -{ - // stricmp - lua_pushcfunction(lstate, &nlua_stricmp); - lua_setglobal(lstate, "stricmp"); - - // print - lua_pushcfunction(lstate, &nlua_print); - lua_setglobal(lstate, "print"); - - // debug.debug - lua_getglobal(lstate, "debug"); - lua_pushcfunction(lstate, &nlua_debug); - lua_setfield(lstate, -2, "debug"); - lua_pop(lstate, 1); - - // vim - if (luaL_dostring(lstate, (char *)&vim_module[0])) { - nlua_error(lstate, _("E5106: Error while creating vim module: %.*s")); - return 1; - } - // vim.api - nlua_add_api_functions(lstate); - // vim.types, vim.type_idx, vim.val_idx - nlua_init_types(lstate); - lua_setglobal(lstate, "vim"); - return 0; -} - -/// Initialize lua interpreter -/// -/// Crashes NeoVim if initialization fails. Should be called once per lua -/// interpreter instance. -static lua_State *init_lua(void) - FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT -{ - lua_State *lstate = luaL_newstate(); - if (lstate == NULL) { - EMSG(_("E970: Failed to initialize lua interpreter")); - preserve_exit(); - } - luaL_openlibs(lstate); - NLUA_CALL_C_FUNCTION_0(lstate, nlua_state_init, 0); - return lstate; -} - -static lua_State *global_lstate = NULL; - -/// Execute lua string -/// -/// @param[in] str String to execute. -/// @param[out] ret_tv Location where result will be saved. -/// -/// @return Result of the execution. -void executor_exec_lua(const String str, typval_T *const ret_tv) - FUNC_ATTR_NONNULL_ALL -{ - if (global_lstate == NULL) { - global_lstate = init_lua(); - } - - NLUA_CALL_C_FUNCTION_2(global_lstate, nlua_exec_lua_string, 0, - (void *)&str, ret_tv); -} - -/// Evaluate lua string -/// -/// Used for luaeval(). Expects three values on the stack: -/// -/// 1. String to evaluate. -/// 2. _A value. -/// 3. Pointer to location where result is saved. -/// -/// @param[in,out] lstate Lua interpreter state. -static int nlua_eval_lua_string(lua_State *const lstate) - FUNC_ATTR_NONNULL_ALL -{ - const String *const str = (const String *)lua_touserdata(lstate, 1); - typval_T *const arg = (typval_T *)lua_touserdata(lstate, 2); - typval_T *const 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 (" - 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 - if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) { - nlua_error(lstate, - _("E5107: Error while creating lua chunk for luaeval(): %.*s")); - if (lcmd != (char *)IObuff) { - xfree(lcmd); - } - return 0; - } - if (lcmd != (char *)IObuff) { - xfree(lcmd); - } - - if (arg == NULL || arg->v_type == VAR_UNKNOWN) { - lua_pushnil(lstate); - } else { - nlua_push_typval(lstate, arg); - } - if (lua_pcall(lstate, 1, 1, 0)) { - nlua_error(lstate, - _("E5108: Error while calling lua chunk for luaeval(): %.*s")); - return 0; - } - if (!nlua_pop_typval(lstate, ret_tv)) { - return 0; - } - - return 0; -} - -/// Print as a Vim message -/// -/// @param lstate Lua interpreter state. -static int nlua_print(lua_State *const lstate) - FUNC_ATTR_NONNULL_ALL -{ -#define PRINT_ERROR(msg) \ - do { \ - errmsg = msg; \ - errmsg_len = sizeof(msg) - 1; \ - goto nlua_print_error; \ - } while (0) - const int nargs = lua_gettop(lstate); - lua_getglobal(lstate, "tostring"); - const char *errmsg = NULL; - size_t errmsg_len = 0; - garray_T msg_ga; - ga_init(&msg_ga, 1, 80); - int curargidx = 1; - for (; curargidx <= nargs; curargidx++) { - lua_pushvalue(lstate, -1); // tostring - lua_pushvalue(lstate, curargidx); // arg - if (lua_pcall(lstate, 1, 1, 0)) { - errmsg = lua_tolstring(lstate, -1, &errmsg_len); - goto nlua_print_error; - } - size_t len; - const char *const s = lua_tolstring(lstate, -1, &len); - if (s == NULL) { - PRINT_ERROR( - "<Unknown error: lua_tolstring returned NULL for tostring result>"); - } - ga_concat_len(&msg_ga, s, len); - if (curargidx < nargs) { - ga_append(&msg_ga, ' '); - } - lua_pop(lstate, 1); - } -#undef PRINT_ERROR - lua_pop(lstate, nargs + 1); - ga_append(&msg_ga, NUL); - { - const size_t len = (size_t)msg_ga.ga_len - 1; - char *const str = (char *)msg_ga.ga_data; - - for (size_t i = 0; i < len;) { - const size_t start = i; - while (i < len) { - switch (str[i]) { - case NUL: { - str[i] = NL; - i++; - continue; - } - case NL: { - str[i] = NUL; - i++; - break; - } - default: { - i++; - continue; - } - } - break; - } - msg((char_u *)str + start); - } - if (str[len - 1] == NUL) { // Last was newline - msg((char_u *)""); - } - } - ga_clear(&msg_ga); - return 0; -nlua_print_error: - emsgf(_("E5114: Error while converting print argument #%i: %.*s"), - curargidx, errmsg_len, errmsg); - ga_clear(&msg_ga); - lua_pop(lstate, lua_gettop(lstate)); - return 0; -} - -/// debug.debug implementation: interaction with user while debugging -/// -/// @param lstate Lua interpreter state. -int nlua_debug(lua_State *lstate) - FUNC_ATTR_NONNULL_ALL -{ - const typval_T input_args[] = { - { - .v_lock = VAR_FIXED, - .v_type = VAR_STRING, - .vval.v_string = (char_u *)"lua_debug> ", - }, - { - .v_type = VAR_UNKNOWN, - }, - }; - for (;;) { - lua_settop(lstate, 0); - typval_T input; - get_user_input(input_args, &input, false); - msg_putchar('\n'); // Avoid outputting on input line. - if (input.v_type != VAR_STRING - || input.vval.v_string == NULL - || *input.vval.v_string == NUL - || STRCMP(input.vval.v_string, "cont") == 0) { - tv_clear(&input); - return 0; - } - if (luaL_loadbuffer(lstate, (const char *)input.vval.v_string, - STRLEN(input.vval.v_string), "=(debug command)")) { - nlua_error(lstate, _("E5115: Error while loading debug string: %.*s")); - } - tv_clear(&input); - if (lua_pcall(lstate, 0, 0, 0)) { - nlua_error(lstate, _("E5116: Error while calling debug string: %.*s")); - } - } - return 0; -} - -/// Evaluate lua string -/// -/// Used for luaeval(). -/// -/// @param[in] str String to execute. -/// @param[in] arg Second argument to `luaeval()`. -/// @param[out] ret_tv Location where result will be saved. -/// -/// @return Result of the execution. -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(); - } - - NLUA_CALL_C_FUNCTION_3(global_lstate, nlua_eval_lua_string, 0, - (void *)&str, arg, ret_tv); -} - -/// Run lua string -/// -/// Used for :lua. -/// -/// @param eap VimL command being run. -void ex_lua(exarg_T *const eap) - FUNC_ATTR_NONNULL_ALL -{ - size_t len; - char *const code = script_get(eap, &len); - if (eap->skip) { - xfree(code); - return; - } - typval_T tv = { .v_type = VAR_UNKNOWN }; - executor_exec_lua((String) { .data = code, .size = len }, &tv); - tv_clear(&tv); - xfree(code); -} - -/// Run lua string for each line in range -/// -/// Used for :luado. -/// -/// @param eap VimL command being run. -void ex_luado(exarg_T *const eap) - FUNC_ATTR_NONNULL_ALL -{ - if (global_lstate == NULL) { - global_lstate = init_lua(); - } - if (u_save(eap->line1 - 1, eap->line2 + 1) == FAIL) { - EMSG(_("cannot save undo information")); - return; - } - const String cmd = { - .size = STRLEN(eap->arg), - .data = (char *)eap->arg, - }; - const linenr_T range[] = { eap->line1, eap->line2 }; - NLUA_CALL_C_FUNCTION_2(global_lstate, nlua_exec_luado_string, 0, - (void *)&cmd, (void *)range); -} - -/// Run lua file -/// -/// Used for :luafile. -/// -/// @param eap VimL command being run. -void ex_luafile(exarg_T *const eap) - FUNC_ATTR_NONNULL_ALL -{ - if (global_lstate == NULL) { - global_lstate = init_lua(); - } - NLUA_CALL_C_FUNCTION_1(global_lstate, nlua_exec_lua_file, 0, - (void *)eap->arg); -} diff --git a/src/nvim/viml/executor/executor.h b/src/nvim/viml/executor/executor.h deleted file mode 100644 index 648bb73785..0000000000 --- a/src/nvim/viml/executor/executor.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef NVIM_VIML_EXECUTOR_EXECUTOR_H -#define NVIM_VIML_EXECUTOR_EXECUTOR_H - -#include <lua.h> - -#include "nvim/api/private/defs.h" -#include "nvim/func_attr.h" -#include "nvim/eval/typval.h" -#include "nvim/ex_cmds_defs.h" - -// Generated by msgpack-gen.lua -void nlua_add_api_functions(lua_State *lstate) REAL_FATTR_NONNULL_ALL; - -#define set_api_error(s, err) \ - do { \ - Error *err_ = (err); \ - err_->type = kErrorTypeException; \ - err_->set = true; \ - memcpy(&err_->msg[0], s, sizeof(s)); \ - } while (0) - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "viml/executor/executor.h.generated.h" -#endif -#endif // NVIM_VIML_EXECUTOR_EXECUTOR_H diff --git a/src/nvim/viml/executor/vim.lua b/src/nvim/viml/executor/vim.lua deleted file mode 100644 index 8d1c5bdf4f..0000000000 --- a/src/nvim/viml/executor/vim.lua +++ /dev/null @@ -1,2 +0,0 @@ --- TODO(ZyX-I): Create compatibility layer. -return {} |