mirror of
https://github.com/neovim/neovim.git
synced 2025-09-14 15:28:17 +00:00
eval: Also make clear_tv non-recursive
This commit is contained in:
177
src/nvim/eval.c
177
src/nvim/eval.c
@@ -91,6 +91,7 @@
|
|||||||
#include "nvim/os/input.h"
|
#include "nvim/os/input.h"
|
||||||
#include "nvim/event/loop.h"
|
#include "nvim/event/loop.h"
|
||||||
#include "nvim/lib/queue.h"
|
#include "nvim/lib/queue.h"
|
||||||
|
#include "nvim/eval/typval_encode.h"
|
||||||
|
|
||||||
#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */
|
#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */
|
||||||
|
|
||||||
@@ -18148,45 +18149,147 @@ void free_tv(typval_T *varp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
#define TYPVAL_ENCODE_ALLOW_SPECIALS false
|
||||||
* Free the memory for a variable value and set the value to NULL or 0.
|
|
||||||
*/
|
#define TYPVAL_ENCODE_CONV_NIL() \
|
||||||
|
do { \
|
||||||
|
tv->vval.v_special = kSpecialVarFalse; \
|
||||||
|
tv->v_lock = VAR_UNLOCKED; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_BOOL(ignored) \
|
||||||
|
TYPVAL_ENCODE_CONV_NIL()
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_NUMBER(ignored) \
|
||||||
|
do { \
|
||||||
|
(void) ignored; \
|
||||||
|
tv->vval.v_number = 0; \
|
||||||
|
tv->v_lock = VAR_UNLOCKED; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(ignored) \
|
||||||
|
assert(false)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_FLOAT(ignored) \
|
||||||
|
do { \
|
||||||
|
tv->vval.v_float = 0; \
|
||||||
|
tv->v_lock = VAR_UNLOCKED; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_STRING(str, ignored) \
|
||||||
|
do { \
|
||||||
|
xfree(str); \
|
||||||
|
tv->vval.v_string = NULL; \
|
||||||
|
tv->v_lock = VAR_UNLOCKED; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_STR_STRING(ignored1, ignored2)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_EXT_STRING(ignored1, ignored2, ignored3)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_FUNC(fun) \
|
||||||
|
do { \
|
||||||
|
func_unref(fun); \
|
||||||
|
if (fun != empty_string) { \
|
||||||
|
xfree(fun); \
|
||||||
|
} \
|
||||||
|
tv->vval.v_string = NULL; \
|
||||||
|
tv->v_lock = VAR_UNLOCKED; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
||||||
|
do { \
|
||||||
|
list_unref(tv->vval.v_list); \
|
||||||
|
tv->vval.v_list = NULL; \
|
||||||
|
tv->v_lock = VAR_UNLOCKED; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_EMPTY_DICT() \
|
||||||
|
do { \
|
||||||
|
dict_unref(tv->vval.v_dict); \
|
||||||
|
tv->vval.v_dict = NULL; \
|
||||||
|
tv->v_lock = VAR_UNLOCKED; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_LIST_START(ignored) \
|
||||||
|
do { \
|
||||||
|
if (tv->vval.v_list->lv_refcount > 1) { \
|
||||||
|
tv->vval.v_list->lv_refcount--; \
|
||||||
|
tv->vval.v_list = NULL; \
|
||||||
|
tv->v_lock = VAR_UNLOCKED; \
|
||||||
|
return OK; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS()
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_LIST_END() \
|
||||||
|
do { \
|
||||||
|
typval_T *const cur_tv = cur_mpsv->tv; \
|
||||||
|
assert(cur_tv->v_type == VAR_LIST); \
|
||||||
|
list_unref(cur_tv->vval.v_list); \
|
||||||
|
cur_tv->vval.v_list = NULL; \
|
||||||
|
cur_tv->v_lock = VAR_UNLOCKED; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_DICT_START(ignored) \
|
||||||
|
do { \
|
||||||
|
if (tv->vval.v_dict->dv_refcount > 1) { \
|
||||||
|
tv->vval.v_dict->dv_refcount--; \
|
||||||
|
tv->vval.v_dict = NULL; \
|
||||||
|
tv->v_lock = VAR_UNLOCKED; \
|
||||||
|
return OK; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(ignored1, ignored2)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY()
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS()
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_DICT_END() \
|
||||||
|
do { \
|
||||||
|
typval_T *const cur_tv = cur_mpsv->tv; \
|
||||||
|
assert(cur_tv->v_type == VAR_DICT); \
|
||||||
|
dict_unref(cur_tv->vval.v_dict); \
|
||||||
|
cur_tv->vval.v_dict = NULL; \
|
||||||
|
cur_tv->v_lock = VAR_UNLOCKED; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_RECURSE(ignored1, ignored2)
|
||||||
|
|
||||||
|
TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, nothing, void *, ignored)
|
||||||
|
|
||||||
|
#undef TYPVAL_ENCODE_ALLOW_SPECIALS
|
||||||
|
#undef TYPVAL_ENCODE_CONV_NIL
|
||||||
|
#undef TYPVAL_ENCODE_CONV_BOOL
|
||||||
|
#undef TYPVAL_ENCODE_CONV_NUMBER
|
||||||
|
#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER
|
||||||
|
#undef TYPVAL_ENCODE_CONV_FLOAT
|
||||||
|
#undef TYPVAL_ENCODE_CONV_STRING
|
||||||
|
#undef TYPVAL_ENCODE_CONV_STR_STRING
|
||||||
|
#undef TYPVAL_ENCODE_CONV_EXT_STRING
|
||||||
|
#undef TYPVAL_ENCODE_CONV_FUNC
|
||||||
|
#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
|
||||||
|
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
||||||
|
#undef TYPVAL_ENCODE_CONV_LIST_START
|
||||||
|
#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS
|
||||||
|
#undef TYPVAL_ENCODE_CONV_LIST_END
|
||||||
|
#undef TYPVAL_ENCODE_CONV_DICT_START
|
||||||
|
#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK
|
||||||
|
#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY
|
||||||
|
#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS
|
||||||
|
#undef TYPVAL_ENCODE_CONV_DICT_END
|
||||||
|
#undef TYPVAL_ENCODE_CONV_RECURSE
|
||||||
|
|
||||||
|
/// Free memory for a variable value and set the value to NULL or 0
|
||||||
|
///
|
||||||
|
/// @param[in,out] varp Value to free.
|
||||||
void clear_tv(typval_T *varp)
|
void clear_tv(typval_T *varp)
|
||||||
{
|
{
|
||||||
if (varp != NULL) {
|
if (varp != NULL && varp->v_type != VAR_UNKNOWN) {
|
||||||
switch (varp->v_type) {
|
encode_vim_to_nothing(varp, varp, "clear_tv argument");
|
||||||
case VAR_FUNC:
|
|
||||||
func_unref(varp->vval.v_string);
|
|
||||||
if (varp->vval.v_string != empty_string) {
|
|
||||||
xfree(varp->vval.v_string);
|
|
||||||
}
|
|
||||||
varp->vval.v_string = NULL;
|
|
||||||
break;
|
|
||||||
case VAR_STRING:
|
|
||||||
xfree(varp->vval.v_string);
|
|
||||||
varp->vval.v_string = NULL;
|
|
||||||
break;
|
|
||||||
case VAR_LIST:
|
|
||||||
list_unref(varp->vval.v_list);
|
|
||||||
varp->vval.v_list = NULL;
|
|
||||||
break;
|
|
||||||
case VAR_DICT:
|
|
||||||
dict_unref(varp->vval.v_dict);
|
|
||||||
varp->vval.v_dict = NULL;
|
|
||||||
break;
|
|
||||||
case VAR_NUMBER:
|
|
||||||
varp->vval.v_number = 0;
|
|
||||||
break;
|
|
||||||
case VAR_FLOAT:
|
|
||||||
varp->vval.v_float = 0.0;
|
|
||||||
break;
|
|
||||||
case VAR_SPECIAL:
|
|
||||||
varp->vval.v_special = kSpecialVarFalse;
|
|
||||||
break;
|
|
||||||
case VAR_UNKNOWN:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
varp->v_lock = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -344,7 +344,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf,
|
|||||||
#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS() \
|
#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS() \
|
||||||
ga_concat(gap, ", ")
|
ga_concat(gap, ", ")
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, kv_pair)
|
#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, key)
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_LIST_END() \
|
#define TYPVAL_ENCODE_CONV_LIST_END() \
|
||||||
ga_append(gap, ']')
|
ga_append(gap, ']')
|
||||||
@@ -696,9 +696,9 @@ bool encode_check_json_key(const typval_T *const tv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK
|
#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK
|
||||||
#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, kv_pair) \
|
#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, key) \
|
||||||
do { \
|
do { \
|
||||||
if (!encode_check_json_key(&kv_pair->lv_first->li_tv)) { \
|
if (!encode_check_json_key(&key)) { \
|
||||||
EMSG(_("E474: Invalid key in special dictionary")); \
|
EMSG(_("E474: Invalid key in special dictionary")); \
|
||||||
goto label; \
|
goto label; \
|
||||||
} \
|
} \
|
||||||
@@ -873,7 +873,7 @@ char *encode_tv2json(typval_T *tv, size_t *len)
|
|||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS()
|
#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS()
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, kv_pair)
|
#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, key)
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_LIST_END()
|
#define TYPVAL_ENCODE_CONV_LIST_END()
|
||||||
|
|
||||||
|
@@ -104,7 +104,7 @@
|
|||||||
/// @brief Macros used to check special dictionary key
|
/// @brief Macros used to check special dictionary key
|
||||||
///
|
///
|
||||||
/// @param label Label for goto in case check was not successfull.
|
/// @param label Label for goto in case check was not successfull.
|
||||||
/// @param kv_pair List with two elements: key and value.
|
/// @param key typval_T key to check.
|
||||||
|
|
||||||
/// @def TYPVAL_ENCODE_CONV_DICT_AFTER_KEY
|
/// @def TYPVAL_ENCODE_CONV_DICT_AFTER_KEY
|
||||||
/// @brief Macros used after finishing converting dictionary key
|
/// @brief Macros used after finishing converting dictionary key
|
||||||
@@ -154,6 +154,7 @@ typedef enum {
|
|||||||
/// Structure representing current VimL to messagepack conversion state
|
/// Structure representing current VimL to messagepack conversion state
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MPConvStackValType type; ///< Type of the stack entry.
|
MPConvStackValType type; ///< Type of the stack entry.
|
||||||
|
typval_T *tv; ///< Currently converted typval_T.
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
dict_T *dict; ///< Currently converted dictionary.
|
dict_T *dict; ///< Currently converted dictionary.
|
||||||
@@ -217,10 +218,10 @@ static inline size_t tv_strlen(const typval_T *const tv)
|
|||||||
/// tv)` which returns OK or FAIL and helper functions.
|
/// tv)` which returns OK or FAIL and helper functions.
|
||||||
///
|
///
|
||||||
/// @param scope Scope of the main function: either nothing or `static`.
|
/// @param scope Scope of the main function: either nothing or `static`.
|
||||||
|
/// @param name Name of the target converter.
|
||||||
/// @param firstargtype Type of the first argument. It will be used to return
|
/// @param firstargtype Type of the first argument. It will be used to return
|
||||||
/// the results.
|
/// the results.
|
||||||
/// @param firstargname Name of the first argument.
|
/// @param firstargname Name of the first argument.
|
||||||
/// @param name Name of the target converter.
|
|
||||||
#define TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(scope, name, firstargtype, \
|
#define TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(scope, name, firstargtype, \
|
||||||
firstargname) \
|
firstargname) \
|
||||||
static int name##_convert_one_value(firstargtype firstargname, \
|
static int name##_convert_one_value(firstargtype firstargname, \
|
||||||
@@ -257,6 +258,7 @@ static int name##_convert_one_value(firstargtype firstargname, \
|
|||||||
TYPVAL_ENCODE_CONV_LIST_START(tv->vval.v_list->lv_len); \
|
TYPVAL_ENCODE_CONV_LIST_START(tv->vval.v_list->lv_len); \
|
||||||
_mp_push(*mpstack, ((MPConvStackVal) { \
|
_mp_push(*mpstack, ((MPConvStackVal) { \
|
||||||
.type = kMPConvList, \
|
.type = kMPConvList, \
|
||||||
|
.tv = tv, \
|
||||||
.data = { \
|
.data = { \
|
||||||
.l = { \
|
.l = { \
|
||||||
.list = tv->vval.v_list, \
|
.list = tv->vval.v_list, \
|
||||||
@@ -387,6 +389,7 @@ static int name##_convert_one_value(firstargtype firstargname, \
|
|||||||
lv_copyID, kMPConvList); \
|
lv_copyID, kMPConvList); \
|
||||||
TYPVAL_ENCODE_CONV_LIST_START(val_di->di_tv.vval.v_list->lv_len); \
|
TYPVAL_ENCODE_CONV_LIST_START(val_di->di_tv.vval.v_list->lv_len); \
|
||||||
_mp_push(*mpstack, ((MPConvStackVal) { \
|
_mp_push(*mpstack, ((MPConvStackVal) { \
|
||||||
|
.tv = tv, \
|
||||||
.type = kMPConvList, \
|
.type = kMPConvList, \
|
||||||
.data = { \
|
.data = { \
|
||||||
.l = { \
|
.l = { \
|
||||||
@@ -417,6 +420,7 @@ static int name##_convert_one_value(firstargtype firstargname, \
|
|||||||
kMPConvPairs); \
|
kMPConvPairs); \
|
||||||
TYPVAL_ENCODE_CONV_DICT_START(val_list->lv_len); \
|
TYPVAL_ENCODE_CONV_DICT_START(val_list->lv_len); \
|
||||||
_mp_push(*mpstack, ((MPConvStackVal) { \
|
_mp_push(*mpstack, ((MPConvStackVal) { \
|
||||||
|
.tv = tv, \
|
||||||
.type = kMPConvPairs, \
|
.type = kMPConvPairs, \
|
||||||
.data = { \
|
.data = { \
|
||||||
.l = { \
|
.l = { \
|
||||||
@@ -457,6 +461,7 @@ name##_convert_one_value_regular_dict: \
|
|||||||
kMPConvDict); \
|
kMPConvDict); \
|
||||||
TYPVAL_ENCODE_CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); \
|
TYPVAL_ENCODE_CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); \
|
||||||
_mp_push(*mpstack, ((MPConvStackVal) { \
|
_mp_push(*mpstack, ((MPConvStackVal) { \
|
||||||
|
.tv = tv, \
|
||||||
.type = kMPConvDict, \
|
.type = kMPConvDict, \
|
||||||
.data = { \
|
.data = { \
|
||||||
.d = { \
|
.d = { \
|
||||||
@@ -537,7 +542,7 @@ scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \
|
|||||||
} \
|
} \
|
||||||
const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list; \
|
const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list; \
|
||||||
TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK( \
|
TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK( \
|
||||||
encode_vim_to_##name##_error_ret, kv_pair); \
|
encode_vim_to_##name##_error_ret, kv_pair->lv_first->li_tv); \
|
||||||
if (name##_convert_one_value(firstargname, &mpstack, \
|
if (name##_convert_one_value(firstargname, &mpstack, \
|
||||||
&kv_pair->lv_first->li_tv, copyID, \
|
&kv_pair->lv_first->li_tv, copyID, \
|
||||||
objname) == FAIL) { \
|
objname) == FAIL) { \
|
||||||
|
@@ -155,6 +155,10 @@ typedef struct list_stack_S {
|
|||||||
/// Convert a hashitem key pointer to a dictitem pointer
|
/// Convert a hashitem key pointer to a dictitem pointer
|
||||||
#define HIKEY2DI(p) ((dictitem_T *)(p - offsetof(dictitem_T, di_key)))
|
#define HIKEY2DI(p) ((dictitem_T *)(p - offsetof(dictitem_T, di_key)))
|
||||||
|
|
||||||
|
/// Convert a hashitem value pointer to a dictitem pointer
|
||||||
|
#define HIVAL2DI(p) \
|
||||||
|
((dictitem_T *)(((char *) p) - offsetof(dictitem_T, di_tv)))
|
||||||
|
|
||||||
/// Convert a hashitem pointer to a dictitem pointer
|
/// Convert a hashitem pointer to a dictitem pointer
|
||||||
#define HI2DI(hi) HIKEY2DI((hi)->hi_key)
|
#define HI2DI(hi) HIKEY2DI((hi)->hi_key)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user