diff options
Diffstat (limited to 'src/nvim/eval/typval.c')
-rw-r--r-- | src/nvim/eval/typval.c | 189 |
1 files changed, 163 insertions, 26 deletions
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 106b8f6eed..8dde78de3d 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -15,6 +15,8 @@ #include "nvim/eval/encode.h" #include "nvim/eval/typval_encode.h" #include "nvim/eval.h" +#include "nvim/eval/userfunc.h" +#include "nvim/lua/executor.h" #include "nvim/types.h" #include "nvim/assert.h" #include "nvim/memory.h" @@ -300,6 +302,7 @@ void tv_list_free_list(list_T *const l) } list_log(l, NULL, NULL, "freelist"); + nlua_free_typval_list(l); xfree(l); } @@ -637,6 +640,57 @@ tv_list_copy_error: return NULL; } +/// Flatten "list" in place to depth "maxdepth". +/// Does nothing if "maxdepth" is 0. +/// +/// @param[in,out] list List to flatten +/// @param[in] maxdepth Maximum depth that will be flattened +/// +/// @return OK or FAIL +int tv_list_flatten(list_T *list, long maxdepth) + FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT +{ + listitem_T *item; + listitem_T *to_free; + int n; + if (maxdepth == 0) { + return OK; + } + + n = 0; + item = list->lv_first; + while (item != NULL) { + fast_breakcheck(); + if (got_int) { + return FAIL; + } + if (item->li_tv.v_type == VAR_LIST) { + listitem_T *next = item->li_next; + + tv_list_drop_items(list, item, item); + tv_list_extend(list, item->li_tv.vval.v_list, next); + tv_clear(&item->li_tv); + to_free = item; + + if (item->li_prev == NULL) { + item = list->lv_first; + } else { + item = item->li_prev->li_next; + } + xfree(to_free); + + if (++n >= maxdepth) { + n = 0; + item = next; + } + } else { + n = 0; + item = item->li_next; + } + } + return OK; +} + /// Extend first list with the second /// /// @param[out] l1 List to extend. @@ -796,10 +850,14 @@ bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic, if (l1 == l2) { return true; } - if (l1 == NULL || l2 == NULL) { + if (tv_list_len(l1) != tv_list_len(l2)) { return false; } - if (tv_list_len(l1) != tv_list_len(l2)) { + if (tv_list_len(l1) == 0) { + // empty and NULL list are considered equal + return true; + } + if (l1 == NULL || l2 == NULL) { return false; } @@ -1200,6 +1258,7 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key, typval_T rettv; + dict->dv_refcount++; QUEUE *w; QUEUE_FOREACH(w, &dict->watchers) { DictWatcher *watcher = tv_dict_watcher_node_data(w); @@ -1211,6 +1270,7 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key, tv_clear(&rettv); } } + tv_dict_unref(dict); for (size_t i = 1; i < ARRAY_SIZE(argv); i++) { tv_clear(argv + i); @@ -1304,7 +1364,7 @@ void tv_dict_item_remove(dict_T *const dict, dictitem_T *const item) dict_T *tv_dict_alloc(void) FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT { - dict_T *const d = xmalloc(sizeof(dict_T)); + dict_T *const d = xcalloc(1, sizeof(dict_T)); // Add the dict to the list of dicts for garbage collection. if (gc_first_dict != NULL) { @@ -1371,6 +1431,7 @@ void tv_dict_free_dict(dict_T *const d) d->dv_used_next->dv_used_prev = d->dv_used_prev; } + nlua_free_typval_dict(d); xfree(d); } @@ -1426,6 +1487,23 @@ dictitem_T *tv_dict_find(const dict_T *const d, const char *const key, return TV_DICT_HI2DI(hi); } +/// Get a typval item from a dictionary and copy it into "rettv". +/// +/// @param[in] d Dictionary to check. +/// @param[in] key Dictionary key. +/// @param[in] rettv Return value. +/// @return OK in case of success or FAIL if nothing was found. +int tv_dict_get_tv(dict_T *d, const char *const key, typval_T *rettv) +{ + dictitem_T *const di = tv_dict_find(d, key, -1); + if (di == NULL) { + return FAIL; + } + + tv_copy(&di->di_tv, rettv); + return OK; +} + /// Get a number item from a dictionary /// /// Returns 0 if the entry does not exist. @@ -1585,6 +1663,26 @@ int tv_dict_add_list(dict_T *const d, const char *const key, return OK; } +/// Add a typval entry to dictionary. +/// +/// @param[out] d Dictionary to add entry to. +/// @param[in] key Key to add. +/// @param[in] key_len Key length. +/// +/// @return FAIL if out of memory or key already exists. +int tv_dict_add_tv(dict_T *d, const char *key, const size_t key_len, + typval_T *tv) +{ + dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); + + tv_copy(tv, &item->di_tv); + if (tv_dict_add(d, item) == FAIL) { + tv_dict_item_free(item); + return FAIL; + } + return OK; +} + /// Add a dictionary entry to dictionary /// /// @param[out] d Dictionary to add entry to. @@ -1631,21 +1729,43 @@ int tv_dict_add_nr(dict_T *const d, const char *const key, return OK; } -/// Add a special entry to dictionary +/// Add a floating point number entry to dictionary +/// +/// @param[out] d Dictionary to add entry to. +/// @param[in] key Key to add. +/// @param[in] key_len Key length. +/// @param[in] nr Floating point number to add. +/// +/// @return OK in case of success, FAIL when key already exists. +int tv_dict_add_float(dict_T *const d, const char *const key, + const size_t key_len, const float_T nr) +{ + dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); + + item->di_tv.v_type = VAR_FLOAT; + item->di_tv.vval.v_float = nr; + if (tv_dict_add(d, item) == FAIL) { + tv_dict_item_free(item); + return FAIL; + } + return OK; +} + +/// Add a boolean entry to dictionary /// /// @param[out] d Dictionary to add entry to. /// @param[in] key Key to add. /// @param[in] key_len Key length. -/// @param[in] val SpecialVarValue to add. +/// @param[in] val BoolVarValue to add. /// /// @return OK in case of success, FAIL when key already exists. -int tv_dict_add_special(dict_T *const d, const char *const key, - const size_t key_len, SpecialVarValue val) +int tv_dict_add_bool(dict_T *const d, const char *const key, + const size_t key_len, BoolVarValue val) { dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); - item->di_tv.v_type = VAR_SPECIAL; - item->di_tv.vval.v_special = val; + item->di_tv.v_type = VAR_BOOL; + item->di_tv.vval.v_bool = val; if (tv_dict_add(d, item) == FAIL) { tv_dict_item_free(item); return FAIL; @@ -1659,9 +1779,9 @@ int tv_dict_add_special(dict_T *const d, const char *const key, int tv_dict_add_str(dict_T *const d, const char *const key, const size_t key_len, const char *const val) - FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_NONNULL_ARG(1, 2) { - return tv_dict_add_allocated_str(d, key, key_len, xstrdup(val)); + return tv_dict_add_str_len(d, key, key_len, val, -1); } /// Add a string entry to dictionary @@ -1675,10 +1795,10 @@ int tv_dict_add_str(dict_T *const d, /// @return OK in case of success, FAIL when key already exists. int tv_dict_add_str_len(dict_T *const d, const char *const key, const size_t key_len, - char *const val, int len) + const char *const val, int len) FUNC_ATTR_NONNULL_ARG(1, 2) { - char *s = val ? val : ""; + char *s = NULL; if (val != NULL) { s = (len < 0) ? xstrdup(val) : xstrndup(val, (size_t)len); } @@ -1701,7 +1821,7 @@ int tv_dict_add_str_len(dict_T *const d, int tv_dict_add_allocated_str(dict_T *const d, const char *const key, const size_t key_len, char *const val) - FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_NONNULL_ARG(1, 2) { dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); @@ -1951,12 +2071,15 @@ void tv_dict_alloc_ret(typval_T *const ret_tv) #define TYPVAL_ENCODE_CONV_NIL(tv) \ do { \ - tv->vval.v_special = kSpecialVarFalse; \ + tv->vval.v_special = kSpecialVarNull; \ tv->v_lock = VAR_UNLOCKED; \ } while (0) #define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ - TYPVAL_ENCODE_CONV_NIL(tv) + do { \ + tv->vval.v_bool = kBoolVarFalse; \ + tv->v_lock = VAR_UNLOCKED; \ + } while (0) #define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ do { \ @@ -2231,6 +2354,7 @@ void tv_free(typval_T *tv) tv_dict_unref(tv->vval.v_dict); break; } + case VAR_BOOL: case VAR_SPECIAL: case VAR_NUMBER: case VAR_FLOAT: @@ -2262,6 +2386,7 @@ void tv_copy(const typval_T *const from, typval_T *const to) switch (from->v_type) { case VAR_NUMBER: case VAR_FLOAT: + case VAR_BOOL: case VAR_SPECIAL: { break; } @@ -2363,6 +2488,7 @@ void tv_item_lock(typval_T *const tv, const int deep, const bool lock) case VAR_STRING: case VAR_FUNC: case VAR_PARTIAL: + case VAR_BOOL: case VAR_SPECIAL: { break; } @@ -2526,6 +2652,9 @@ bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic, const char *s2 = tv_get_string_buf(tv2, buf2); return mb_strcmp_ic((bool)ic, s1, s2) == 0; } + case VAR_BOOL: { + return tv1->vval.v_bool == tv2->vval.v_bool; + } case VAR_SPECIAL: { return tv1->vval.v_special == tv2->vval.v_special; } @@ -2576,6 +2705,10 @@ bool tv_check_str_or_nr(const typval_T *const tv) EMSG(_("E728: Expected a Number or a String, Dictionary found")); return false; } + case VAR_BOOL: { + EMSG(_("E5299: Expected a Number or a String, Boolean found")); + return false; + } case VAR_SPECIAL: { EMSG(_("E5300: Expected a Number or a String")); return false; @@ -2615,6 +2748,7 @@ bool tv_check_num(const typval_T *const tv) { switch (tv->v_type) { case VAR_NUMBER: + case VAR_BOOL: case VAR_SPECIAL: case VAR_STRING: { return true; @@ -2659,6 +2793,7 @@ bool tv_check_str(const typval_T *const tv) { switch (tv->v_type) { case VAR_NUMBER: + case VAR_BOOL: case VAR_SPECIAL: case VAR_STRING: { return true; @@ -2729,17 +2864,11 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error) } return n; } + case VAR_BOOL: { + return tv->vval.v_bool == kBoolVarTrue ? 1 : 0; + } case VAR_SPECIAL: { - switch (tv->vval.v_special) { - case kSpecialVarTrue: { - return 1; - } - case kSpecialVarFalse: - case kSpecialVarNull: { - return 0; - } - } - break; + return 0; } case VAR_UNKNOWN: { emsgf(_(e_intern2), "tv_get_number(UNKNOWN)"); @@ -2807,6 +2936,10 @@ float_T tv_get_float(const typval_T *const tv) EMSG(_("E894: Using a Dictionary as a Float")); break; } + case VAR_BOOL: { + EMSG(_("E362: Using a boolean value as a Float")); + break; + } case VAR_SPECIAL: { EMSG(_("E907: Using a special value as a Float")); break; @@ -2844,6 +2977,10 @@ const char *tv_get_string_buf_chk(const typval_T *const tv, char *const buf) } return ""; } + case VAR_BOOL: { + STRCPY(buf, encode_bool_var_names[tv->vval.v_bool]); + return buf; + } case VAR_SPECIAL: { STRCPY(buf, encode_special_var_names[tv->vval.v_special]); return buf; |