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