diff options
Diffstat (limited to 'src/nvim/eval/typval_encode.h')
| -rw-r--r-- | src/nvim/eval/typval_encode.h | 593 | 
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  | 
