aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/typval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval/typval.c')
-rw-r--r--src/nvim/eval/typval.c189
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;