diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.c | 177 | ||||
-rw-r--r-- | src/nvim/eval/encode.c | 8 | ||||
-rw-r--r-- | src/nvim/eval/typval_encode.h | 11 | ||||
-rw-r--r-- | src/nvim/eval_defs.h | 4 |
4 files changed, 156 insertions, 44 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index aa5cd676af..2a4d06b1e7 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -91,6 +91,7 @@ #include "nvim/os/input.h" #include "nvim/event/loop.h" #include "nvim/lib/queue.h" +#include "nvim/eval/typval_encode.h" #define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ @@ -18148,45 +18149,147 @@ void free_tv(typval_T *varp) } } -/* - * Free the memory for a variable value and set the value to NULL or 0. - */ +#define TYPVAL_ENCODE_ALLOW_SPECIALS false + +#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) { - if (varp != NULL) { - switch (varp->v_type) { - 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; + if (varp != NULL && varp->v_type != VAR_UNKNOWN) { + encode_vim_to_nothing(varp, varp, "clear_tv argument"); } } diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index 771655fee5..670437ceda 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -344,7 +344,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, #define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS() \ 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() \ 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 -#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, kv_pair) \ +#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, key) \ 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")); \ 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_SPECIAL_DICT_KEY_CHECK(label, kv_pair) +#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, key) #define TYPVAL_ENCODE_CONV_LIST_END() diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h index e73a1ce057..98fa7b26c6 100644 --- a/src/nvim/eval/typval_encode.h +++ b/src/nvim/eval/typval_encode.h @@ -104,7 +104,7 @@ /// @brief Macros used to check special dictionary key /// /// @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 /// @brief Macros used after finishing converting dictionary key @@ -154,6 +154,7 @@ typedef enum { /// Structure representing current VimL to messagepack conversion state typedef struct { MPConvStackValType type; ///< Type of the stack entry. + typval_T *tv; ///< Currently converted typval_T. union { struct { 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. /// /// @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 /// the results. /// @param firstargname Name of the first argument. -/// @param name Name of the target converter. #define TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(scope, name, 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); \ _mp_push(*mpstack, ((MPConvStackVal) { \ .type = kMPConvList, \ + .tv = tv, \ .data = { \ .l = { \ .list = tv->vval.v_list, \ @@ -387,6 +389,7 @@ static int name##_convert_one_value(firstargtype firstargname, \ lv_copyID, kMPConvList); \ TYPVAL_ENCODE_CONV_LIST_START(val_di->di_tv.vval.v_list->lv_len); \ _mp_push(*mpstack, ((MPConvStackVal) { \ + .tv = tv, \ .type = kMPConvList, \ .data = { \ .l = { \ @@ -417,6 +420,7 @@ static int name##_convert_one_value(firstargtype firstargname, \ kMPConvPairs); \ TYPVAL_ENCODE_CONV_DICT_START(val_list->lv_len); \ _mp_push(*mpstack, ((MPConvStackVal) { \ + .tv = tv, \ .type = kMPConvPairs, \ .data = { \ .l = { \ @@ -457,6 +461,7 @@ name##_convert_one_value_regular_dict: \ kMPConvDict); \ TYPVAL_ENCODE_CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); \ _mp_push(*mpstack, ((MPConvStackVal) { \ + .tv = tv, \ .type = kMPConvDict, \ .data = { \ .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; \ 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, \ &kv_pair->lv_first->li_tv, copyID, \ objname) == FAIL) { \ diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h index 8ffc0c98ce..9000c06719 100644 --- a/src/nvim/eval_defs.h +++ b/src/nvim/eval_defs.h @@ -155,6 +155,10 @@ typedef struct list_stack_S { /// Convert a hashitem key pointer to a dictitem pointer #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 #define HI2DI(hi) HIKEY2DI((hi)->hi_key) |