aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/typval_encode.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval/typval_encode.h')
-rw-r--r--src/nvim/eval/typval_encode.h593
1 files changed, 79 insertions, 514 deletions
diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h
index b79158b30c..6517efa961 100644
--- a/src/nvim/eval/typval_encode.h
+++ b/src/nvim/eval/typval_encode.h
@@ -1,161 +1,35 @@
-/// @file eval/typval_convert.h
+/// @file eval/typval_encode.h
///
-/// Contains set of macros used to convert (possibly recursive) typval_T into
-/// something else. For these macros to work the following macros must be
-/// defined:
-
-/// @def TYPVAL_ENCODE_CONV_NIL
-/// @brief Macros used to convert NIL value
-///
-/// Is called both for special dictionary (unless #TYPVAL_ENCODE_ALLOW_SPECIALS
-/// is false) and `v:null`. Accepts no arguments, but still must be
-/// a function-like macros.
-
-/// @def TYPVAL_ENCODE_CONV_BOOL
-/// @brief Macros used to convert boolean value
-///
-/// Is called both for special dictionary (unless #TYPVAL_ENCODE_ALLOW_SPECIALS
-/// is false) and `v:true`/`v:false`.
-///
-/// @param num Boolean value to convert. Value is an expression which
-/// evaluates to some integer.
-
-/// @def TYPVAL_ENCODE_CONV_NUMBER
-/// @brief Macros used to convert integer
-///
-/// @param num Integer to convert, must accept both varnumber_T and int64_t.
-
-/// @def TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER
-/// @brief Macros used to convert unsigned integer
-///
-/// Not used if #TYPVAL_ENCODE_ALLOW_SPECIALS is false, but still must be
-/// defined.
-///
-/// @param num Integer to convert, must accept uint64_t.
-
-/// @def TYPVAL_ENCODE_CONV_FLOAT
-/// @brief Macros used to convert floating-point number
-///
-/// @param flt Number to convert, must accept float_T.
-
-/// @def TYPVAL_ENCODE_CONV_STRING
-/// @brief Macros used to convert plain string
-///
-/// Is used to convert VAR_STRING objects as well as BIN strings represented as
-/// special dictionary.
-///
-/// @param buf String to convert. Is a char[] buffer, not NUL-terminated.
-/// @param len String length.
-
-/// @def TYPVAL_ENCODE_CONV_STR_STRING
-/// @brief Like #TYPVAL_ENCODE_CONV_STRING, but for STR strings
-///
-/// Is used to convert dictionary keys and STR strings represented as special
-/// dictionaries.
-
-/// @def TYPVAL_ENCODE_CONV_EXT_STRING
-/// @brief Macros used to convert EXT string
-///
-/// Is used to convert EXT strings represented as special dictionaries. Never
-/// actually used if #TYPVAL_ENCODE_ALLOW_SPECIALS is false, but still must be
-/// defined.
-///
-/// @param buf String to convert. Is a char[] buffer, not NUL-terminated.
-/// @param len String length.
-/// @param type EXT type.
-
-/// @def TYPVAL_ENCODE_CONV_FUNC
-/// @brief Macros used to convert a function reference
-///
-/// @param fun Function name.
-
-/// @def TYPVAL_ENCODE_CONV_PARTIAL
-/// @brief Macros used to convert a partial
-///
-/// @param pt Partial name.
-
-/// @def TYPVAL_ENCODE_CONV_EMPTY_LIST
-/// @brief Macros used to convert an empty list
-///
-/// Accepts no arguments, but still must be a function-like macros.
-
-/// @def TYPVAL_ENCODE_CONV_EMPTY_DICT
-/// @brief Macros used to convert an empty dictionary
-///
-/// Accepts no arguments, but still must be a function-like macros.
-
-/// @def TYPVAL_ENCODE_CONV_LIST_START
-/// @brief Macros used before starting to convert non-empty list
-///
-/// @param len List length. Is an expression which evaluates to an integer.
-
-/// @def TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS
-/// @brief Macros used after finishing converting non-last list item
-///
-/// Accepts no arguments, but still must be a function-like macros.
-
-/// @def TYPVAL_ENCODE_CONV_LIST_END
-/// @brief Macros used after converting non-empty list
-///
-/// Accepts no arguments, but still must be a function-like macros.
-
-/// @def TYPVAL_ENCODE_CONV_DICT_START
-/// @brief Macros used before starting to convert non-empty dictionary
-///
-/// @param len Dictionary length. Is an expression which evaluates to an
-/// integer.
-
-/// @def TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK
-/// @brief Macros used to check special dictionary key
-///
-/// @param label Label for goto in case check was not successfull.
-/// @param key typval_T key to check.
-
-/// @def TYPVAL_ENCODE_CONV_DICT_AFTER_KEY
-/// @brief Macros used after finishing converting dictionary key
-///
-/// Accepts no arguments, but still must be a function-like macros.
-
-/// @def TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS
-/// @brief Macros used after finishing converting non-last dictionary value
-///
-/// Accepts no arguments, but still must be a function-like macros.
-
-/// @def TYPVAL_ENCODE_CONV_DICT_END
-/// @brief Macros used after converting non-empty dictionary
-///
-/// Accepts no arguments, but still must be a function-like macros.
-
-/// @def TYPVAL_ENCODE_CONV_RECURSE
-/// @brief Macros used when self-containing container is detected
-///
-/// @param val Container for which this situation was detected.
-/// @param conv_type Type of the stack entry, @see MPConvStackValType.
-
-/// @def TYPVAL_ENCODE_ALLOW_SPECIALS
-/// @brief Macros that specifies whether special dictionaries are special
-///
-/// Must be something that evaluates to boolean, most likely `true` or `false`.
-/// If it is false then special dictionaries are not treated specially.
+/// Contains common definitions for eval/typval_encode.c.h. Most of time should
+/// not be included directly.
#ifndef NVIM_EVAL_TYPVAL_ENCODE_H
#define NVIM_EVAL_TYPVAL_ENCODE_H
#include <stddef.h>
#include <inttypes.h>
+#include <string.h>
#include <assert.h>
#include "nvim/lib/kvec.h"
#include "nvim/eval_defs.h"
-#include "nvim/eval/encode.h"
#include "nvim/func_attr.h"
/// Type of the stack entry
typedef enum {
- kMPConvDict, ///< Convert dict_T *dictionary.
- kMPConvList, ///< Convert list_T *list.
+ kMPConvDict, ///< Convert dict_T *dictionary.
+ kMPConvList, ///< Convert list_T *list.
kMPConvPairs, ///< Convert mapping represented as a list_T* of pairs.
+ kMPConvPartial, ///< Convert partial_T* partial.
+ kMPConvPartialList, ///< Convert argc/argv pair coming from a partial.
} MPConvStackValType;
+/// Stage at which partial is being converted
+typedef enum {
+ kMPConvPartialArgs, ///< About to convert arguments.
+ kMPConvPartialSelf, ///< About to convert self dictionary.
+ kMPConvPartialEnd, ///< Already converted everything.
+} MPConvPartialStage;
+
/// Structure representing current VimL to messagepack conversion state
typedef struct {
MPConvStackValType type; ///< Type of the stack entry.
@@ -163,6 +37,9 @@ typedef struct {
union {
struct {
dict_T *dict; ///< Currently converted dictionary.
+ dict_T **dictp; ///< Location where that dictionary is stored.
+ ///< Normally it is &.tv->vval.v_dict, but not when
+ ///< converting partials.
hashitem_T *hi; ///< Currently converted dictionary item.
size_t todo; ///< Amount of items left to process.
} d; ///< State of dictionary conversion.
@@ -170,6 +47,15 @@ typedef struct {
list_T *list; ///< Currently converted list.
listitem_T *li; ///< Currently converted list item.
} l; ///< State of list or generic mapping conversion.
+ struct {
+ MPConvPartialStage stage; ///< Stage at which partial is being converted.
+ partial_T *pt; ///< Currently converted partial.
+ } p; ///< State of partial conversion.
+ struct {
+ typval_T *arg; ///< Currently converted argument.
+ typval_T *argv; ///< Start of the argument list.
+ size_t todo; ///< Number of items left to process.
+ } a; ///< State of list or generic mapping conversion.
} data; ///< Data to convert.
} MPConvStackVal;
@@ -184,21 +70,9 @@ typedef kvec_withinit_t(MPConvStackVal, 8) MPConvStack;
#define _mp_pop kv_pop
#define _mp_last kv_last
-/// Code for checking whether container references itself
-///
-/// @param[in,out] val Container to check.
-/// @param copyID_attr Name of the container attribute that holds copyID.
-/// After checking whether value of this attribute is
-/// copyID (variable) it is set to copyID.
-/// @param conv_type Type of the conversion, @see MPConvStackValType.
-#define _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val, copyID_attr, conv_type) \
- do { \
- if ((val)->copyID_attr == copyID) { \
- TYPVAL_ENCODE_CONV_RECURSE((val), conv_type); \
- return OK; \
- } \
- (val)->copyID_attr = copyID; \
- } while (0)
+static inline size_t tv_strlen(const typval_T *const tv)
+ REAL_FATTR_ALWAYS_INLINE REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT
+ REAL_FATTR_NONNULL_ALL;
/// Length of the string stored in typval_T
///
@@ -208,8 +82,6 @@ typedef kvec_withinit_t(MPConvStackVal, 8) MPConvStack;
/// @return Length of the string stored in typval_T, including 0 for NULL
/// string.
static inline size_t tv_strlen(const typval_T *const tv)
- FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
- FUNC_ATTR_NONNULL_ALL
{
assert(tv->v_type == VAR_STRING);
return (tv->vval.v_string == NULL
@@ -217,363 +89,56 @@ static inline size_t tv_strlen(const typval_T *const tv)
: strlen((char *) tv->vval.v_string));
}
-/// Define functions to convert a VimL value:
-/// `{name}_convert_one_value(...)`
-/// `encode_vim_to_{name}(...)`
+/// Code for checking whether container references itself
///
-/// @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.
-#define TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(scope, name, firstargtype, \
- firstargname) \
-/* Returns OK or FAIL */ \
-static int name##_convert_one_value(firstargtype firstargname, \
- MPConvStack *const mpstack, \
- typval_T *const tv, \
- const int copyID, \
- const char *const objname) \
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \
-{ \
- switch (tv->v_type) { \
- case VAR_STRING: { \
- TYPVAL_ENCODE_CONV_STRING(tv->vval.v_string, tv_strlen(tv)); \
- break; \
- } \
- case VAR_NUMBER: { \
- TYPVAL_ENCODE_CONV_NUMBER(tv->vval.v_number); \
- break; \
- } \
- case VAR_FLOAT: { \
- TYPVAL_ENCODE_CONV_FLOAT(tv->vval.v_float); \
- break; \
- } \
- case VAR_FUNC: { \
- TYPVAL_ENCODE_CONV_FUNC(tv->vval.v_string); \
- break; \
- } \
- case VAR_PARTIAL: { \
- TYPVAL_ENCODE_CONV_PARTIAL(tv->vval.v_partial); \
- break; \
- } \
- case VAR_LIST: { \
- if (tv->vval.v_list == NULL || tv->vval.v_list->lv_len == 0) { \
- TYPVAL_ENCODE_CONV_EMPTY_LIST(); \
- break; \
- } \
- _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, \
- kMPConvList); \
- 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, \
- .li = tv->vval.v_list->lv_first, \
- }, \
- }, \
- })); \
- break; \
- } \
- case VAR_SPECIAL: { \
- switch (tv->vval.v_special) { \
- case kSpecialVarNull: { \
- TYPVAL_ENCODE_CONV_NIL(); \
- break; \
- } \
- case kSpecialVarTrue: \
- case kSpecialVarFalse: { \
- TYPVAL_ENCODE_CONV_BOOL(tv->vval.v_special == kSpecialVarTrue); \
- break; \
- } \
- } \
- break; \
- } \
- case VAR_DICT: { \
- if (tv->vval.v_dict == NULL \
- || tv->vval.v_dict->dv_hashtab.ht_used == 0) { \
- TYPVAL_ENCODE_CONV_EMPTY_DICT(); \
- break; \
- } \
- const dictitem_T *type_di; \
- const dictitem_T *val_di; \
- if (TYPVAL_ENCODE_ALLOW_SPECIALS \
- && tv->vval.v_dict->dv_hashtab.ht_used == 2 \
- && (type_di = dict_find((dict_T *) tv->vval.v_dict, \
- (char_u *) "_TYPE", -1)) != NULL \
- && type_di->di_tv.v_type == VAR_LIST \
- && (val_di = dict_find((dict_T *) tv->vval.v_dict, \
- (char_u *) "_VAL", -1)) != NULL) { \
- size_t i; \
- for (i = 0; i < ARRAY_SIZE(eval_msgpack_type_lists); i++) { \
- if (type_di->di_tv.vval.v_list == eval_msgpack_type_lists[i]) { \
- break; \
- } \
- } \
- if (i == ARRAY_SIZE(eval_msgpack_type_lists)) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- switch ((MessagePackType) i) { \
- case kMPNil: { \
- TYPVAL_ENCODE_CONV_NIL(); \
- break; \
- } \
- case kMPBoolean: { \
- if (val_di->di_tv.v_type != VAR_NUMBER) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- TYPVAL_ENCODE_CONV_BOOL(val_di->di_tv.vval.v_number); \
- break; \
- } \
- case kMPInteger: { \
- const list_T *val_list; \
- varnumber_T sign; \
- varnumber_T highest_bits; \
- varnumber_T high_bits; \
- varnumber_T low_bits; \
- /* List of 4 integers; first is signed (should be 1 or -1, but */ \
- /* this is not checked), second is unsigned and have at most */ \
- /* one (sign is -1) or two (sign is 1) non-zero bits (number of */ \
- /* bits is not checked), other unsigned and have at most 31 */ \
- /* non-zero bits (number of bits is not checked).*/ \
- if (val_di->di_tv.v_type != VAR_LIST \
- || (val_list = val_di->di_tv.vval.v_list) == NULL \
- || val_list->lv_len != 4 \
- || val_list->lv_first->li_tv.v_type != VAR_NUMBER \
- || (sign = val_list->lv_first->li_tv.vval.v_number) == 0 \
- || val_list->lv_first->li_next->li_tv.v_type != VAR_NUMBER \
- || (highest_bits = \
- val_list->lv_first->li_next->li_tv.vval.v_number) < 0 \
- || val_list->lv_last->li_prev->li_tv.v_type != VAR_NUMBER \
- || (high_bits = \
- val_list->lv_last->li_prev->li_tv.vval.v_number) < 0 \
- || val_list->lv_last->li_tv.v_type != VAR_NUMBER \
- || (low_bits = val_list->lv_last->li_tv.vval.v_number) < 0) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- uint64_t number = ((uint64_t) (((uint64_t) highest_bits) << 62) \
- | (uint64_t) (((uint64_t) high_bits) << 31) \
- | (uint64_t) low_bits); \
- if (sign > 0) { \
- TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(number); \
- } else { \
- TYPVAL_ENCODE_CONV_NUMBER(-number); \
- } \
- break; \
- } \
- case kMPFloat: { \
- if (val_di->di_tv.v_type != VAR_FLOAT) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- TYPVAL_ENCODE_CONV_FLOAT(val_di->di_tv.vval.v_float); \
- break; \
- } \
- case kMPString: \
- case kMPBinary: { \
- const bool is_string = ((MessagePackType) i == kMPString); \
- if (val_di->di_tv.v_type != VAR_LIST) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- size_t len; \
- char *buf; \
- if (!encode_vim_list_to_buf(val_di->di_tv.vval.v_list, &len, \
- &buf)) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- if (is_string) { \
- TYPVAL_ENCODE_CONV_STR_STRING(buf, len); \
- } else { \
- TYPVAL_ENCODE_CONV_STRING(buf, len); \
- } \
- xfree(buf); \
- break; \
- } \
- case kMPArray: { \
- if (val_di->di_tv.v_type != VAR_LIST) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, \
- 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 = { \
- .list = val_di->di_tv.vval.v_list, \
- .li = val_di->di_tv.vval.v_list->lv_first, \
- }, \
- }, \
- })); \
- break; \
- } \
- case kMPMap: { \
- if (val_di->di_tv.v_type != VAR_LIST) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- list_T *const val_list = val_di->di_tv.vval.v_list; \
- if (val_list == NULL || val_list->lv_len == 0) { \
- TYPVAL_ENCODE_CONV_EMPTY_DICT(); \
- break; \
- } \
- for (const listitem_T *li = val_list->lv_first; li != NULL; \
- li = li->li_next) { \
- if (li->li_tv.v_type != VAR_LIST \
- || li->li_tv.vval.v_list->lv_len != 2) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- } \
- _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_list, lv_copyID, \
- kMPConvPairs); \
- TYPVAL_ENCODE_CONV_DICT_START(val_list->lv_len); \
- _mp_push(*mpstack, ((MPConvStackVal) { \
- .tv = tv, \
- .type = kMPConvPairs, \
- .data = { \
- .l = { \
- .list = val_list, \
- .li = val_list->lv_first, \
- }, \
- }, \
- })); \
- break; \
- } \
- case kMPExt: { \
- const list_T *val_list; \
- varnumber_T type; \
- if (val_di->di_tv.v_type != VAR_LIST \
- || (val_list = val_di->di_tv.vval.v_list) == NULL \
- || val_list->lv_len != 2 \
- || (val_list->lv_first->li_tv.v_type != VAR_NUMBER) \
- || (type = val_list->lv_first->li_tv.vval.v_number) > INT8_MAX \
- || type < INT8_MIN \
- || (val_list->lv_last->li_tv.v_type != VAR_LIST)) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- size_t len; \
- char *buf; \
- if (!encode_vim_list_to_buf(val_list->lv_last->li_tv.vval.v_list, \
- &len, &buf)) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type); \
- xfree(buf); \
- break; \
- } \
- } \
- break; \
- } \
-name##_convert_one_value_regular_dict: \
- _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, \
- kMPConvDict); \
- TYPVAL_ENCODE_CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); \
- _mp_push(*mpstack, ((MPConvStackVal) { \
- .tv = tv, \
- .type = kMPConvDict, \
- .data = { \
- .d = { \
- .dict = tv->vval.v_dict, \
- .hi = tv->vval.v_dict->dv_hashtab.ht_array, \
- .todo = tv->vval.v_dict->dv_hashtab.ht_used, \
- }, \
- }, \
- })); \
- break; \
- } \
- case VAR_UNKNOWN: { \
- EMSG2(_(e_intern2), #name "_convert_one_value()"); \
- return FAIL; \
- } \
- } \
- return OK; \
-} \
-\
-scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \
- const char *const objname) \
- FUNC_ATTR_WARN_UNUSED_RESULT \
-{ \
- const int copyID = get_copyID(); \
- MPConvStack mpstack; \
- _mp_init(mpstack); \
- if (name##_convert_one_value(firstargname, &mpstack, tv, copyID, objname) \
- == FAIL) { \
- goto encode_vim_to_##name##_error_ret; \
- } \
- while (_mp_size(mpstack)) { \
- MPConvStackVal *cur_mpsv = &_mp_last(mpstack); \
- typval_T *cur_tv = NULL; \
- switch (cur_mpsv->type) { \
- case kMPConvDict: { \
- if (!cur_mpsv->data.d.todo) { \
- (void) _mp_pop(mpstack); \
- cur_mpsv->data.d.dict->dv_copyID = copyID - 1; \
- TYPVAL_ENCODE_CONV_DICT_END(); \
- continue; \
- } else if (cur_mpsv->data.d.todo \
- != cur_mpsv->data.d.dict->dv_hashtab.ht_used) { \
- TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(); \
- } \
- while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) { \
- cur_mpsv->data.d.hi++; \
- } \
- dictitem_T *const di = HI2DI(cur_mpsv->data.d.hi); \
- cur_mpsv->data.d.todo--; \
- cur_mpsv->data.d.hi++; \
- TYPVAL_ENCODE_CONV_STR_STRING(&di->di_key[0], \
- strlen((char *) &di->di_key[0])); \
- TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(); \
- cur_tv = &di->di_tv; \
- break; \
- } \
- case kMPConvList: { \
- if (cur_mpsv->data.l.li == NULL) { \
- (void) _mp_pop(mpstack); \
- cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
- TYPVAL_ENCODE_CONV_LIST_END(); \
- continue; \
- } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { \
- TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(); \
- } \
- cur_tv = &cur_mpsv->data.l.li->li_tv; \
- cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \
- break; \
- } \
- case kMPConvPairs: { \
- if (cur_mpsv->data.l.li == NULL) { \
- (void) _mp_pop(mpstack); \
- cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
- TYPVAL_ENCODE_CONV_DICT_END(); \
- continue; \
- } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { \
- TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(); \
- } \
- 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->lv_first->li_tv); \
- if (name##_convert_one_value(firstargname, &mpstack, \
- &kv_pair->lv_first->li_tv, copyID, \
- objname) == FAIL) { \
- goto encode_vim_to_##name##_error_ret; \
- } \
- TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(); \
- cur_tv = &kv_pair->lv_last->li_tv; \
- cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \
- break; \
+/// @param[in,out] val Container to check.
+/// @param copyID_attr Name of the container attribute that holds copyID.
+/// After checking whether value of this attribute is
+/// copyID (variable) it is set to copyID.
+/// @param[in] copyID CopyID used by the caller.
+/// @param conv_type Type of the conversion, @see MPConvStackValType.
+#define _TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(val, copyID_attr, copyID, \
+ conv_type) \
+ do { \
+ const int te_csr_ret = _TYPVAL_ENCODE_CHECK_SELF_REFERENCE( \
+ TYPVAL_ENCODE_FIRST_ARG_NAME, \
+ (val), &(val)->copyID_attr, mpstack, copyID, conv_type, objname); \
+ if (te_csr_ret != NOTDONE) { \
+ return te_csr_ret; \
} \
- } \
- assert(cur_tv != NULL); \
- if (name##_convert_one_value(firstargname, &mpstack, cur_tv, copyID, \
- objname) == FAIL) { \
- goto encode_vim_to_##name##_error_ret; \
- } \
- } \
- _mp_destroy(mpstack); \
- return OK; \
-encode_vim_to_##name##_error_ret: \
- _mp_destroy(mpstack); \
- return FAIL; \
-}
+ } while (0)
+
+#define _TYPVAL_ENCODE_CHECK_SELF_REFERENCE_INNER_2(name) \
+ _typval_encode_##name##_check_self_reference
+#define _TYPVAL_ENCODE_CHECK_SELF_REFERENCE_INNER(name) \
+ _TYPVAL_ENCODE_CHECK_SELF_REFERENCE_INNER_2(name)
+
+/// Self reference checker function name
+#define _TYPVAL_ENCODE_CHECK_SELF_REFERENCE \
+ _TYPVAL_ENCODE_CHECK_SELF_REFERENCE_INNER(TYPVAL_ENCODE_NAME)
+
+#define _TYPVAL_ENCODE_ENCODE_INNER_2(name) encode_vim_to_##name
+#define _TYPVAL_ENCODE_ENCODE_INNER(name) _TYPVAL_ENCODE_ENCODE_INNER_2(name)
+
+/// Entry point function name
+#define _TYPVAL_ENCODE_ENCODE _TYPVAL_ENCODE_ENCODE_INNER(TYPVAL_ENCODE_NAME)
+
+#define _TYPVAL_ENCODE_CONVERT_ONE_VALUE_INNER_2(name) \
+ _typval_encode_##name##_convert_one_value
+#define _TYPVAL_ENCODE_CONVERT_ONE_VALUE_INNER(name) \
+ _TYPVAL_ENCODE_CONVERT_ONE_VALUE_INNER_2(name)
+
+/// Name of the …convert_one_value function
+#define _TYPVAL_ENCODE_CONVERT_ONE_VALUE \
+ _TYPVAL_ENCODE_CONVERT_ONE_VALUE_INNER(TYPVAL_ENCODE_NAME)
+
+#define _TYPVAL_ENCODE_NODICT_VAR_INNER_2(name) \
+ _typval_encode_##name##_nodict_var
+#define _TYPVAL_ENCODE_NODICT_VAR_INNER(name) \
+ _TYPVAL_ENCODE_NODICT_VAR_INNER_2(name)
+
+/// Name of the dummy const dict_T *const variable
+#define TYPVAL_ENCODE_NODICT_VAR \
+ _TYPVAL_ENCODE_NODICT_VAR_INNER(TYPVAL_ENCODE_NAME)
#endif // NVIM_EVAL_TYPVAL_ENCODE_H