converter.c (43557B)
1 #include <assert.h> 2 #include <lauxlib.h> 3 #include <lua.h> 4 #include <stdbool.h> 5 #include <stddef.h> 6 #include <stdint.h> 7 #include <stdlib.h> 8 #include <string.h> 9 10 #include "klib/kvec.h" 11 #include "nvim/api/private/defs.h" 12 #include "nvim/api/private/helpers.h" 13 #include "nvim/ascii_defs.h" 14 #include "nvim/eval/decode.h" 15 #include "nvim/eval/typval.h" 16 #include "nvim/eval/typval_defs.h" 17 #include "nvim/eval/typval_encode.h" 18 #include "nvim/eval/userfunc.h" 19 #include "nvim/gettext_defs.h" 20 #include "nvim/highlight_group.h" 21 #include "nvim/lua/converter.h" 22 #include "nvim/lua/executor.h" 23 #include "nvim/macros_defs.h" 24 #include "nvim/memory.h" 25 #include "nvim/memory_defs.h" 26 #include "nvim/message.h" 27 #include "nvim/types_defs.h" 28 #include "nvim/vim_defs.h" 29 30 /// Determine, which keys Lua table contains 31 typedef struct { 32 size_t maxidx; ///< Maximum positive integral value found. 33 size_t string_keys_num; ///< Number of string keys. 34 bool has_string_with_nul; ///< True if there is string key with NUL byte. 35 ObjectType type; ///< If has_type_key is true then attached value. Otherwise 36 ///< either kObjectTypeNil, kObjectTypeDict or 37 ///< kObjectTypeArray, depending on other properties. 38 lua_Number val; ///< If has_val_key and val_type == LUA_TNUMBER: value. 39 bool has_type_key; ///< True if type key is present. 40 } LuaTableProps; 41 42 #include "lua/converter.c.generated.h" 43 44 #define TYPE_IDX_VALUE true 45 #define VAL_IDX_VALUE false 46 47 #define LUA_PUSH_STATIC_STRING(lstate, s) \ 48 lua_pushlstring(lstate, s, sizeof(s) - 1) 49 50 static LuaTableProps nlua_traverse_table(lua_State *const lstate) 51 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 52 { 53 size_t tsize = 0; // Total number of keys. 54 int val_type = 0; // If has_val_key: Lua type of the value. 55 bool has_val_key = false; // True if val key was found, 56 // @see nlua_push_val_idx(). 57 size_t other_keys_num = 0; // Number of keys that are not string, integral 58 // or type keys. 59 LuaTableProps ret; 60 CLEAR_FIELD(ret); 61 if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { 62 semsg(_("E1502: Lua failed to grow stack to %i"), lua_gettop(lstate) + 2); 63 ret.type = kObjectTypeNil; 64 return ret; 65 } 66 lua_pushnil(lstate); 67 while (lua_next(lstate, -2)) { 68 switch (lua_type(lstate, -2)) { 69 case LUA_TSTRING: { 70 size_t len; 71 const char *s = lua_tolstring(lstate, -2, &len); 72 if (memchr(s, NUL, len) != NULL) { 73 ret.has_string_with_nul = true; 74 } 75 ret.string_keys_num++; 76 break; 77 } 78 case LUA_TNUMBER: { 79 const lua_Number n = lua_tonumber(lstate, -2); 80 if (n > (lua_Number)SIZE_MAX || n <= 0 81 || ((lua_Number)((size_t)n)) != n) { 82 other_keys_num++; 83 } else { 84 const size_t idx = (size_t)n; 85 if (idx > ret.maxidx) { 86 ret.maxidx = idx; 87 } 88 } 89 break; 90 } 91 case LUA_TBOOLEAN: { 92 const bool b = lua_toboolean(lstate, -2); 93 if (b == TYPE_IDX_VALUE) { 94 if (lua_type(lstate, -1) == LUA_TNUMBER) { 95 lua_Number n = lua_tonumber(lstate, -1); 96 if (n == (lua_Number)kObjectTypeFloat 97 || n == (lua_Number)kObjectTypeArray 98 || n == (lua_Number)kObjectTypeDict) { 99 ret.has_type_key = true; 100 ret.type = (ObjectType)n; 101 } else { 102 other_keys_num++; 103 } 104 } else { 105 other_keys_num++; 106 } 107 } else { 108 has_val_key = true; 109 val_type = lua_type(lstate, -1); 110 if (val_type == LUA_TNUMBER) { 111 ret.val = lua_tonumber(lstate, -1); 112 } 113 } 114 break; 115 } 116 default: 117 other_keys_num++; 118 break; 119 } 120 tsize++; 121 lua_pop(lstate, 1); 122 } 123 if (ret.has_type_key) { 124 assert(tsize > 0); 125 if (ret.type == kObjectTypeFloat 126 && (!has_val_key || val_type != LUA_TNUMBER)) { 127 ret.type = kObjectTypeNil; 128 } else if (ret.type == kObjectTypeArray) { 129 // Determine what is the last number in a *sequence* of keys. 130 // This condition makes sure that Neovim will not crash when it gets table 131 // {[vim.type_idx]=vim.types.array, [SIZE_MAX]=1}: without it maxidx will 132 // be SIZE_MAX, with this condition it should be zero and [SIZE_MAX] key 133 // should be ignored. 134 if (ret.maxidx != 0 135 && ret.maxidx != (tsize 136 - ret.has_type_key 137 - other_keys_num 138 - has_val_key 139 - ret.string_keys_num)) { 140 for (ret.maxidx = 0;; ret.maxidx++) { 141 lua_rawgeti(lstate, -1, (int)ret.maxidx + 1); 142 if (lua_isnil(lstate, -1)) { 143 lua_pop(lstate, 1); 144 break; 145 } 146 lua_pop(lstate, 1); 147 } 148 } 149 } 150 } else { 151 if (tsize == 0 152 || (tsize <= ret.maxidx 153 && other_keys_num == 0 154 && ret.string_keys_num == 0)) { 155 ret.type = kObjectTypeArray; 156 if (tsize == 0 && lua_getmetatable(lstate, -1)) { 157 nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); 158 if (lua_rawequal(lstate, -2, -1)) { 159 ret.type = kObjectTypeDict; 160 } 161 lua_pop(lstate, 2); 162 } 163 } else if (ret.string_keys_num == tsize) { 164 ret.type = kObjectTypeDict; 165 } else { 166 ret.type = kObjectTypeNil; 167 } 168 } 169 return ret; 170 } 171 172 /// Helper structure for nlua_pop_typval 173 typedef struct { 174 typval_T *tv; ///< Location where conversion result is saved. 175 size_t list_len; ///< Maximum length when tv is a list. 176 bool container; ///< True if tv is a container. 177 bool special; ///< If true then tv is a _VAL part of special dict. 178 ///< that represents mapping. 179 int idx; ///< Container index (used to detect self-referencing structures). 180 } TVPopStackItem; 181 182 /// Convert Lua object to Vimscript typval_T 183 /// 184 /// Should pop exactly one value from Lua stack. 185 /// 186 /// @param lstate Lua state. 187 /// @param[out] ret_tv Where to put the result. 188 /// 189 /// @return `true` in case of success, `false` in case of failure. Error is 190 /// reported automatically. 191 bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) 192 { 193 bool ret = true; 194 const int initial_size = lua_gettop(lstate); 195 kvec_withinit_t(TVPopStackItem, 2) stack = KV_INITIAL_VALUE; 196 kvi_init(stack); 197 kvi_push(stack, ((TVPopStackItem){ .tv = ret_tv })); 198 while (ret && kv_size(stack)) { 199 if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { 200 semsg(_("E1502: Lua failed to grow stack to %i"), lua_gettop(lstate) + 3); 201 ret = false; 202 break; 203 } 204 TVPopStackItem cur = kv_pop(stack); 205 if (cur.container) { 206 if (cur.special || cur.tv->v_type == VAR_DICT) { 207 assert(cur.tv->v_type == (cur.special ? VAR_LIST : VAR_DICT)); 208 bool next_key_found = false; 209 while (lua_next(lstate, -2)) { 210 if (lua_type(lstate, -2) == LUA_TSTRING) { 211 next_key_found = true; 212 break; 213 } 214 lua_pop(lstate, 1); 215 } 216 if (next_key_found) { 217 size_t len; 218 const char *s = lua_tolstring(lstate, -2, &len); 219 if (cur.special) { 220 list_T *const kv_pair = tv_list_alloc(2); 221 222 typval_T s_tv = decode_string(s, len, true, false); 223 tv_list_append_owned_tv(kv_pair, s_tv); 224 225 // Value: not populated yet, need to create list item to push. 226 tv_list_append_owned_tv(kv_pair, (typval_T) { 227 .v_type = VAR_UNKNOWN, 228 }); 229 kvi_push(stack, cur); 230 tv_list_append_list(cur.tv->vval.v_list, kv_pair); 231 cur = (TVPopStackItem){ .tv = TV_LIST_ITEM_TV(tv_list_last(kv_pair)) }; 232 } else { 233 dictitem_T *const di = tv_dict_item_alloc_len(s, len); 234 if (tv_dict_add(cur.tv->vval.v_dict, di) == FAIL) { 235 abort(); 236 } 237 kvi_push(stack, cur); 238 cur = (TVPopStackItem){ .tv = &di->di_tv }; 239 } 240 } else { 241 lua_pop(lstate, 1); 242 continue; 243 } 244 } else { 245 assert(cur.tv->v_type == VAR_LIST); 246 if ((size_t)tv_list_len(cur.tv->vval.v_list) == cur.list_len) { 247 lua_pop(lstate, 1); 248 continue; 249 } 250 lua_rawgeti(lstate, -1, tv_list_len(cur.tv->vval.v_list) + 1); 251 // Not populated yet, need to create list item to push. 252 tv_list_append_owned_tv(cur.tv->vval.v_list, (typval_T) { 253 .v_type = VAR_UNKNOWN, 254 }); 255 kvi_push(stack, cur); 256 // TODO(ZyX-I): Use indexes, here list item *will* be reallocated. 257 cur = (TVPopStackItem){ .tv = TV_LIST_ITEM_TV(tv_list_last(cur.tv->vval.v_list)) }; 258 } 259 } 260 assert(!cur.container); 261 *cur.tv = (typval_T) { 262 .v_type = VAR_NUMBER, 263 .v_lock = VAR_UNLOCKED, 264 .vval = { .v_number = 0 }, 265 }; 266 switch (lua_type(lstate, -1)) { 267 case LUA_TNIL: 268 cur.tv->v_type = VAR_SPECIAL; 269 cur.tv->vval.v_special = kSpecialVarNull; 270 break; 271 case LUA_TBOOLEAN: 272 cur.tv->v_type = VAR_BOOL; 273 cur.tv->vval.v_bool = (lua_toboolean(lstate, -1) ? kBoolVarTrue : kBoolVarFalse); 274 break; 275 case LUA_TSTRING: { 276 size_t len; 277 const char *s = lua_tolstring(lstate, -1, &len); 278 *cur.tv = decode_string(s, len, false, false); 279 break; 280 } 281 case LUA_TNUMBER: { 282 const lua_Number n = lua_tonumber(lstate, -1); 283 if (n > (lua_Number)VARNUMBER_MAX || n < (lua_Number)VARNUMBER_MIN 284 || ((lua_Number)((varnumber_T)n)) != n) { 285 cur.tv->v_type = VAR_FLOAT; 286 cur.tv->vval.v_float = (float_T)n; 287 } else { 288 cur.tv->v_type = VAR_NUMBER; 289 cur.tv->vval.v_number = (varnumber_T)n; 290 } 291 break; 292 } 293 case LUA_TTABLE: { 294 // Only need to track table refs if we have a metatable associated. 295 LuaRef table_ref = LUA_NOREF; 296 if (lua_getmetatable(lstate, -1)) { 297 lua_pop(lstate, 1); 298 table_ref = nlua_ref_global(lstate, -1); 299 } 300 301 const LuaTableProps table_props = nlua_traverse_table(lstate); 302 303 for (size_t i = 0; i < kv_size(stack); i++) { 304 const TVPopStackItem item = kv_A(stack, i); 305 if (item.container && lua_rawequal(lstate, -1, item.idx)) { 306 tv_copy(item.tv, cur.tv); 307 cur.container = false; 308 goto nlua_pop_typval_table_processing_end; 309 } 310 } 311 312 switch (table_props.type) { 313 case kObjectTypeArray: 314 cur.tv->v_type = VAR_LIST; 315 cur.tv->vval.v_list = tv_list_alloc((ptrdiff_t)table_props.maxidx); 316 cur.tv->vval.v_list->lua_table_ref = table_ref; 317 tv_list_ref(cur.tv->vval.v_list); 318 cur.list_len = table_props.maxidx; 319 if (table_props.maxidx != 0) { 320 cur.container = true; 321 cur.idx = lua_gettop(lstate); 322 kvi_push(stack, cur); 323 } 324 break; 325 case kObjectTypeDict: 326 if (table_props.string_keys_num == 0) { 327 cur.tv->v_type = VAR_DICT; 328 cur.tv->vval.v_dict = tv_dict_alloc(); 329 cur.tv->vval.v_dict->dv_refcount++; 330 cur.tv->vval.v_dict->lua_table_ref = table_ref; 331 } else { 332 cur.special = table_props.has_string_with_nul; 333 if (table_props.has_string_with_nul) { 334 decode_create_map_special_dict(cur.tv, (ptrdiff_t)table_props.string_keys_num); 335 assert(cur.tv->v_type == VAR_DICT); 336 dictitem_T *const val_di = tv_dict_find(cur.tv->vval.v_dict, 337 S_LEN("_VAL")); 338 assert(val_di != NULL); 339 cur.tv = &val_di->di_tv; 340 cur.tv->vval.v_list->lua_table_ref = table_ref; 341 assert(cur.tv->v_type == VAR_LIST); 342 cur.list_len = table_props.string_keys_num; 343 } else { 344 cur.tv->v_type = VAR_DICT; 345 cur.tv->vval.v_dict = tv_dict_alloc(); 346 cur.tv->vval.v_dict->dv_refcount++; 347 cur.tv->vval.v_dict->lua_table_ref = table_ref; 348 } 349 cur.container = true; 350 cur.idx = lua_gettop(lstate); 351 kvi_push(stack, cur); 352 lua_pushnil(lstate); 353 } 354 break; 355 case kObjectTypeFloat: 356 cur.tv->v_type = VAR_FLOAT; 357 cur.tv->vval.v_float = (float_T)table_props.val; 358 break; 359 case kObjectTypeNil: 360 emsg(_("E5100: Cannot convert given Lua table: table should " 361 "contain either only integer keys or only string keys")); 362 ret = false; 363 break; 364 default: 365 abort(); 366 } 367 nlua_pop_typval_table_processing_end: 368 break; 369 } 370 case LUA_TFUNCTION: { 371 LuaRef func = nlua_ref_global(lstate, -1); 372 373 char *name = register_luafunc(func); 374 375 cur.tv->v_type = VAR_FUNC; 376 cur.tv->vval.v_string = xstrdup(name); 377 break; 378 } 379 case LUA_TUSERDATA: { 380 // TODO(bfredl): check mt.__call and convert to function? 381 nlua_pushref(lstate, nlua_global_refs->nil_ref); 382 bool is_nil = lua_rawequal(lstate, -2, -1); 383 lua_pop(lstate, 1); 384 if (is_nil) { 385 cur.tv->v_type = VAR_SPECIAL; 386 cur.tv->vval.v_special = kSpecialVarNull; 387 } else { 388 emsg(_("E5101: Cannot convert given Lua type")); 389 ret = false; 390 } 391 break; 392 } 393 default: 394 emsg(_("E5101: Cannot convert given Lua type")); 395 ret = false; 396 break; 397 } 398 if (!cur.container) { 399 lua_pop(lstate, 1); 400 } 401 } 402 kvi_destroy(stack); 403 if (!ret) { 404 tv_clear(ret_tv); 405 *ret_tv = (typval_T) { 406 .v_type = VAR_NUMBER, 407 .v_lock = VAR_UNLOCKED, 408 .vval = { .v_number = 0 }, 409 }; 410 lua_pop(lstate, lua_gettop(lstate) - initial_size + 1); 411 } 412 assert(lua_gettop(lstate) == initial_size - 1); 413 return ret; 414 } 415 416 static bool typval_conv_special = false; 417 418 #define TYPVAL_ENCODE_ALLOW_SPECIALS true 419 420 #define TYPVAL_ENCODE_CHECK_BEFORE 421 422 #define TYPVAL_ENCODE_CONV_NIL(tv) \ 423 do { \ 424 if (typval_conv_special) { \ 425 lua_pushnil(lstate); \ 426 } else { \ 427 nlua_pushref(lstate, nlua_global_refs->nil_ref); \ 428 } \ 429 } while (0) 430 431 #define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ 432 lua_pushboolean(lstate, (bool)(num)) 433 434 #define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ 435 lua_pushnumber(lstate, (lua_Number)(num)) 436 437 #define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER TYPVAL_ENCODE_CONV_NUMBER 438 439 #define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ 440 TYPVAL_ENCODE_CONV_NUMBER(tv, flt) 441 442 #define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \ 443 lua_pushlstring(lstate, (str), (len)) 444 445 #define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING 446 447 #define TYPVAL_ENCODE_CONV_EXT_STRING(tv, str, len, type) \ 448 TYPVAL_ENCODE_CONV_NIL(tv) 449 450 #define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \ 451 do { \ 452 const blob_T *const blob_ = (blob); \ 453 lua_pushlstring(lstate, blob_ != NULL ? blob_->bv_ga.ga_data : "", (size_t)(len)); \ 454 } while (0) 455 456 #define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun, prefix) \ 457 do { \ 458 const char *const fun_ = (fun); \ 459 ufunc_T *fp; \ 460 if (fun_ != NULL && (fp = find_func(fun_)) != NULL && fp->uf_flags & FC_LUAREF) { \ 461 nlua_pushref(lstate, fp->uf_luaref); \ 462 } else { \ 463 TYPVAL_ENCODE_CONV_NIL(tv); \ 464 } \ 465 goto typval_encode_stop_converting_one_item; \ 466 } while (0) 467 468 #define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len) 469 #define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len) 470 #define TYPVAL_ENCODE_CONV_FUNC_END(tv) 471 472 #define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \ 473 lua_createtable(lstate, 0, 0) 474 475 #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ 476 do { \ 477 if (typval_conv_special) { \ 478 nlua_create_typed_table(lstate, 0, 0, kObjectTypeDict); \ 479 } else { \ 480 lua_createtable(lstate, 0, 0); \ 481 nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); \ 482 lua_setmetatable(lstate, -2); \ 483 } \ 484 } while (0) 485 486 #define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ 487 do { \ 488 if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { \ 489 semsg(_("E5102: Lua failed to grow stack to %i"), \ 490 lua_gettop(lstate) + 3); \ 491 return false; \ 492 } \ 493 lua_createtable(lstate, (int)(len), 0); \ 494 lua_pushnumber(lstate, 1); \ 495 } while (0) 496 497 #define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) 498 499 #define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) \ 500 do { \ 501 lua_Number idx = lua_tonumber(lstate, -2); \ 502 lua_rawset(lstate, -3); \ 503 lua_pushnumber(lstate, idx + 1); \ 504 } while (0) 505 506 #define TYPVAL_ENCODE_CONV_LIST_END(tv) \ 507 lua_rawset(lstate, -3) 508 509 #define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \ 510 do { \ 511 if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { \ 512 semsg(_("E5102: Lua failed to grow stack to %i"), \ 513 lua_gettop(lstate) + 3); \ 514 return false; \ 515 } \ 516 lua_createtable(lstate, 0, (int)(len)); \ 517 } while (0) 518 519 #define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(label, kv_pair) 520 521 #define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv) 522 523 #define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict) 524 525 #define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) \ 526 lua_rawset(lstate, -3) 527 528 #define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \ 529 TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) 530 531 #define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ 532 do { \ 533 for (size_t backref = kv_size(*mpstack); backref; backref--) { \ 534 const MPConvStackVal mpval = kv_A(*mpstack, backref - 1); \ 535 if (mpval.type == conv_type) { \ 536 if (conv_type == kMPConvDict \ 537 ? (void *)mpval.data.d.dict == (void *)(val) \ 538 : (void *)mpval.data.l.list == (void *)(val)) { \ 539 lua_pushvalue(lstate, \ 540 -((int)((kv_size(*mpstack) - backref + 1) * 2))); \ 541 break; \ 542 } \ 543 } \ 544 } \ 545 } while (0) 546 547 #define TYPVAL_ENCODE_SCOPE static 548 #define TYPVAL_ENCODE_NAME lua 549 #define TYPVAL_ENCODE_FIRST_ARG_TYPE lua_State *const 550 #define TYPVAL_ENCODE_FIRST_ARG_NAME lstate 551 #include "nvim/eval/typval_encode.c.h" 552 553 #undef TYPVAL_ENCODE_SCOPE 554 #undef TYPVAL_ENCODE_NAME 555 #undef TYPVAL_ENCODE_FIRST_ARG_TYPE 556 #undef TYPVAL_ENCODE_FIRST_ARG_NAME 557 558 #undef TYPVAL_ENCODE_CONV_STRING 559 #undef TYPVAL_ENCODE_CONV_STR_STRING 560 #undef TYPVAL_ENCODE_CONV_EXT_STRING 561 #undef TYPVAL_ENCODE_CONV_BLOB 562 #undef TYPVAL_ENCODE_CONV_NUMBER 563 #undef TYPVAL_ENCODE_CONV_FLOAT 564 #undef TYPVAL_ENCODE_CONV_FUNC_START 565 #undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS 566 #undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF 567 #undef TYPVAL_ENCODE_CONV_FUNC_END 568 #undef TYPVAL_ENCODE_CONV_EMPTY_LIST 569 #undef TYPVAL_ENCODE_CONV_LIST_START 570 #undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START 571 #undef TYPVAL_ENCODE_CONV_EMPTY_DICT 572 #undef TYPVAL_ENCODE_CHECK_BEFORE 573 #undef TYPVAL_ENCODE_CONV_NIL 574 #undef TYPVAL_ENCODE_CONV_BOOL 575 #undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER 576 #undef TYPVAL_ENCODE_CONV_DICT_START 577 #undef TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START 578 #undef TYPVAL_ENCODE_CONV_DICT_END 579 #undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY 580 #undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS 581 #undef TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK 582 #undef TYPVAL_ENCODE_CONV_LIST_END 583 #undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS 584 #undef TYPVAL_ENCODE_CONV_RECURSE 585 #undef TYPVAL_ENCODE_ALLOW_SPECIALS 586 587 /// Convert Vimscript typval_T to Lua value 588 /// 589 /// Should leave single value in Lua stack. May only fail if Lua failed to grow stack. 590 /// 591 /// @param lstate Lua interpreter state. 592 /// @param[in] tv typval_T to convert. 593 /// 594 /// @return true in case of success, false otherwise. 595 bool nlua_push_typval(lua_State *lstate, typval_T *const tv, int flags) 596 { 597 typval_conv_special = (flags & kNluaPushSpecial); 598 const int initial_size = lua_gettop(lstate); 599 600 if (!lua_checkstack(lstate, initial_size + 2)) { 601 semsg(_("E1502: Lua failed to grow stack to %i"), initial_size + 4); 602 return false; 603 } 604 if (encode_vim_to_lua(lstate, tv, "nlua_push_typval argument") == FAIL) { 605 return false; 606 } 607 assert(lua_gettop(lstate) == initial_size + 1); 608 return true; 609 } 610 611 /// Push value which is a type index 612 /// 613 /// Used for all “typed” tables: i.e. for all tables which represent Vimscript values. 614 static inline void nlua_push_type_idx(lua_State *lstate) 615 FUNC_ATTR_NONNULL_ALL 616 { 617 lua_pushboolean(lstate, TYPE_IDX_VALUE); 618 } 619 620 /// Push value which is a value index 621 /// 622 /// Used for tables which represent scalar values, like float value. 623 static inline void nlua_push_val_idx(lua_State *lstate) 624 FUNC_ATTR_NONNULL_ALL 625 { 626 lua_pushboolean(lstate, VAL_IDX_VALUE); 627 } 628 629 /// Push type 630 /// 631 /// Type is a value in vim.types table. 632 /// 633 /// @param[out] lstate Lua state. 634 /// @param[in] type Type to push. 635 static inline void nlua_push_type(lua_State *lstate, ObjectType type) 636 FUNC_ATTR_NONNULL_ALL 637 { 638 lua_pushnumber(lstate, (lua_Number)type); 639 } 640 641 /// Create Lua table which has an entry that determines its Vimscript type 642 /// 643 /// @param[out] lstate Lua state. 644 /// @param[in] narr Number of “array” entries to be populated later. 645 /// @param[in] nrec Number of “dictionary” entries to be populated later. 646 /// @param[in] type Type of the table. 647 static inline void nlua_create_typed_table(lua_State *lstate, const size_t narr, const size_t nrec, 648 const ObjectType type) 649 FUNC_ATTR_NONNULL_ALL 650 { 651 lua_createtable(lstate, (int)narr, (int)(1 + nrec)); 652 nlua_push_type_idx(lstate); 653 nlua_push_type(lstate, type); 654 lua_rawset(lstate, -3); 655 } 656 657 /// Convert given String to Lua string 658 /// 659 /// Leaves converted string on top of the stack. 660 void nlua_push_String(lua_State *lstate, const String s, int flags) 661 FUNC_ATTR_NONNULL_ALL 662 { 663 lua_pushlstring(lstate, s.size ? s.data : "", s.size); 664 } 665 666 /// Convert given Integer to Lua number 667 /// 668 /// Leaves converted number on top of the stack. 669 void nlua_push_Integer(lua_State *lstate, const Integer n, int flags) 670 FUNC_ATTR_NONNULL_ALL 671 { 672 lua_pushnumber(lstate, (lua_Number)n); 673 } 674 675 /// Convert given Float to Lua table 676 /// 677 /// Leaves converted table on top of the stack. 678 void nlua_push_Float(lua_State *lstate, const Float f, int flags) 679 FUNC_ATTR_NONNULL_ALL 680 { 681 if (flags & kNluaPushSpecial) { 682 nlua_create_typed_table(lstate, 0, 1, kObjectTypeFloat); 683 nlua_push_val_idx(lstate); 684 lua_pushnumber(lstate, (lua_Number)f); 685 lua_rawset(lstate, -3); 686 } else { 687 lua_pushnumber(lstate, (lua_Number)f); 688 } 689 } 690 691 /// Convert given Float to Lua boolean 692 /// 693 /// Leaves converted value on top of the stack. 694 void nlua_push_Boolean(lua_State *lstate, const Boolean b, int flags) 695 FUNC_ATTR_NONNULL_ALL 696 { 697 lua_pushboolean(lstate, b); 698 } 699 700 /// Convert given Dict to Lua table 701 /// 702 /// Leaves converted table on top of the stack. 703 void nlua_push_Dict(lua_State *lstate, const Dict dict, int flags) 704 FUNC_ATTR_NONNULL_ALL 705 { 706 lua_createtable(lstate, 0, (int)dict.size); 707 if (dict.size == 0) { 708 nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); 709 lua_setmetatable(lstate, -2); 710 } 711 for (size_t i = 0; i < dict.size; i++) { 712 nlua_push_String(lstate, dict.items[i].key, flags); 713 nlua_push_Object(lstate, &dict.items[i].value, flags); 714 lua_rawset(lstate, -3); 715 } 716 } 717 718 /// Convert given Array to Lua table 719 /// 720 /// Leaves converted table on top of the stack. 721 void nlua_push_Array(lua_State *lstate, const Array array, int flags) 722 FUNC_ATTR_NONNULL_ALL 723 { 724 lua_createtable(lstate, (int)array.size, 0); 725 for (size_t i = 0; i < array.size; i++) { 726 nlua_push_Object(lstate, &array.items[i], flags); 727 lua_rawseti(lstate, -2, (int)i + 1); 728 } 729 } 730 731 void nlua_push_handle(lua_State *lstate, const handle_T item, int flags) 732 FUNC_ATTR_NONNULL_ALL 733 { 734 lua_pushnumber(lstate, (lua_Number)(item)); 735 } 736 737 /// Convert given Object to Lua value 738 /// 739 /// Leaves converted value on top of the stack. 740 void nlua_push_Object(lua_State *lstate, Object *obj, int flags) 741 FUNC_ATTR_NONNULL_ALL 742 { 743 switch (obj->type) { 744 case kObjectTypeNil: 745 if (flags & kNluaPushSpecial) { 746 lua_pushnil(lstate); 747 } else { 748 nlua_pushref(lstate, nlua_global_refs->nil_ref); 749 } 750 break; 751 case kObjectTypeLuaRef: { 752 nlua_pushref(lstate, obj->data.luaref); 753 if (flags & kNluaPushFreeRefs) { 754 api_free_luaref(obj->data.luaref); 755 obj->data.luaref = LUA_NOREF; 756 } 757 break; 758 } 759 #define ADD_TYPE(type, data_key) \ 760 case kObjectType##type: { \ 761 nlua_push_##type(lstate, obj->data.data_key, flags); \ 762 break; \ 763 } 764 ADD_TYPE(Boolean, boolean) 765 ADD_TYPE(Integer, integer) 766 ADD_TYPE(Float, floating) 767 ADD_TYPE(String, string) 768 ADD_TYPE(Array, array) 769 ADD_TYPE(Dict, dict) 770 #undef ADD_TYPE 771 #define ADD_REMOTE_TYPE(type) \ 772 case kObjectType##type: { \ 773 nlua_push_##type(lstate, (type)obj->data.integer, flags); \ 774 break; \ 775 } 776 ADD_REMOTE_TYPE(Buffer) 777 ADD_REMOTE_TYPE(Window) 778 ADD_REMOTE_TYPE(Tabpage) 779 #undef ADD_REMOTE_TYPE 780 } 781 } 782 783 /// Convert Lua value to string 784 /// 785 /// Always pops one value from the stack. 786 String nlua_pop_String(lua_State *lstate, Arena *arena, Error *err) 787 FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT 788 { 789 if (lua_type(lstate, -1) != LUA_TSTRING) { 790 lua_pop(lstate, 1); 791 api_set_error(err, kErrorTypeValidation, "Expected Lua string"); 792 return (String) { .size = 0, .data = NULL }; 793 } 794 String ret; 795 796 ret.data = (char *)lua_tolstring(lstate, -1, &(ret.size)); 797 assert(ret.data != NULL); 798 // TODO(bfredl): it would be "nice" to just use the memory of the Lua string 799 // directly, although ensuring the lifetime of such strings is a bit tricky 800 // (an API call could invoke nested Lua, which triggers GC, and kaboom?) 801 ret.data = arena_memdupz(arena, ret.data, ret.size); 802 lua_pop(lstate, 1); 803 804 return ret; 805 } 806 807 /// Convert Lua value to integer 808 /// 809 /// Always pops one value from the stack. 810 Integer nlua_pop_Integer(lua_State *lstate, Arena *arena, Error *err) 811 FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT 812 { 813 if (lua_type(lstate, -1) != LUA_TNUMBER) { 814 lua_pop(lstate, 1); 815 api_set_error(err, kErrorTypeValidation, "Expected Lua number"); 816 return 0; 817 } 818 const lua_Number n = lua_tonumber(lstate, -1); 819 lua_pop(lstate, 1); 820 if (n > (lua_Number)API_INTEGER_MAX || n < (lua_Number)API_INTEGER_MIN 821 || ((lua_Number)((Integer)n)) != n) { 822 api_set_error(err, kErrorTypeException, "Number is not integral"); 823 return 0; 824 } 825 return (Integer)n; 826 } 827 828 /// Convert Lua value to boolean 829 /// 830 /// Despite the name of the function, this uses Lua semantics for booleans. 831 /// thus `err` is never set as any Lua value can be co-erced into a Lua bool 832 /// 833 /// Always pops one value from the stack. 834 Boolean nlua_pop_Boolean(lua_State *lstate, Arena *arena, Error *err) 835 FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT 836 { 837 const Boolean ret = lua_toboolean(lstate, -1); 838 lua_pop(lstate, 1); 839 return ret; 840 } 841 842 /// Convert Lua value to boolean 843 /// 844 /// This follows API conventions for a Boolean value, compare api_object_to_bool 845 /// 846 /// Always pops one value from the stack. 847 Boolean nlua_pop_Boolean_strict(lua_State *lstate, Error *err) 848 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 849 { 850 Boolean ret = false; 851 switch (lua_type(lstate, -1)) { 852 case LUA_TBOOLEAN: 853 ret = lua_toboolean(lstate, -1); 854 break; 855 856 case LUA_TNUMBER: 857 ret = (lua_tonumber(lstate, -1) != 0); 858 break; 859 860 case LUA_TNIL: 861 ret = false; 862 break; 863 864 default: 865 api_set_error(err, kErrorTypeValidation, "not a boolean"); 866 } 867 868 lua_pop(lstate, 1); 869 return ret; 870 } 871 872 /// Check whether typed table on top of the stack has given type 873 /// 874 /// @param[in] lstate Lua state. 875 /// @param[out] err Location where error will be saved. May be NULL. 876 /// @param[in] type Type to check. 877 /// 878 /// @return @see nlua_traverse_table(). 879 static inline LuaTableProps nlua_check_type(lua_State *const lstate, Error *const err, 880 const ObjectType type) 881 FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT 882 { 883 if (lua_type(lstate, -1) != LUA_TTABLE) { 884 if (err) { 885 api_set_error(err, kErrorTypeValidation, "Expected Lua %s", 886 (type == kObjectTypeFloat) ? "number" : "table"); 887 } 888 return (LuaTableProps) { .type = kObjectTypeNil }; 889 } 890 LuaTableProps table_props = nlua_traverse_table(lstate); 891 892 if (type == kObjectTypeDict && table_props.type == kObjectTypeArray 893 && table_props.maxidx == 0 && !table_props.has_type_key) { 894 table_props.type = kObjectTypeDict; 895 } 896 897 if (table_props.type != type) { 898 if (err) { 899 api_set_error(err, kErrorTypeValidation, "Expected %s-like Lua table", api_typename(type)); 900 } 901 } 902 903 return table_props; 904 } 905 906 /// Convert Lua table to float 907 /// 908 /// Always pops one value from the stack. 909 Float nlua_pop_Float(lua_State *lstate, Arena *arena, Error *err) 910 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 911 { 912 if (lua_type(lstate, -1) == LUA_TNUMBER) { 913 const Float ret = (Float)lua_tonumber(lstate, -1); 914 lua_pop(lstate, 1); 915 return ret; 916 } 917 918 const LuaTableProps table_props = nlua_check_type(lstate, err, 919 kObjectTypeFloat); 920 lua_pop(lstate, 1); 921 if (table_props.type != kObjectTypeFloat) { 922 return 0; 923 } 924 return (Float)table_props.val; 925 } 926 927 /// Convert Lua table to array without determining whether it is array 928 /// 929 /// @param lstate Lua state. 930 /// @param[in] table_props nlua_traverse_table() output. 931 /// @param[out] err Location where error will be saved. 932 static Array nlua_pop_Array_unchecked(lua_State *const lstate, const LuaTableProps table_props, 933 Arena *arena, Error *const err) 934 { 935 Array ret = arena_array(arena, table_props.maxidx); 936 937 if (table_props.maxidx == 0) { 938 lua_pop(lstate, 1); 939 return ret; 940 } 941 942 for (size_t i = 1; i <= table_props.maxidx; i++) { 943 Object val; 944 945 lua_rawgeti(lstate, -1, (int)i); 946 947 val = nlua_pop_Object(lstate, false, arena, err); 948 if (ERROR_SET(err)) { 949 lua_pop(lstate, 1); 950 if (!arena) { 951 api_free_array(ret); 952 } 953 return (Array) { .size = 0, .items = NULL }; 954 } 955 ADD_C(ret, val); 956 } 957 lua_pop(lstate, 1); 958 959 return ret; 960 } 961 962 /// Convert Lua table to array 963 /// 964 /// Always pops one value from the stack. 965 Array nlua_pop_Array(lua_State *lstate, Arena *arena, Error *err) 966 FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT 967 { 968 const LuaTableProps table_props = nlua_check_type(lstate, err, kObjectTypeArray); 969 if (table_props.type != kObjectTypeArray) { 970 return (Array) { .size = 0, .items = NULL }; 971 } 972 return nlua_pop_Array_unchecked(lstate, table_props, arena, err); 973 } 974 975 /// Convert Lua table to dictionary 976 /// 977 /// Always pops one value from the stack. Does not check whether whether topmost 978 /// value on the stack is a table. 979 /// 980 /// @param lstate Lua interpreter state. 981 /// @param[in] table_props nlua_traverse_table() output. 982 /// @param[out] err Location where error will be saved. 983 static Dict nlua_pop_Dict_unchecked(lua_State *lstate, const LuaTableProps table_props, bool ref, 984 Arena *arena, Error *err) 985 FUNC_ATTR_NONNULL_ARG(1, 5) FUNC_ATTR_WARN_UNUSED_RESULT 986 { 987 Dict ret = arena_dict(arena, table_props.string_keys_num); 988 989 if (table_props.string_keys_num == 0) { 990 lua_pop(lstate, 1); 991 return ret; 992 } 993 994 lua_pushnil(lstate); 995 for (size_t i = 0; lua_next(lstate, -2) && i < table_props.string_keys_num;) { 996 // stack: dict, key, value 997 998 if (lua_type(lstate, -2) == LUA_TSTRING) { 999 lua_pushvalue(lstate, -2); 1000 // stack: dict, key, value, key 1001 1002 String key = nlua_pop_String(lstate, arena, err); 1003 // stack: dict, key, value 1004 1005 if (!ERROR_SET(err)) { 1006 Object value = nlua_pop_Object(lstate, ref, arena, err); 1007 kv_push_c(ret, ((KeyValuePair) { .key = key, .value = value })); 1008 // stack: dict, key 1009 } else { 1010 lua_pop(lstate, 1); 1011 // stack: dict, key 1012 } 1013 1014 if (ERROR_SET(err)) { 1015 if (!arena) { 1016 api_free_dict(ret); 1017 } 1018 lua_pop(lstate, 2); 1019 // stack: 1020 return (Dict) { .size = 0, .items = NULL }; 1021 } 1022 i++; 1023 } else { 1024 lua_pop(lstate, 1); 1025 // stack: dict, key 1026 } 1027 } 1028 lua_pop(lstate, 1); 1029 1030 return ret; 1031 } 1032 1033 /// Convert Lua table to dictionary 1034 /// 1035 /// Always pops one value from the stack. 1036 Dict nlua_pop_Dict(lua_State *lstate, bool ref, Arena *arena, Error *err) 1037 FUNC_ATTR_NONNULL_ARG(1, 4) FUNC_ATTR_WARN_UNUSED_RESULT 1038 { 1039 const LuaTableProps table_props = nlua_check_type(lstate, err, 1040 kObjectTypeDict); 1041 if (table_props.type != kObjectTypeDict) { 1042 lua_pop(lstate, 1); 1043 return (Dict) { .size = 0, .items = NULL }; 1044 } 1045 1046 return nlua_pop_Dict_unchecked(lstate, table_props, ref, arena, err); 1047 } 1048 1049 /// Helper structure for nlua_pop_Object 1050 typedef struct { 1051 Object *obj; ///< Location where conversion result is saved. 1052 bool container; ///< True if tv is a container. 1053 } ObjPopStackItem; 1054 1055 /// Convert Lua table to object 1056 /// 1057 /// Always pops one value from the stack. 1058 Object nlua_pop_Object(lua_State *const lstate, bool ref, Arena *arena, Error *const err) 1059 FUNC_ATTR_NONNULL_ARG(1, 4) FUNC_ATTR_WARN_UNUSED_RESULT 1060 { 1061 Object ret = NIL; 1062 const int initial_size = lua_gettop(lstate); 1063 kvec_withinit_t(ObjPopStackItem, 2) stack = KV_INITIAL_VALUE; 1064 kvi_init(stack); 1065 kvi_push(stack, ((ObjPopStackItem){ .obj = &ret })); 1066 while (!ERROR_SET(err) && kv_size(stack)) { 1067 ObjPopStackItem cur = kv_pop(stack); 1068 if (cur.container) { 1069 if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { 1070 api_set_error(err, kErrorTypeException, "Lua failed to grow stack"); 1071 break; 1072 } 1073 if (cur.obj->type == kObjectTypeDict) { 1074 // stack: …, dict, key 1075 if (cur.obj->data.dict.size == cur.obj->data.dict.capacity) { 1076 lua_pop(lstate, 2); 1077 continue; 1078 } 1079 bool next_key_found = false; 1080 while (lua_next(lstate, -2)) { 1081 // stack: …, dict, new key, val 1082 if (lua_type(lstate, -2) == LUA_TSTRING) { 1083 next_key_found = true; 1084 break; 1085 } 1086 lua_pop(lstate, 1); 1087 // stack: …, dict, new key 1088 } 1089 if (next_key_found) { 1090 // stack: …, dict, new key, val 1091 size_t len; 1092 const char *s = lua_tolstring(lstate, -2, &len); 1093 const size_t idx = cur.obj->data.dict.size++; 1094 cur.obj->data.dict.items[idx].key = CBUF_TO_ARENA_STR(arena, s, len); 1095 kvi_push(stack, cur); 1096 cur = (ObjPopStackItem){ .obj = &cur.obj->data.dict.items[idx].value }; 1097 } else { 1098 // stack: …, dict 1099 lua_pop(lstate, 1); 1100 // stack: … 1101 continue; 1102 } 1103 } else { 1104 if (cur.obj->data.array.size == cur.obj->data.array.capacity) { 1105 lua_pop(lstate, 1); 1106 continue; 1107 } 1108 const size_t idx = cur.obj->data.array.size++; 1109 lua_rawgeti(lstate, -1, (int)idx + 1); 1110 kvi_push(stack, cur); 1111 cur = (ObjPopStackItem){ .obj = &cur.obj->data.array.items[idx] }; 1112 } 1113 } 1114 assert(!cur.container); 1115 *cur.obj = NIL; 1116 switch (lua_type(lstate, -1)) { 1117 case LUA_TNIL: 1118 break; 1119 case LUA_TBOOLEAN: 1120 *cur.obj = BOOLEAN_OBJ(lua_toboolean(lstate, -1)); 1121 break; 1122 case LUA_TSTRING: { 1123 size_t len; 1124 const char *s = lua_tolstring(lstate, -1, &len); 1125 *cur.obj = STRING_OBJ(CBUF_TO_ARENA_STR(arena, s, len)); 1126 break; 1127 } 1128 case LUA_TNUMBER: { 1129 const lua_Number n = lua_tonumber(lstate, -1); 1130 if (n > (lua_Number)API_INTEGER_MAX || n < (lua_Number)API_INTEGER_MIN 1131 || ((lua_Number)((Integer)n)) != n) { 1132 *cur.obj = FLOAT_OBJ((Float)n); 1133 } else { 1134 *cur.obj = INTEGER_OBJ((Integer)n); 1135 } 1136 break; 1137 } 1138 case LUA_TTABLE: { 1139 const LuaTableProps table_props = nlua_traverse_table(lstate); 1140 1141 switch (table_props.type) { 1142 case kObjectTypeArray: 1143 *cur.obj = ARRAY_OBJ(((Array)ARRAY_DICT_INIT)); 1144 if (table_props.maxidx != 0) { 1145 cur.obj->data.array = arena_array(arena, table_props.maxidx); 1146 cur.container = true; 1147 assert(kv_size(stack) < SIZE_MAX); 1148 kvi_push(stack, cur); 1149 } 1150 break; 1151 case kObjectTypeDict: 1152 *cur.obj = DICT_OBJ(((Dict)ARRAY_DICT_INIT)); 1153 if (table_props.string_keys_num != 0) { 1154 cur.obj->data.dict = arena_dict(arena, table_props.string_keys_num); 1155 cur.container = true; 1156 assert(kv_size(stack) < SIZE_MAX); 1157 kvi_push(stack, cur); 1158 lua_pushnil(lstate); 1159 } 1160 break; 1161 case kObjectTypeFloat: 1162 *cur.obj = FLOAT_OBJ((Float)table_props.val); 1163 break; 1164 case kObjectTypeNil: 1165 api_set_error(err, kErrorTypeValidation, 1166 "Cannot convert given Lua table"); 1167 break; 1168 default: 1169 abort(); 1170 } 1171 break; 1172 } 1173 1174 case LUA_TFUNCTION: 1175 if (ref) { 1176 *cur.obj = LUAREF_OBJ(nlua_ref_global(lstate, -1)); 1177 } else { 1178 goto type_error; 1179 } 1180 break; 1181 1182 case LUA_TUSERDATA: { 1183 nlua_pushref(lstate, nlua_global_refs->nil_ref); 1184 bool is_nil = lua_rawequal(lstate, -2, -1); 1185 lua_pop(lstate, 1); 1186 if (is_nil) { 1187 *cur.obj = NIL; 1188 } else { 1189 api_set_error(err, kErrorTypeValidation, "Cannot convert userdata"); 1190 } 1191 break; 1192 } 1193 1194 default: 1195 type_error: 1196 api_set_error(err, kErrorTypeValidation, "Cannot convert given Lua type"); 1197 break; 1198 } 1199 if (!cur.container) { 1200 lua_pop(lstate, 1); 1201 } 1202 } 1203 kvi_destroy(stack); 1204 if (ERROR_SET(err)) { 1205 if (!arena) { 1206 api_free_object(ret); 1207 } 1208 ret = NIL; 1209 lua_pop(lstate, lua_gettop(lstate) - initial_size + 1); 1210 } 1211 assert(lua_gettop(lstate) == initial_size - 1); 1212 return ret; 1213 } 1214 1215 LuaRef nlua_pop_LuaRef(lua_State *const lstate, Arena *arena, Error *err) 1216 { 1217 LuaRef rv = nlua_ref_global(lstate, -1); 1218 lua_pop(lstate, 1); 1219 return rv; 1220 } 1221 1222 handle_T nlua_pop_handle(lua_State *lstate, Arena *arena, Error *err) 1223 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 1224 { 1225 handle_T ret; 1226 if (lua_type(lstate, -1) != LUA_TNUMBER) { 1227 api_set_error(err, kErrorTypeValidation, "Expected Lua number"); 1228 ret = (handle_T)(-1); 1229 } else { 1230 ret = (handle_T)lua_tonumber(lstate, -1); 1231 } 1232 lua_pop(lstate, 1); 1233 return ret; 1234 } 1235 1236 /// Record some auxiliary values in vim module 1237 /// 1238 /// Assumes that module table is on top of the stack. 1239 /// 1240 /// Recorded values: 1241 /// 1242 /// `vim.type_idx`: @see nlua_push_type_idx() 1243 /// `vim.val_idx`: @see nlua_push_val_idx() 1244 /// `vim.types`: table mapping possible values of `vim.type_idx` to string 1245 /// names (i.e. `array`, `float`, `dictionary`) and back. 1246 void nlua_init_types(lua_State *const lstate) 1247 { 1248 LUA_PUSH_STATIC_STRING(lstate, "type_idx"); 1249 nlua_push_type_idx(lstate); 1250 lua_rawset(lstate, -3); 1251 1252 LUA_PUSH_STATIC_STRING(lstate, "val_idx"); 1253 nlua_push_val_idx(lstate); 1254 lua_rawset(lstate, -3); 1255 1256 LUA_PUSH_STATIC_STRING(lstate, "types"); 1257 lua_createtable(lstate, 0, 3); 1258 1259 LUA_PUSH_STATIC_STRING(lstate, "float"); 1260 lua_pushnumber(lstate, (lua_Number)kObjectTypeFloat); 1261 lua_rawset(lstate, -3); 1262 lua_pushnumber(lstate, (lua_Number)kObjectTypeFloat); 1263 LUA_PUSH_STATIC_STRING(lstate, "float"); 1264 lua_rawset(lstate, -3); 1265 1266 LUA_PUSH_STATIC_STRING(lstate, "array"); 1267 lua_pushnumber(lstate, (lua_Number)kObjectTypeArray); 1268 lua_rawset(lstate, -3); 1269 lua_pushnumber(lstate, (lua_Number)kObjectTypeArray); 1270 LUA_PUSH_STATIC_STRING(lstate, "array"); 1271 lua_rawset(lstate, -3); 1272 1273 LUA_PUSH_STATIC_STRING(lstate, "dictionary"); 1274 lua_pushnumber(lstate, (lua_Number)kObjectTypeDict); 1275 lua_rawset(lstate, -3); 1276 lua_pushnumber(lstate, (lua_Number)kObjectTypeDict); 1277 LUA_PUSH_STATIC_STRING(lstate, "dictionary"); 1278 lua_rawset(lstate, -3); 1279 1280 lua_rawset(lstate, -3); 1281 } 1282 1283 // Lua specific variant of api_dict_to_keydict 1284 void nlua_pop_keydict(lua_State *L, void *retval, FieldHashfn hashy, char **err_opt, Arena *arena, 1285 Error *err) 1286 { 1287 if (!lua_istable(L, -1)) { 1288 api_set_error(err, kErrorTypeValidation, "Expected Lua table"); 1289 lua_pop(L, -1); 1290 return; 1291 } 1292 1293 lua_pushnil(L); // [dict, nil] 1294 while (lua_next(L, -2)) { 1295 // [dict, key, value] 1296 size_t len; 1297 const char *s = lua_tolstring(L, -2, &len); 1298 KeySetLink *field = hashy(s, len); 1299 if (!field) { 1300 api_set_error(err, kErrorTypeValidation, "invalid key: %.*s", (int)len, s); 1301 lua_pop(L, 3); // [] 1302 return; 1303 } 1304 1305 if (field->opt_index >= 0) { 1306 OptKeySet *ks = (OptKeySet *)retval; 1307 ks->is_set_ |= (1ULL << field->opt_index); 1308 } 1309 char *mem = ((char *)retval + field->ptr_off); 1310 1311 if (field->type == kObjectTypeNil) { 1312 *(Object *)mem = nlua_pop_Object(L, true, arena, err); 1313 } else if (field->type == kObjectTypeInteger) { 1314 if (field->is_hlgroup && lua_type(L, -1) == LUA_TSTRING) { 1315 size_t name_len; 1316 const char *name = lua_tolstring(L, -1, &name_len); 1317 lua_pop(L, 1); 1318 *(Integer *)mem = name_len > 0 ? syn_check_group(name, name_len) : 0; 1319 } else { 1320 *(Integer *)mem = nlua_pop_Integer(L, arena, err); 1321 } 1322 } else if (field->type == kObjectTypeBoolean) { 1323 *(Boolean *)mem = nlua_pop_Boolean_strict(L, err); 1324 } else if (field->type == kObjectTypeString) { 1325 *(String *)mem = nlua_pop_String(L, arena, err); 1326 } else if (field->type == kObjectTypeFloat) { 1327 *(Float *)mem = nlua_pop_Float(L, arena, err); 1328 } else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow 1329 || field->type == kObjectTypeTabpage) { 1330 *(handle_T *)mem = nlua_pop_handle(L, arena, err); 1331 } else if (field->type == kObjectTypeArray) { 1332 *(Array *)mem = nlua_pop_Array(L, arena, err); 1333 } else if (field->type == kObjectTypeDict) { 1334 *(Dict *)mem = nlua_pop_Dict(L, false, arena, err); 1335 } else if (field->type == kObjectTypeLuaRef) { 1336 *(LuaRef *)mem = nlua_pop_LuaRef(L, arena, err); 1337 } else { 1338 abort(); 1339 } 1340 if (ERROR_SET(err)) { 1341 *err_opt = field->str; 1342 break; 1343 } 1344 } 1345 // [dict] 1346 lua_pop(L, 1); 1347 // [] 1348 } 1349 1350 void nlua_push_keydict(lua_State *L, void *value, KeySetLink *table) 1351 { 1352 lua_createtable(L, 0, 0); 1353 for (size_t i = 0; table[i].str; i++) { 1354 KeySetLink *field = &table[i]; 1355 bool is_set = true; 1356 if (field->opt_index >= 0) { 1357 OptKeySet *ks = (OptKeySet *)value; 1358 is_set = ks->is_set_ & (1ULL << field->opt_index); 1359 } 1360 1361 if (!is_set) { 1362 continue; 1363 } 1364 1365 char *mem = ((char *)value + field->ptr_off); 1366 1367 lua_pushstring(L, field->str); 1368 if (field->type == kObjectTypeNil) { 1369 nlua_push_Object(L, (Object *)mem, 0); 1370 } else if (field->type == kObjectTypeInteger) { 1371 lua_pushinteger(L, *(Integer *)mem); 1372 } else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow 1373 || field->type == kObjectTypeTabpage) { 1374 lua_pushinteger(L, *(handle_T *)mem); 1375 } else if (field->type == kObjectTypeFloat) { 1376 lua_pushnumber(L, *(Float *)mem); 1377 } else if (field->type == kObjectTypeBoolean) { 1378 lua_pushboolean(L, *(Boolean *)mem); 1379 } else if (field->type == kObjectTypeString) { 1380 nlua_push_String(L, *(String *)mem, 0); 1381 } else if (field->type == kObjectTypeArray) { 1382 nlua_push_Array(L, *(Array *)mem, 0); 1383 } else if (field->type == kObjectTypeDict) { 1384 nlua_push_Dict(L, *(Dict *)mem, 0); 1385 } else if (field->type == kObjectTypeLuaRef) { 1386 nlua_pushref(L, *(LuaRef *)mem); 1387 } else { 1388 abort(); 1389 } 1390 1391 lua_rawset(L, -3); 1392 } 1393 }