aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/lua/converter.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/lua/converter.c')
-rw-r--r--src/nvim/lua/converter.c261
1 files changed, 147 insertions, 114 deletions
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index 4598d48c4a..bba771f8a5 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -16,8 +16,8 @@
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/typval_encode.h"
#include "nvim/eval/userfunc.h"
-#include "nvim/func_attr.h"
-#include "nvim/gettext.h"
+#include "nvim/gettext_defs.h"
+#include "nvim/highlight_group.h"
#include "nvim/lua/converter.h"
#include "nvim/lua/executor.h"
#include "nvim/macros_defs.h"
@@ -149,7 +149,7 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate)
}
} else {
if (tsize == 0
- || (tsize == ret.maxidx
+ || (tsize <= ret.maxidx
&& other_keys_num == 0
&& ret.string_keys_num == 0)) {
ret.type = kObjectTypeArray;
@@ -171,11 +171,12 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate)
/// 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).
+ typval_T *tv; ///< Location where conversion result is saved.
+ size_t list_len; ///< Maximum length when tv is a list.
+ 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 Vimscript typval_T
@@ -193,7 +194,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
const int initial_size = lua_gettop(lstate);
kvec_withinit_t(TVPopStackItem, 2) stack = KV_INITIAL_VALUE;
kvi_init(stack);
- kvi_push(stack, ((TVPopStackItem) { ret_tv, false, false, 0 }));
+ kvi_push(stack, ((TVPopStackItem){ .tv = ret_tv }));
while (ret && kv_size(stack)) {
if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) {
semsg(_("E1502: Lua failed to grow stack to %i"), lua_gettop(lstate) + 3);
@@ -232,19 +233,14 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
});
kvi_push(stack, cur);
tv_list_append_list(cur.tv->vval.v_list, kv_pair);
- cur = (TVPopStackItem) {
- .tv = TV_LIST_ITEM_TV(tv_list_last(kv_pair)),
- .container = false,
- .special = false,
- .idx = 0,
- };
+ cur = (TVPopStackItem){ .tv = TV_LIST_ITEM_TV(tv_list_last(kv_pair)) };
} else {
dictitem_T *const di = tv_dict_item_alloc_len(s, len);
if (tv_dict_add(cur.tv->vval.v_dict, di) == FAIL) {
abort();
}
kvi_push(stack, cur);
- cur = (TVPopStackItem) { &di->di_tv, false, false, 0 };
+ cur = (TVPopStackItem){ .tv = &di->di_tv };
}
} else {
lua_pop(lstate, 1);
@@ -252,23 +248,18 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
}
} else {
assert(cur.tv->v_type == VAR_LIST);
- lua_rawgeti(lstate, -1, tv_list_len(cur.tv->vval.v_list) + 1);
- if (lua_isnil(lstate, -1)) {
- lua_pop(lstate, 2);
+ if ((size_t)tv_list_len(cur.tv->vval.v_list) == cur.list_len) {
+ lua_pop(lstate, 1);
continue;
}
+ lua_rawgeti(lstate, -1, tv_list_len(cur.tv->vval.v_list) + 1);
// Not populated yet, need to create list item to push.
tv_list_append_owned_tv(cur.tv->vval.v_list, (typval_T) {
.v_type = VAR_UNKNOWN,
});
kvi_push(stack, cur);
// TODO(ZyX-I): Use indexes, here list item *will* be reallocated.
- cur = (TVPopStackItem) {
- .tv = TV_LIST_ITEM_TV(tv_list_last(cur.tv->vval.v_list)),
- .container = false,
- .special = false,
- .idx = 0,
- };
+ cur = (TVPopStackItem){ .tv = TV_LIST_ITEM_TV(tv_list_last(cur.tv->vval.v_list)) };
}
}
assert(!cur.container);
@@ -332,6 +323,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
cur.tv->vval.v_list = tv_list_alloc((ptrdiff_t)table_props.maxidx);
cur.tv->vval.v_list->lua_table_ref = table_ref;
tv_list_ref(cur.tv->vval.v_list);
+ cur.list_len = table_props.maxidx;
if (table_props.maxidx != 0) {
cur.container = true;
cur.idx = lua_gettop(lstate);
@@ -355,6 +347,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
cur.tv = &val_di->di_tv;
cur.tv->vval.v_list->lua_table_ref = table_ref;
assert(cur.tv->v_type == VAR_LIST);
+ cur.list_len = table_props.string_keys_num;
} else {
cur.tv->v_type = VAR_DICT;
cur.tv->vval.v_dict = tv_dict_alloc();
@@ -372,9 +365,8 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
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"));
+ emsg(_("E5100: Cannot convert given lua table: table should "
+ "contain either only integer keys or only string keys"));
ret = false;
break;
default:
@@ -727,7 +719,7 @@ void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, bool special
}
for (size_t i = 0; i < dict.size; i++) {
nlua_push_String(lstate, dict.items[i].key, special);
- nlua_push_Object(lstate, dict.items[i].value, special);
+ nlua_push_Object(lstate, &dict.items[i].value, special);
lua_rawset(lstate, -3);
}
}
@@ -740,7 +732,7 @@ void nlua_push_Array(lua_State *lstate, const Array array, bool special)
{
lua_createtable(lstate, (int)array.size, 0);
for (size_t i = 0; i < array.size; i++) {
- nlua_push_Object(lstate, array.items[i], special);
+ nlua_push_Object(lstate, &array.items[i], special);
lua_rawseti(lstate, -2, (int)i + 1);
}
}
@@ -761,10 +753,10 @@ GENERATE_INDEX_FUNCTION(Tabpage)
/// Convert given Object to lua value
///
/// Leaves converted value on top of the stack.
-void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
+void nlua_push_Object(lua_State *lstate, Object *obj, bool special)
FUNC_ATTR_NONNULL_ALL
{
- switch (obj.type) {
+ switch (obj->type) {
case kObjectTypeNil:
if (special) {
lua_pushnil(lstate);
@@ -773,12 +765,14 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
}
break;
case kObjectTypeLuaRef: {
- nlua_pushref(lstate, obj.data.luaref);
+ nlua_pushref(lstate, obj->data.luaref);
+ api_free_luaref(obj->data.luaref);
+ obj->data.luaref = LUA_NOREF;
break;
}
#define ADD_TYPE(type, data_key) \
case kObjectType##type: { \
- nlua_push_##type(lstate, obj.data.data_key, special); \
+ nlua_push_##type(lstate, obj->data.data_key, special); \
break; \
}
ADD_TYPE(Boolean, boolean)
@@ -790,7 +784,7 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
#undef ADD_TYPE
#define ADD_REMOTE_TYPE(type) \
case kObjectType##type: { \
- nlua_push_##type(lstate, (type)obj.data.integer, special); \
+ nlua_push_##type(lstate, (type)obj->data.integer, special); \
break; \
}
ADD_REMOTE_TYPE(Buffer)
@@ -803,8 +797,8 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
/// 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
+String nlua_pop_String(lua_State *lstate, Arena *arena, Error *err)
+ FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT
{
if (lua_type(lstate, -1) != LUA_TSTRING) {
lua_pop(lstate, 1);
@@ -815,7 +809,10 @@ String nlua_pop_String(lua_State *lstate, Error *err)
ret.data = (char *)lua_tolstring(lstate, -1, &(ret.size));
assert(ret.data != NULL);
- ret.data = xmemdupz(ret.data, ret.size);
+ // TODO(bfredl): it would be "nice" to just use the memory of the lua string
+ // directly, although ensuring the lifetime of such strings is a bit tricky
+ // (an API call could invoke nested lua, which triggers GC, and kaboom?)
+ ret.data = arena_memdupz(arena, ret.data, ret.size);
lua_pop(lstate, 1);
return ret;
@@ -824,8 +821,8 @@ String nlua_pop_String(lua_State *lstate, Error *err)
/// 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
+Integer nlua_pop_Integer(lua_State *lstate, Arena *arena, Error *err)
+ FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT
{
if (lua_type(lstate, -1) != LUA_TNUMBER) {
lua_pop(lstate, 1);
@@ -848,8 +845,8 @@ Integer nlua_pop_Integer(lua_State *lstate, Error *err)
/// thus `err` is never set as any lua value can be co-erced into a lua bool
///
/// 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
+Boolean nlua_pop_Boolean(lua_State *lstate, Arena *arena, Error *err)
+ FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT
{
const Boolean ret = lua_toboolean(lstate, -1);
lua_pop(lstate, 1);
@@ -923,7 +920,7 @@ static inline LuaTableProps nlua_check_type(lua_State *const lstate, Error *cons
/// Convert lua table to float
///
/// Always pops one value from the stack.
-Float nlua_pop_Float(lua_State *lstate, Error *err)
+Float nlua_pop_Float(lua_State *lstate, Arena *arena, Error *err)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
if (lua_type(lstate, -1) == LUA_TNUMBER) {
@@ -947,29 +944,29 @@ Float nlua_pop_Float(lua_State *lstate, Error *err)
/// @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)
+ Arena *arena, Error *const err)
{
- Array ret = { .size = table_props.maxidx, .items = NULL };
+ Array ret = arena_array(arena, table_props.maxidx);
- if (ret.size == 0) {
+ if (table_props.maxidx == 0) {
lua_pop(lstate, 1);
return ret;
}
- ret.items = xcalloc(ret.size, sizeof(*ret.items));
- for (size_t i = 1; i <= ret.size; i++) {
+ for (size_t i = 1; i <= table_props.maxidx; i++) {
Object val;
lua_rawgeti(lstate, -1, (int)i);
- val = nlua_pop_Object(lstate, false, err);
+ val = nlua_pop_Object(lstate, false, arena, err);
if (ERROR_SET(err)) {
- ret.size = i - 1;
lua_pop(lstate, 1);
- api_free_array(ret);
+ if (!arena) {
+ api_free_array(ret);
+ }
return (Array) { .size = 0, .items = NULL };
}
- ret.items[i - 1] = val;
+ ADD_C(ret, val);
}
lua_pop(lstate, 1);
@@ -979,15 +976,14 @@ static Array nlua_pop_Array_unchecked(lua_State *const lstate, const LuaTablePro
/// 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
+Array nlua_pop_Array(lua_State *lstate, Arena *arena, Error *err)
+ FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT
{
- const LuaTableProps table_props = nlua_check_type(lstate, err,
- kObjectTypeArray);
+ 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);
+ return nlua_pop_Array_unchecked(lstate, table_props, arena, err);
}
/// Convert lua table to dictionary
@@ -999,30 +995,30 @@ Array nlua_pop_Array(lua_State *lstate, Error *err)
/// @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,
- bool ref, Error *err)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+ bool ref, Arena *arena, Error *err)
+ FUNC_ATTR_NONNULL_ARG(1, 5) FUNC_ATTR_WARN_UNUSED_RESULT
{
- Dictionary ret = { .size = table_props.string_keys_num, .items = NULL };
+ Dictionary ret = arena_dict(arena, table_props.string_keys_num);
- if (ret.size == 0) {
+ if (table_props.string_keys_num == 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;) {
+ for (size_t i = 0; lua_next(lstate, -2) && i < table_props.string_keys_num;) {
// 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);
+ String key = nlua_pop_String(lstate, arena, err);
// stack: dict, key, value
if (!ERROR_SET(err)) {
- ret.items[i].value = nlua_pop_Object(lstate, ref, err);
+ Object value = nlua_pop_Object(lstate, ref, arena, err);
+ kv_push_c(ret, ((KeyValuePair) { .key = key, .value = value }));
// stack: dict, key
} else {
lua_pop(lstate, 1);
@@ -1030,8 +1026,9 @@ static Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate, const LuaTabl
}
if (ERROR_SET(err)) {
- ret.size = i;
- api_free_dictionary(ret);
+ if (!arena) {
+ api_free_dictionary(ret);
+ }
lua_pop(lstate, 2);
// stack:
return (Dictionary) { .size = 0, .items = NULL };
@@ -1050,8 +1047,8 @@ static Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate, const LuaTabl
/// Convert lua table to dictionary
///
/// Always pops one value from the stack.
-Dictionary nlua_pop_Dictionary(lua_State *lstate, bool ref, Error *err)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+Dictionary nlua_pop_Dictionary(lua_State *lstate, bool ref, Arena *arena, Error *err)
+ FUNC_ATTR_NONNULL_ARG(1, 4) FUNC_ATTR_WARN_UNUSED_RESULT
{
const LuaTableProps table_props = nlua_check_type(lstate, err,
kObjectTypeDictionary);
@@ -1060,7 +1057,7 @@ Dictionary nlua_pop_Dictionary(lua_State *lstate, bool ref, Error *err)
return (Dictionary) { .size = 0, .items = NULL };
}
- return nlua_pop_Dictionary_unchecked(lstate, table_props, ref, err);
+ return nlua_pop_Dictionary_unchecked(lstate, table_props, ref, arena, err);
}
/// Helper structure for nlua_pop_Object
@@ -1072,13 +1069,14 @@ typedef struct {
/// Convert lua table to object
///
/// Always pops one value from the stack.
-Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
+Object nlua_pop_Object(lua_State *const lstate, bool ref, Arena *arena, Error *const err)
+ FUNC_ATTR_NONNULL_ARG(1, 4) FUNC_ATTR_WARN_UNUSED_RESULT
{
Object ret = NIL;
const int initial_size = lua_gettop(lstate);
kvec_withinit_t(ObjPopStackItem, 2) stack = KV_INITIAL_VALUE;
kvi_init(stack);
- kvi_push(stack, ((ObjPopStackItem) { &ret, false }));
+ kvi_push(stack, ((ObjPopStackItem){ .obj = &ret }));
while (!ERROR_SET(err) && kv_size(stack)) {
ObjPopStackItem cur = kv_pop(stack);
if (cur.container) {
@@ -1088,8 +1086,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
}
if (cur.obj->type == kObjectTypeDictionary) {
// stack: …, dict, key
- if (cur.obj->data.dictionary.size
- == cur.obj->data.dictionary.capacity) {
+ if (cur.obj->data.dictionary.size == cur.obj->data.dictionary.capacity) {
lua_pop(lstate, 2);
continue;
}
@@ -1108,15 +1105,9 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
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,
- };
+ cur.obj->data.dictionary.items[idx].key = CBUF_TO_ARENA_STR(arena, s, len);
kvi_push(stack, cur);
- cur = (ObjPopStackItem) {
- .obj = &cur.obj->data.dictionary.items[idx].value,
- .container = false,
- };
+ cur = (ObjPopStackItem){ .obj = &cur.obj->data.dictionary.items[idx].value };
} else {
// stack: …, dict
lua_pop(lstate, 1);
@@ -1130,15 +1121,8 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
}
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;
- }
kvi_push(stack, cur);
- cur = (ObjPopStackItem) {
- .obj = &cur.obj->data.array.items[idx],
- .container = false,
- };
+ cur = (ObjPopStackItem){ .obj = &cur.obj->data.array.items[idx] };
}
}
assert(!cur.container);
@@ -1152,7 +1136,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
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 }));
+ *cur.obj = STRING_OBJ(CBUF_TO_ARENA_STR(arena, s, len));
break;
}
case LUA_TNUMBER: {
@@ -1170,23 +1154,17 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
switch (table_props.type) {
case kObjectTypeArray:
- *cur.obj = ARRAY_OBJ(((Array) { .items = NULL, .size = 0, .capacity = 0 }));
+ *cur.obj = ARRAY_OBJ(((Array)ARRAY_DICT_INIT));
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.obj->data.array = arena_array(arena, table_props.maxidx);
cur.container = true;
kvi_push(stack, cur);
}
break;
case kObjectTypeDictionary:
- *cur.obj = DICTIONARY_OBJ(((Dictionary) { .items = NULL, .size = 0, .capacity = 0 }));
+ *cur.obj = DICTIONARY_OBJ(((Dictionary)ARRAY_DICT_INIT));
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.obj->data.dictionary = arena_dict(arena, table_props.string_keys_num);
cur.container = true;
kvi_push(stack, cur);
lua_pushnil(lstate);
@@ -1238,7 +1216,9 @@ type_error:
}
kvi_destroy(stack);
if (ERROR_SET(err)) {
- api_free_object(ret);
+ if (!arena) {
+ api_free_object(ret);
+ }
ret = NIL;
lua_pop(lstate, lua_gettop(lstate) - initial_size + 1);
}
@@ -1246,20 +1226,20 @@ type_error:
return ret;
}
-LuaRef nlua_pop_LuaRef(lua_State *const lstate, Error *err)
+LuaRef nlua_pop_LuaRef(lua_State *const lstate, Arena *arena, Error *err)
{
LuaRef rv = nlua_ref_global(lstate, -1);
lua_pop(lstate, 1);
return rv;
}
-handle_T nlua_pop_handle(lua_State *lstate, Error *err)
+handle_T nlua_pop_handle(lua_State *lstate, Arena *arena, Error *err)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
handle_T ret;
if (lua_type(lstate, -1) != LUA_TNUMBER) {
api_set_error(err, kErrorTypeValidation, "Expected Lua number");
- ret = (handle_T) - 1;
+ ret = (handle_T)(-1);
} else {
ret = (handle_T)lua_tonumber(lstate, -1);
}
@@ -1315,7 +1295,8 @@ void nlua_init_types(lua_State *const lstate)
}
// lua specific variant of api_dict_to_keydict
-void nlua_pop_keydict(lua_State *L, void *retval, FieldHashfn hashy, char **err_opt, Error *err)
+void nlua_pop_keydict(lua_State *L, void *retval, FieldHashfn hashy, char **err_opt, Arena *arena,
+ Error *err)
{
if (!lua_istable(L, -1)) {
api_set_error(err, kErrorTypeValidation, "Expected Lua table");
@@ -1342,24 +1323,31 @@ void nlua_pop_keydict(lua_State *L, void *retval, FieldHashfn hashy, char **err_
char *mem = ((char *)retval + field->ptr_off);
if (field->type == kObjectTypeNil) {
- *(Object *)mem = nlua_pop_Object(L, true, err);
+ *(Object *)mem = nlua_pop_Object(L, true, arena, err);
} else if (field->type == kObjectTypeInteger) {
- *(Integer *)mem = nlua_pop_Integer(L, err);
+ if (field->is_hlgroup && lua_type(L, -1) == LUA_TSTRING) {
+ size_t name_len;
+ const char *name = lua_tolstring(L, -1, &name_len);
+ lua_pop(L, 1);
+ *(Integer *)mem = name_len > 0 ? syn_check_group(name, name_len) : 0;
+ } else {
+ *(Integer *)mem = nlua_pop_Integer(L, arena, err);
+ }
} else if (field->type == kObjectTypeBoolean) {
*(Boolean *)mem = nlua_pop_Boolean_strict(L, err);
} else if (field->type == kObjectTypeString) {
- *(String *)mem = nlua_pop_String(L, err);
+ *(String *)mem = nlua_pop_String(L, arena, err);
} else if (field->type == kObjectTypeFloat) {
- *(Float *)mem = nlua_pop_Float(L, err);
+ *(Float *)mem = nlua_pop_Float(L, arena, err);
} else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow
|| field->type == kObjectTypeTabpage) {
- *(handle_T *)mem = nlua_pop_handle(L, err);
+ *(handle_T *)mem = nlua_pop_handle(L, arena, err);
} else if (field->type == kObjectTypeArray) {
- *(Array *)mem = nlua_pop_Array(L, err);
+ *(Array *)mem = nlua_pop_Array(L, arena, err);
} else if (field->type == kObjectTypeDictionary) {
- *(Dictionary *)mem = nlua_pop_Dictionary(L, false, err);
+ *(Dictionary *)mem = nlua_pop_Dictionary(L, false, arena, err);
} else if (field->type == kObjectTypeLuaRef) {
- *(LuaRef *)mem = nlua_pop_LuaRef(L, err);
+ *(LuaRef *)mem = nlua_pop_LuaRef(L, arena, err);
} else {
abort();
}
@@ -1372,3 +1360,48 @@ void nlua_pop_keydict(lua_State *L, void *retval, FieldHashfn hashy, char **err_
lua_pop(L, 1);
// []
}
+
+void nlua_push_keydict(lua_State *L, void *value, KeySetLink *table)
+{
+ lua_createtable(L, 0, 0);
+ for (size_t i = 0; table[i].str; i++) {
+ KeySetLink *field = &table[i];
+ bool is_set = true;
+ if (field->opt_index >= 0) {
+ OptKeySet *ks = (OptKeySet *)value;
+ is_set = ks->is_set_ & (1ULL << field->opt_index);
+ }
+
+ if (!is_set) {
+ continue;
+ }
+
+ char *mem = ((char *)value + field->ptr_off);
+
+ lua_pushstring(L, field->str);
+ if (field->type == kObjectTypeNil) {
+ nlua_push_Object(L, (Object *)mem, false);
+ } else if (field->type == kObjectTypeInteger) {
+ lua_pushinteger(L, *(Integer *)mem);
+ } else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow
+ || field->type == kObjectTypeTabpage) {
+ lua_pushinteger(L, *(handle_T *)mem);
+ } else if (field->type == kObjectTypeFloat) {
+ lua_pushnumber(L, *(Float *)mem);
+ } else if (field->type == kObjectTypeBoolean) {
+ lua_pushboolean(L, *(Boolean *)mem);
+ } else if (field->type == kObjectTypeString) {
+ nlua_push_String(L, *(String *)mem, false);
+ } else if (field->type == kObjectTypeArray) {
+ nlua_push_Array(L, *(Array *)mem, false);
+ } else if (field->type == kObjectTypeDictionary) {
+ nlua_push_Dictionary(L, *(Dictionary *)mem, false);
+ } else if (field->type == kObjectTypeLuaRef) {
+ nlua_pushref(L, *(LuaRef *)mem);
+ } else {
+ abort();
+ }
+
+ lua_rawset(L, -3);
+ }
+}