From c5c75513b81398f05a4e63b2f7207ae74de25ecc Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 25 Dec 2016 19:37:13 +0300 Subject: eval/typval_encode: Make partial conversions not recursive Is known to crash in the current state. Ref #5825. --- src/nvim/eval/encode.c | 131 +++++++++++++++++++----------------------- src/nvim/eval/typval_encode.h | 131 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 182 insertions(+), 80 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index 5af4893975..7e59998bf0 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -108,9 +108,12 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack, { garray_T msg_ga; ga_init(&msg_ga, (int)sizeof(char), 80); - char *const key_msg = _("key %s"); - char *const key_pair_msg = _("key %s at index %i from special map"); - char *const idx_msg = _("index %i"); + const char *const key_msg = _("key %s"); + const char *const key_pair_msg = _("key %s at index %i from special map"); + const char *const idx_msg = _("index %i"); + const char *const partial_arg_msg = _("partial"); + const char *const partial_arg_i_msg = _("argument %i"); + const char *const partial_self_msg = _("partial self dictionary"); for (size_t i = 0; i < kv_size(*mpstack); i++) { if (i != 0) { ga_concat(&msg_ga, ", "); @@ -154,6 +157,29 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack, } break; } + case kMPConvPartial: { + switch (v.data.p.stage) { + case kMPConvPartialArgs: { + assert(false); + break; + } + case kMPConvPartialSelf: { + ga_concat(&msg_ga, partial_arg_msg); + break; + } + case kMPConvPartialEnd: { + ga_concat(&msg_ga, partial_self_msg); + break; + } + } + break; + } + case kMPConvPartialList: { + const int idx = (int)(v.data.a.arg - v.data.a.argv) - 1; + vim_snprintf((char *)IObuff, IOSIZE, partial_arg_i_msg, idx); + ga_concat(&msg_ga, IObuff); + break; + } } } EMSG3(msg, objname, (kv_size(*mpstack) == 0 @@ -308,67 +334,29 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, } \ } while (0) -#define TYPVAL_ENCODE_CONV_FUNC(fun) \ +#define TYPVAL_ENCODE_CONV_FUNC_START(fun, is_partial, pt) \ do { \ ga_concat(gap, "function("); \ TYPVAL_ENCODE_CONV_STRING(fun, STRLEN(fun)); \ - ga_append(gap, ')'); \ } while (0) -#define TYPVAL_ENCODE_CONV_PARTIAL(pt) \ +#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(len) \ do { \ - int i; \ - ga_concat(gap, "function("); \ - if (pt->pt_name != NULL) { \ - size_t len; \ - char_u *p; \ - len = 3; \ - len += STRLEN(pt->pt_name); \ - for (p = pt->pt_name; *p != NUL; mb_ptr_adv(p)) { \ - if (*p == '\'') { \ - len++; \ - } \ - } \ - char_u *r, *s; \ - s = r = xmalloc(len); \ - if (r != NULL) { \ - *r++ = '\''; \ - for (p = pt->pt_name; *p != NUL; ) { \ - if (*p == '\'') { \ - *r++ = '\''; \ - } \ - MB_COPY_CHAR(p, r); \ - } \ - *r++ = '\''; \ - *r++ = NUL; \ - } \ - ga_concat(gap, s); \ - xfree(s); \ - } \ - if (pt->pt_argc > 0) { \ - ga_concat(gap, ", ["); \ - for (i = 0; i < pt->pt_argc; i++) { \ - if (i > 0) { \ - ga_concat(gap, ", "); \ - } \ - char *tofree = encode_tv2string(&pt->pt_argv[i], NULL); \ - ga_concat(gap, tofree); \ - xfree(tofree); \ - } \ - ga_append(gap, ']'); \ - } \ - if (pt->pt_dict != NULL) { \ - typval_T dtv; \ - ga_concat(gap, ", "); \ - dtv.v_type = VAR_DICT; \ - dtv.vval.v_dict = pt->pt_dict; \ - char *tofree = encode_tv2string(&dtv, NULL); \ - ga_concat(gap, tofree); \ - xfree(tofree); \ - } \ - ga_append(gap, ')'); \ + if (len != 0) { \ + ga_concat(gap, ", "); \ + } \ + } while (0) + +#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(len) \ + do { \ + if ((ptrdiff_t)len != -1) { \ + ga_concat(gap, ", "); \ + } \ } while (0) +#define TYPVAL_ENCODE_CONV_FUNC_END() \ + ga_append(gap, ')') + #define TYPVAL_ENCODE_CONV_EMPTY_LIST() \ ga_concat(gap, "[]") @@ -709,18 +697,12 @@ static inline int convert_to_json_string(garray_T *const gap, return FAIL; \ } while (0) -#undef TYPVAL_ENCODE_CONV_FUNC -#define TYPVAL_ENCODE_CONV_FUNC(fun) \ +#undef TYPVAL_ENCODE_CONV_FUNC_START +#define TYPVAL_ENCODE_CONV_FUNC_START(fun, is_partial, pt) \ return conv_error(_("E474: Error while dumping %s, %s: " \ "attempt to dump function reference"), \ mpstack, objname) -#undef TYPVAL_ENCODE_CONV_PARTIAL -#define TYPVAL_ENCODE_CONV_PARTIAL(pt) \ - return conv_error(_("E474: Error while dumping %s, %s: " \ - "attempt to dump partial"), \ - mpstack, objname) - /// Check whether given key can be used in json_encode() /// /// @param[in] tv Key to check. @@ -777,8 +759,10 @@ TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, json, garray_T *const, gap) #undef TYPVAL_ENCODE_CONV_EXT_STRING #undef TYPVAL_ENCODE_CONV_NUMBER #undef TYPVAL_ENCODE_CONV_FLOAT -#undef TYPVAL_ENCODE_CONV_FUNC -#undef TYPVAL_ENCODE_CONV_PARTIAL +#undef TYPVAL_ENCODE_CONV_FUNC_START +#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS +#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF +#undef TYPVAL_ENCODE_CONV_FUNC_END #undef TYPVAL_ENCODE_CONV_EMPTY_LIST #undef TYPVAL_ENCODE_CONV_LIST_START #undef TYPVAL_ENCODE_CONV_EMPTY_DICT @@ -902,15 +886,14 @@ char *encode_tv2json(typval_T *tv, size_t *len) #define TYPVAL_ENCODE_CONV_FLOAT(flt) \ msgpack_pack_double(packer, (double) (flt)) -#define TYPVAL_ENCODE_CONV_FUNC(fun) \ +#define TYPVAL_ENCODE_CONV_FUNC_START(fun, is_partial, pt) \ return conv_error(_("E5004: Error while dumping %s, %s: " \ "attempt to dump function reference"), \ mpstack, objname) -#define TYPVAL_ENCODE_CONV_PARTIAL(partial) \ - return conv_error(_("E5004: Error while dumping %s, %s: " \ - "attempt to dump partial"), \ - mpstack, objname) +#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(len) +#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(len) +#define TYPVAL_ENCODE_CONV_FUNC_END() #define TYPVAL_ENCODE_CONV_EMPTY_LIST() \ msgpack_pack_array(packer, 0) @@ -967,8 +950,10 @@ TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(, msgpack, msgpack_packer *const, packer) #undef TYPVAL_ENCODE_CONV_EXT_STRING #undef TYPVAL_ENCODE_CONV_NUMBER #undef TYPVAL_ENCODE_CONV_FLOAT -#undef TYPVAL_ENCODE_CONV_FUNC -#undef TYPVAL_ENCODE_CONV_PARTIAL +#undef TYPVAL_ENCODE_CONV_FUNC_START +#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS +#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF +#undef TYPVAL_ENCODE_CONV_FUNC_END #undef TYPVAL_ENCODE_CONV_EMPTY_LIST #undef TYPVAL_ENCODE_CONV_LIST_START #undef TYPVAL_ENCODE_CONV_EMPTY_DICT diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h index b79158b30c..149dd22ff7 100644 --- a/src/nvim/eval/typval_encode.h +++ b/src/nvim/eval/typval_encode.h @@ -69,10 +69,30 @@ /// /// @param fun Function name. -/// @def TYPVAL_ENCODE_CONV_PARTIAL -/// @brief Macros used to convert a partial +/// @def TYPVAL_ENCODE_CONV_FUNC_START +/// @brief Macros used when starting to convert a funcref or a partial /// -/// @param pt Partial name. +/// @param fun Function name. +/// @param is_partial True if converted function is a partial. +/// @param pt Pointer to partial or NULL. + +/// @def TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS +/// @brief Macros used before starting to convert partial arguments +/// +/// @param len Number of arguments. Zero for absent arguments or when +/// converting a funcref. + +/// @def TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF +/// @brief Macros used before starting to convert self dictionary +/// +/// @param len Number of arguments. May be zero for empty dictionary or -1 for +/// missing self dictionary, also when converting function +/// reference. + +/// @def TYPVAL_ENCODE_CONV_FUNC_END +/// @brief Macros used after converting a funcref or a partial +/// +/// Accepts no arguments, but still must be a function-like macros. /// @def TYPVAL_ENCODE_CONV_EMPTY_LIST /// @brief Macros used to convert an empty list @@ -151,11 +171,20 @@ /// 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. @@ -170,6 +199,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; @@ -250,11 +288,26 @@ static int name##_convert_one_value(firstargtype firstargname, \ break; \ } \ case VAR_FUNC: { \ - TYPVAL_ENCODE_CONV_FUNC(tv->vval.v_string); \ + TYPVAL_ENCODE_CONV_FUNC_START(tv->vval.v_string, false, NULL); \ + TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(0); \ + TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(-1); \ + TYPVAL_ENCODE_CONV_FUNC_END(); \ break; \ } \ case VAR_PARTIAL: { \ - TYPVAL_ENCODE_CONV_PARTIAL(tv->vval.v_partial); \ + partial_T *const pt = tv->vval.v_partial; \ + (void)pt; \ + TYPVAL_ENCODE_CONV_FUNC_START(pt->pt_name, true, pt); \ + _mp_push(*mpstack, ((MPConvStackVal) { \ + .type = kMPConvPartial, \ + .tv = tv, \ + .data = { \ + .p = { \ + .stage = kMPConvPartialArgs, \ + .pt = tv->vval.v_partial, \ + }, \ + }, \ + })); \ break; \ } \ case VAR_LIST: { \ @@ -562,6 +615,70 @@ scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \ cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \ break; \ } \ + case kMPConvPartial: { \ + partial_T *const pt = cur_mpsv->data.p.pt; \ + switch (cur_mpsv->data.p.stage) { \ + case kMPConvPartialArgs: { \ + TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(pt->pt_argc); \ + cur_mpsv->data.p.stage = kMPConvPartialSelf; \ + if (pt->pt_argc > 0) { \ + TYPVAL_ENCODE_CONV_LIST_START(pt->pt_argc); \ + _mp_push(mpstack, ((MPConvStackVal) { \ + .type = kMPConvPartialList, \ + .tv = tv, \ + .data = { \ + .a = { \ + .arg = pt->pt_argv, \ + .argv = pt->pt_argv, \ + .todo = (size_t)pt->pt_argc, \ + }, \ + }, \ + })); \ + } \ + break; \ + } \ + case kMPConvPartialSelf: { \ + cur_mpsv->data.p.stage = kMPConvPartialEnd; \ + dict_T *const dict = pt->pt_dict; \ + if (dict != NULL) { \ + TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(dict->dv_hashtab.ht_used); \ + TYPVAL_ENCODE_CONV_DICT_START(dict->dv_hashtab.ht_used); \ + _mp_push(mpstack, ((MPConvStackVal) { \ + .type = kMPConvDict, \ + .tv = tv, \ + .data = { \ + .d = { \ + .dict = dict, \ + .hi = dict->dv_hashtab.ht_array, \ + .todo = dict->dv_hashtab.ht_used, \ + }, \ + }, \ + })); \ + } else { \ + TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(-1); \ + } \ + break; \ + } \ + case kMPConvPartialEnd: { \ + TYPVAL_ENCODE_CONV_FUNC_END(); \ + (void) _mp_pop(mpstack); \ + break; \ + } \ + } \ + continue; \ + } \ + case kMPConvPartialList: { \ + if (!cur_mpsv->data.a.todo) { \ + (void) _mp_pop(mpstack); \ + TYPVAL_ENCODE_CONV_LIST_END(); \ + continue; \ + } else if (cur_mpsv->data.a.argv != cur_mpsv->data.a.arg) { \ + TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(); \ + } \ + cur_tv = cur_mpsv->data.a.arg++; \ + cur_mpsv->data.a.todo--; \ + break; \ + } \ } \ assert(cur_tv != NULL); \ if (name##_convert_one_value(firstargname, &mpstack, cur_tv, copyID, \ -- cgit From b3163d06b340b95ca85421cff8a64c5bc1935f5e Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 25 Dec 2016 20:54:06 +0300 Subject: eval/typval_encode: Refactor big-big macros into .c.h file This makes gdb backtraces much more meaningful: specifically I now know at which line it crashes in place of seeing that it crashes at TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS macros invocation. --- src/nvim/eval/encode.c | 58 +++- src/nvim/eval/typval_encode.c.h | 656 ++++++++++++++++++++++++++++++++++++++++ src/nvim/eval/typval_encode.h | 491 +++--------------------------- 3 files changed, 739 insertions(+), 466 deletions(-) create mode 100644 src/nvim/eval/typval_encode.c.h (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index 7e59998bf0..38f0863195 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -425,9 +425,17 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, #define TYPVAL_ENCODE_ALLOW_SPECIALS false -// string_convert_one_value() +#define TYPVAL_ENCODE_SCOPE static +#define TYPVAL_ENCODE_NAME string +#define TYPVAL_ENCODE_FIRST_ARG_TYPE garray_T *const +#define TYPVAL_ENCODE_FIRST_ARG_NAME gap +// _string_convert_one_value() // encode_vim_to_string() -TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, string, garray_T *const, gap) +#include "nvim/eval/typval_encode.c.h" +#undef TYPVAL_ENCODE_SCOPE +#undef TYPVAL_ENCODE_NAME +#undef TYPVAL_ENCODE_FIRST_ARG_TYPE +#undef TYPVAL_ENCODE_FIRST_ARG_NAME #undef TYPVAL_ENCODE_CONV_RECURSE #define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ @@ -457,9 +465,17 @@ TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, string, garray_T *const, gap) return OK; \ } while (0) -// echo_convert_one_value() +#define TYPVAL_ENCODE_SCOPE +#define TYPVAL_ENCODE_NAME echo +#define TYPVAL_ENCODE_FIRST_ARG_TYPE garray_T *const +#define TYPVAL_ENCODE_FIRST_ARG_NAME gap +// _echo_convert_one_value() // encode_vim_to_echo() -TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(, echo, garray_T *const, gap) +#include "nvim/eval/typval_encode.c.h" +#undef TYPVAL_ENCODE_SCOPE +#undef TYPVAL_ENCODE_NAME +#undef TYPVAL_ENCODE_FIRST_ARG_TYPE +#undef TYPVAL_ENCODE_FIRST_ARG_NAME #undef TYPVAL_ENCODE_CONV_RECURSE #define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ @@ -750,9 +766,17 @@ bool encode_check_json_key(const typval_T *const tv) } \ } while (0) -// json_convert_one_value() +#define TYPVAL_ENCODE_SCOPE static +#define TYPVAL_ENCODE_NAME json +#define TYPVAL_ENCODE_FIRST_ARG_TYPE garray_T *const +#define TYPVAL_ENCODE_FIRST_ARG_NAME gap +// _json_convert_one_value() // encode_vim_to_json() -TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, json, garray_T *const, gap) +#include "nvim/eval/typval_encode.c.h" +#undef TYPVAL_ENCODE_SCOPE +#undef TYPVAL_ENCODE_NAME +#undef TYPVAL_ENCODE_FIRST_ARG_TYPE +#undef TYPVAL_ENCODE_FIRST_ARG_NAME #undef TYPVAL_ENCODE_CONV_STRING #undef TYPVAL_ENCODE_CONV_STR_STRING @@ -791,7 +815,9 @@ char *encode_tv2string(typval_T *tv, size_t *len) { garray_T ga; ga_init(&ga, (int)sizeof(char), 80); - encode_vim_to_string(&ga, tv, "encode_tv2string() argument"); + const int evs_ret = encode_vim_to_string(&ga, tv, + "encode_tv2string() argument"); + (void)evs_ret; did_echo_string_emsg = false; if (len != NULL) { *len = (size_t) ga.ga_len; @@ -817,7 +843,8 @@ char *encode_tv2echo(typval_T *tv, size_t *len) ga_concat(&ga, tv->vval.v_string); } } else { - encode_vim_to_echo(&ga, tv, ":echo argument"); + const int eve_ret = encode_vim_to_echo(&ga, tv, ":echo argument"); + (void)eve_ret; } if (len != NULL) { *len = (size_t) ga.ga_len; @@ -838,7 +865,8 @@ char *encode_tv2json(typval_T *tv, size_t *len) { garray_T ga; ga_init(&ga, (int)sizeof(char), 80); - encode_vim_to_json(&ga, tv, "encode_tv2json() argument"); + const int evj_ret = encode_vim_to_json(&ga, tv, "encode_tv2json() argument"); + (void)evj_ret; did_echo_string_emsg = false; if (len != NULL) { *len = (size_t) ga.ga_len; @@ -941,9 +969,17 @@ char *encode_tv2json(typval_T *tv, size_t *len) #define TYPVAL_ENCODE_ALLOW_SPECIALS true -// msgpack_convert_one_value() +#define TYPVAL_ENCODE_SCOPE +#define TYPVAL_ENCODE_NAME msgpack +#define TYPVAL_ENCODE_FIRST_ARG_TYPE msgpack_packer *const +#define TYPVAL_ENCODE_FIRST_ARG_NAME packer +// _msgpack_convert_one_value() // encode_vim_to_msgpack() -TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(, msgpack, msgpack_packer *const, packer) +#include "nvim/eval/typval_encode.c.h" +#undef TYPVAL_ENCODE_SCOPE +#undef TYPVAL_ENCODE_NAME +#undef TYPVAL_ENCODE_FIRST_ARG_TYPE +#undef TYPVAL_ENCODE_FIRST_ARG_NAME #undef TYPVAL_ENCODE_CONV_STRING #undef TYPVAL_ENCODE_CONV_STR_STRING diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h new file mode 100644 index 0000000000..d45986396a --- /dev/null +++ b/src/nvim/eval/typval_encode.c.h @@ -0,0 +1,656 @@ +/// @file eval/typval_encode.c.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_FUNC_START +/// @brief Macros used when starting to convert a funcref or a partial +/// +/// @param fun Function name. +/// @param is_partial True if converted function is a partial. +/// @param pt Pointer to partial or NULL. + +/// @def TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS +/// @brief Macros used before starting to convert partial arguments +/// +/// @param len Number of arguments. Zero for absent arguments or when +/// converting a funcref. + +/// @def TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF +/// @brief Macros used before starting to convert self dictionary +/// +/// @param len Number of arguments. May be zero for empty dictionary or -1 for +/// missing self dictionary, also when converting function +/// reference. + +/// @def TYPVAL_ENCODE_CONV_FUNC_END +/// @brief Macros used after converting a funcref or a partial +/// +/// Accepts no arguments, but still must be a function-like macros. + +/// @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. + +/// @def TYPVAL_ENCODE_SCOPE +/// @brief Scope of the main function: either nothing or `static` + +/// @def TYPVAL_ENCODE_NAME +/// @brief Name of the target converter +/// +/// After including this file it will define function +/// `encode_vim_to_{TYPVAL_ENCODE_NAME}` with scope #TYPVAL_ENCODE_SCOPE and +/// static function `_{TYPVAL_ENCODE_NAME}_convert_one_value`. + +/// @def TYPVAL_ENCODE_FIRST_ARG_TYPE +/// @brief Type of the first argument, which will be used to return the results +/// +/// Is expected to be a pointer type. + +/// @def TYPVAL_ENCODE_FIRST_ARG_NAME +/// @brief Name of the first argument +/// +/// This name will only be used by one of the above macros which are defined by +/// the caller. Functions defined here do not use first argument directly. +#ifndef NVIM_EVAL_TYPVAL_ENCODE_C_H +#define NVIM_EVAL_TYPVAL_ENCODE_C_H +#undef NVIM_EVAL_TYPVAL_ENCODE_C_H + +#include +#include +#include + +#include "nvim/lib/kvec.h" +#include "nvim/eval_defs.h" +#include "nvim/eval/encode.h" +#include "nvim/func_attr.h" +#include "nvim/eval/typval_encode.h" + +static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( + TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME, + MPConvStack *const mpstack, typval_T *const tv, const int copyID, + const char *const objname) + REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; + +/// Convert single value +/// +/// Only scalar values are converted immediately, everything else is pushed onto +/// the stack. +/// +/// @param TYPVAL_ENCODE_FIRST_ARG_NAME First argument, defined by the +/// includer. Only meaningful to macros +/// defined by the includer. +/// @param[out] mpstack Stack with values to convert. Values which are not +/// converted completely by this function (i.e. +/// non-scalars) are pushed here. +/// @param tv Converted value. +/// @param[in] copyID CopyID. +/// @param[in] objname Object name, used for error reporting. +/// +/// @return OK in case of success, FAIL in case of failure. +static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( + TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME, + MPConvStack *const mpstack, typval_T *const tv, const int copyID, + const char *const objname) +{ + 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_START(tv->vval.v_string, false, NULL); + TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(0); + TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(-1); + TYPVAL_ENCODE_CONV_FUNC_END(); + break; + } + case VAR_PARTIAL: { + partial_T *const pt = tv->vval.v_partial; + (void)pt; + TYPVAL_ENCODE_CONV_FUNC_START(pt->pt_name, true, pt); + _mp_push(*mpstack, ((MPConvStackVal) { + .type = kMPConvPartial, + .tv = tv, + .data = { + .p = { + .stage = kMPConvPartialArgs, + .pt = 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, 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 _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 _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 _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 _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 _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 _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 _convert_one_value_regular_dict; + } + _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, + lv_copyID, 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 _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 _convert_one_value_regular_dict; + } + } + _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_list, lv_copyID, 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 _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 _convert_one_value_regular_dict; + } + TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type); + xfree(buf); + break; + } + } + break; + } +_convert_one_value_regular_dict: + _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, 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), STR(_TYPVAL_ENCODE_CONVERT_ONE_VALUE) "()"); + return FAIL; + } + } + return OK; +} + +TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( + TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME, + typval_T *const tv, const char *const objname) + REAL_FATTR_WARN_UNUSED_RESULT; + +/// Convert the whole typval +/// +/// @param TYPVAL_ENCODE_FIRST_ARG_NAME First argument, defined by the +/// includer. Only meaningful to macros +/// defined by the includer. +/// @param tv Converted value. +/// @param[in] objname Object name, used for error reporting. +/// +/// @return OK in case of success, FAIL in case of failure. +TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( + TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME, + typval_T *const tv, const char *const objname) +{ + const int copyID = get_copyID(); + MPConvStack mpstack; + _mp_init(mpstack); + if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE(TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, + tv, copyID, objname) + == FAIL) { + goto encode_vim_to__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__error_ret, kv_pair->lv_first->li_tv); + if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE( + TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, + &kv_pair->lv_first->li_tv, copyID, objname) == FAIL) { + goto encode_vim_to__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; + } + case kMPConvPartial: { + partial_T *const pt = cur_mpsv->data.p.pt; + switch (cur_mpsv->data.p.stage) { + case kMPConvPartialArgs: { + TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(pt->pt_argc); + cur_mpsv->data.p.stage = kMPConvPartialSelf; + if (pt->pt_argc > 0) { + TYPVAL_ENCODE_CONV_LIST_START(pt->pt_argc); + _mp_push(mpstack, ((MPConvStackVal) { + .type = kMPConvPartialList, + .tv = tv, + .data = { + .a = { + .arg = pt->pt_argv, + .argv = pt->pt_argv, + .todo = (size_t)pt->pt_argc, + }, + }, + })); + } + break; + } + case kMPConvPartialSelf: { + cur_mpsv->data.p.stage = kMPConvPartialEnd; + dict_T *const dict = pt->pt_dict; + if (dict != NULL) { + TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(dict->dv_hashtab.ht_used); + TYPVAL_ENCODE_CONV_DICT_START(dict->dv_hashtab.ht_used); + _mp_push(mpstack, ((MPConvStackVal) { + .type = kMPConvDict, + .tv = tv, + .data = { + .d = { + .dict = dict, + .hi = dict->dv_hashtab.ht_array, + .todo = dict->dv_hashtab.ht_used, + }, + }, + })); + } else { + TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(-1); + } + break; + } + case kMPConvPartialEnd: { + TYPVAL_ENCODE_CONV_FUNC_END(); + (void) _mp_pop(mpstack); + break; + } + } + continue; + } + case kMPConvPartialList: { + if (!cur_mpsv->data.a.todo) { + (void) _mp_pop(mpstack); + TYPVAL_ENCODE_CONV_LIST_END(); + continue; + } else if (cur_mpsv->data.a.argv != cur_mpsv->data.a.arg) { + TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(); + } + cur_tv = cur_mpsv->data.a.arg++; + cur_mpsv->data.a.todo--; + break; + } + } + assert(cur_tv != NULL); + if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE( + TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, cur_tv, copyID, objname) + == FAIL) { + goto encode_vim_to__error_ret; + } + } + _mp_destroy(mpstack); + return OK; +encode_vim_to__error_ret: + _mp_destroy(mpstack); + return FAIL; +} +#endif // NVIM_EVAL_TYPVAL_ENCODE_C_H diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h index 149dd22ff7..8fb37de93e 100644 --- a/src/nvim/eval/typval_encode.h +++ b/src/nvim/eval/typval_encode.h @@ -1,4 +1,4 @@ -/// @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 @@ -162,11 +162,11 @@ #include #include +#include #include #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 @@ -222,21 +222,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 /// @@ -246,8 +234,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 @@ -255,442 +241,37 @@ 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}(...)` -/// -/// @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_START(tv->vval.v_string, false, NULL); \ - TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(0); \ - TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(-1); \ - TYPVAL_ENCODE_CONV_FUNC_END(); \ - break; \ - } \ - case VAR_PARTIAL: { \ - partial_T *const pt = tv->vval.v_partial; \ - (void)pt; \ - TYPVAL_ENCODE_CONV_FUNC_START(pt->pt_name, true, pt); \ - _mp_push(*mpstack, ((MPConvStackVal) { \ - .type = kMPConvPartial, \ - .tv = tv, \ - .data = { \ - .p = { \ - .stage = kMPConvPartialArgs, \ - .pt = 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; \ - } \ - case kMPConvPartial: { \ - partial_T *const pt = cur_mpsv->data.p.pt; \ - switch (cur_mpsv->data.p.stage) { \ - case kMPConvPartialArgs: { \ - TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(pt->pt_argc); \ - cur_mpsv->data.p.stage = kMPConvPartialSelf; \ - if (pt->pt_argc > 0) { \ - TYPVAL_ENCODE_CONV_LIST_START(pt->pt_argc); \ - _mp_push(mpstack, ((MPConvStackVal) { \ - .type = kMPConvPartialList, \ - .tv = tv, \ - .data = { \ - .a = { \ - .arg = pt->pt_argv, \ - .argv = pt->pt_argv, \ - .todo = (size_t)pt->pt_argc, \ - }, \ - }, \ - })); \ - } \ - break; \ - } \ - case kMPConvPartialSelf: { \ - cur_mpsv->data.p.stage = kMPConvPartialEnd; \ - dict_T *const dict = pt->pt_dict; \ - if (dict != NULL) { \ - TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(dict->dv_hashtab.ht_used); \ - TYPVAL_ENCODE_CONV_DICT_START(dict->dv_hashtab.ht_used); \ - _mp_push(mpstack, ((MPConvStackVal) { \ - .type = kMPConvDict, \ - .tv = tv, \ - .data = { \ - .d = { \ - .dict = dict, \ - .hi = dict->dv_hashtab.ht_array, \ - .todo = dict->dv_hashtab.ht_used, \ - }, \ - }, \ - })); \ - } else { \ - TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(-1); \ - } \ - break; \ - } \ - case kMPConvPartialEnd: { \ - TYPVAL_ENCODE_CONV_FUNC_END(); \ - (void) _mp_pop(mpstack); \ - break; \ - } \ - } \ - continue; \ - } \ - case kMPConvPartialList: { \ - if (!cur_mpsv->data.a.todo) { \ - (void) _mp_pop(mpstack); \ - TYPVAL_ENCODE_CONV_LIST_END(); \ - continue; \ - } else if (cur_mpsv->data.a.argv != cur_mpsv->data.a.arg) { \ - TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(); \ - } \ - cur_tv = cur_mpsv->data.a.arg++; \ - cur_mpsv->data.a.todo--; \ - break; \ +/// 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[in] copyID CopyID used by the caller. +/// @param conv_type Type of the conversion, @see MPConvStackValType. +#define _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val, copyID_attr, copyID, \ + conv_type) \ + do { \ + if ((val)->copyID_attr == (copyID)) { \ + TYPVAL_ENCODE_CONV_RECURSE((val), conv_type); \ + return OK; \ } \ - } \ - 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; \ -} + (val)->copyID_attr = (copyID); \ + } while (0) + +#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) #endif // NVIM_EVAL_TYPVAL_ENCODE_H -- cgit From 27343bc5b2b56cba76059c117fb97b558bc7bc78 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 25 Dec 2016 21:02:27 +0300 Subject: eval/typval_encode: Fix crashes --- src/nvim/eval/typval_encode.c.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index d45986396a..8005f7cfcf 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -579,9 +579,9 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( partial_T *const pt = cur_mpsv->data.p.pt; switch (cur_mpsv->data.p.stage) { case kMPConvPartialArgs: { - TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(pt->pt_argc); + TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(pt == NULL ? 0 : pt->pt_argc); cur_mpsv->data.p.stage = kMPConvPartialSelf; - if (pt->pt_argc > 0) { + if (pt != NULL && pt->pt_argc > 0) { TYPVAL_ENCODE_CONV_LIST_START(pt->pt_argc); _mp_push(mpstack, ((MPConvStackVal) { .type = kMPConvPartialList, @@ -599,7 +599,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( } case kMPConvPartialSelf: { cur_mpsv->data.p.stage = kMPConvPartialEnd; - dict_T *const dict = pt->pt_dict; + dict_T *const dict = pt == NULL ? NULL : pt->pt_dict; if (dict != NULL) { TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(dict->dv_hashtab.ht_used); TYPVAL_ENCODE_CONV_DICT_START(dict->dv_hashtab.ht_used); -- cgit From dd27fcfda5c650be1cd57806e674f6f723f60659 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 25 Dec 2016 21:20:31 +0300 Subject: eval/typval_encode: Fix linter errors --- src/nvim/eval/typval_encode.c.h | 53 +++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 26 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index 8005f7cfcf..597fd71030 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -299,11 +299,11 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( 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 = 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) { + && (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]) { @@ -313,7 +313,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( if (i == ARRAY_SIZE(eval_msgpack_type_lists)) { goto _convert_one_value_regular_dict; } - switch ((MessagePackType) i) { + switch ((MessagePackType)i) { case kMPNil: { TYPVAL_ENCODE_CONV_NIL(); break; @@ -331,11 +331,11 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( 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).*/ + // 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 @@ -351,9 +351,9 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( || (low_bits = val_list->lv_last->li_tv.vval.v_number) < 0) { goto _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); + 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 { @@ -370,7 +370,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( } case kMPString: case kMPBinary: { - const bool is_string = ((MessagePackType) i == kMPString); + const bool is_string = ((MessagePackType)i == kMPString); if (val_di->di_tv.v_type != VAR_LIST) { goto _convert_one_value_regular_dict; } @@ -520,7 +520,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( switch (cur_mpsv->type) { case kMPConvDict: { if (!cur_mpsv->data.d.todo) { - (void) _mp_pop(mpstack); + (void)_mp_pop(mpstack); cur_mpsv->data.d.dict->dv_copyID = copyID - 1; TYPVAL_ENCODE_CONV_DICT_END(); continue; @@ -535,14 +535,14 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( 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])); + 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); + (void)_mp_pop(mpstack); cur_mpsv->data.l.list->lv_copyID = copyID - 1; TYPVAL_ENCODE_CONV_LIST_END(); continue; @@ -555,7 +555,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( } case kMPConvPairs: { if (cur_mpsv->data.l.li == NULL) { - (void) _mp_pop(mpstack); + (void)_mp_pop(mpstack); cur_mpsv->data.l.list->lv_copyID = copyID - 1; TYPVAL_ENCODE_CONV_DICT_END(); continue; @@ -565,9 +565,11 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( 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__error_ret, kv_pair->lv_first->li_tv); - if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE( - TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, - &kv_pair->lv_first->li_tv, copyID, objname) == FAIL) { + if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE(TYPVAL_ENCODE_FIRST_ARG_NAME, + &mpstack, + &kv_pair->lv_first->li_tv, + copyID, + objname) == FAIL) { goto encode_vim_to__error_ret; } TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(); @@ -621,7 +623,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( } case kMPConvPartialEnd: { TYPVAL_ENCODE_CONV_FUNC_END(); - (void) _mp_pop(mpstack); + (void)_mp_pop(mpstack); break; } } @@ -629,7 +631,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( } case kMPConvPartialList: { if (!cur_mpsv->data.a.todo) { - (void) _mp_pop(mpstack); + (void)_mp_pop(mpstack); TYPVAL_ENCODE_CONV_LIST_END(); continue; } else if (cur_mpsv->data.a.argv != cur_mpsv->data.a.arg) { @@ -641,9 +643,8 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( } } assert(cur_tv != NULL); - if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE( - TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, cur_tv, copyID, objname) - == FAIL) { + if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE(TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, + cur_tv, copyID, objname) == FAIL) { goto encode_vim_to__error_ret; } } -- cgit From 759e736b0ab03034dc61d6a30e1b8b1f17ed9695 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 25 Dec 2016 23:29:35 +0300 Subject: eval/typval_encode: Fix infinite loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Occurs when trying to dump a partial with attached self dictionary which references that partial. “Infinite” loop should normally result in Neovim killed by OOM killer. Also moved the place when partials are unreferenced by clear_tv: from …FUNC_START to …FUNC_END. --- src/nvim/eval/typval_encode.c.h | 96 ++++++++++++++++++++++++++++++++--------- src/nvim/eval/typval_encode.h | 22 +++++++--- 2 files changed, 92 insertions(+), 26 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index 597fd71030..95dc227450 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -166,7 +166,8 @@ /// /// After including this file it will define function /// `encode_vim_to_{TYPVAL_ENCODE_NAME}` with scope #TYPVAL_ENCODE_SCOPE and -/// static function `_{TYPVAL_ENCODE_NAME}_convert_one_value`. +/// static functions `_typval_encode_{TYPVAL_ENCODE_NAME}_convert_one_value` and +/// `_typval_encode_{TYPVAL_ENCODE_NAME}_check_self_reference`. /// @def TYPVAL_ENCODE_FIRST_ARG_TYPE /// @brief Type of the first argument, which will be used to return the results @@ -192,11 +193,50 @@ #include "nvim/func_attr.h" #include "nvim/eval/typval_encode.h" +static inline int _TYPVAL_ENCODE_CHECK_SELF_REFERENCE( + TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME, + void *const val, int *const val_copyID, + const MPConvStack *const mpstack, const int copyID, + const MPConvStackValType conv_type, + const char *const objname) + REAL_FATTR_NONNULL_ARG(2, 3, 4, 7) REAL_FATTR_WARN_UNUSED_RESULT + REAL_FATTR_ALWAYS_INLINE; + +/// Function for checking whether container references itself +/// +/// @param TYPVAL_ENCODE_FIRST_ARG_NAME First argument. +/// @param[in,out] val Container to check. +/// @param val_copyID Pointer to the container attribute that holds copyID. +/// After checking whether value of this attribute is +/// copyID (variable) it is set to copyID. +/// @param[in] mpstack Stack with values to convert. Read-only, used for error +/// reporting. +/// @param[in] copyID CopyID used by the caller. +/// @param[in] conv_type Type of the conversion, @see MPConvStackValType. +/// @param[in] objname Object name, used for error reporting. +/// +/// @return NOTDONE in case of success, what to return in case of failure. +static inline int _TYPVAL_ENCODE_CHECK_SELF_REFERENCE( + TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME, + void *const val, int *const val_copyID, + const MPConvStack *const mpstack, const int copyID, + const MPConvStackValType conv_type, + const char *const objname) +{ + if (*val_copyID == copyID) { + TYPVAL_ENCODE_CONV_RECURSE(val, conv_type); + return OK; + } + *val_copyID = copyID; + return NOTDONE; +} + static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME, - MPConvStack *const mpstack, typval_T *const tv, const int copyID, + MPConvStack *const mpstack, MPConvStackVal *const cur_mpsv, + typval_T *const tv, const int copyID, const char *const objname) - REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; + REAL_FATTR_NONNULL_ARG(2, 4, 6) REAL_FATTR_WARN_UNUSED_RESULT; /// Convert single value /// @@ -206,9 +246,10 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( /// @param TYPVAL_ENCODE_FIRST_ARG_NAME First argument, defined by the /// includer. Only meaningful to macros /// defined by the includer. -/// @param[out] mpstack Stack with values to convert. Values which are not -/// converted completely by this function (i.e. -/// non-scalars) are pushed here. +/// @param mpstack Stack with values to convert. Values which are not +/// converted completely by this function (i.e. +/// non-scalars) are pushed here. +/// @param cur_mpsv Currently converted value from stack. /// @param tv Converted value. /// @param[in] copyID CopyID. /// @param[in] objname Object name, used for error reporting. @@ -216,7 +257,8 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( /// @return OK in case of success, FAIL in case of failure. static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME, - MPConvStack *const mpstack, typval_T *const tv, const int copyID, + MPConvStack *const mpstack, MPConvStackVal *const cur_mpsv, + typval_T *const tv, const int copyID, const char *const objname) { switch (tv->v_type) { @@ -260,8 +302,8 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( TYPVAL_ENCODE_CONV_EMPTY_LIST(); break; } - _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, copyID, - kMPConvList); + _TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, copyID, + kMPConvList); TYPVAL_ENCODE_CONV_LIST_START(tv->vval.v_list->lv_len); _mp_push(*mpstack, ((MPConvStackVal) { .type = kMPConvList, @@ -392,8 +434,9 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( if (val_di->di_tv.v_type != VAR_LIST) { goto _convert_one_value_regular_dict; } - _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, - lv_copyID, copyID, kMPConvList); + _TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, + lv_copyID, copyID, + kMPConvList); TYPVAL_ENCODE_CONV_LIST_START(val_di->di_tv.vval.v_list->lv_len); _mp_push(*mpstack, ((MPConvStackVal) { .tv = tv, @@ -423,8 +466,8 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( goto _convert_one_value_regular_dict; } } - _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_list, lv_copyID, copyID, - kMPConvPairs); + _TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(val_list, lv_copyID, copyID, + kMPConvPairs); TYPVAL_ENCODE_CONV_DICT_START(val_list->lv_len); _mp_push(*mpstack, ((MPConvStackVal) { .tv = tv, @@ -464,8 +507,8 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( break; } _convert_one_value_regular_dict: - _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, copyID, - kMPConvDict); + _TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, copyID, + kMPConvDict); TYPVAL_ENCODE_CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); _mp_push(*mpstack, ((MPConvStackVal) { .tv = tv, @@ -491,7 +534,7 @@ _convert_one_value_regular_dict: TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME, typval_T *const tv, const char *const objname) - REAL_FATTR_WARN_UNUSED_RESULT; + REAL_FATTR_NONNULL_ARG(2, 3) REAL_FATTR_WARN_UNUSED_RESULT; /// Convert the whole typval /// @@ -510,6 +553,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( MPConvStack mpstack; _mp_init(mpstack); if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE(TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, + NULL, tv, copyID, objname) == FAIL) { goto encode_vim_to__error_ret; @@ -566,7 +610,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK( encode_vim_to__error_ret, kv_pair->lv_first->li_tv); if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE(TYPVAL_ENCODE_FIRST_ARG_NAME, - &mpstack, + &mpstack, cur_mpsv, &kv_pair->lv_first->li_tv, copyID, objname) == FAIL) { @@ -587,7 +631,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( TYPVAL_ENCODE_CONV_LIST_START(pt->pt_argc); _mp_push(mpstack, ((MPConvStackVal) { .type = kMPConvPartialList, - .tv = tv, + .tv = NULL, .data = { .a = { .arg = pt->pt_argv, @@ -604,10 +648,21 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( dict_T *const dict = pt == NULL ? NULL : pt->pt_dict; if (dict != NULL) { TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(dict->dv_hashtab.ht_used); + const int te_csr_ret = _TYPVAL_ENCODE_CHECK_SELF_REFERENCE( + TYPVAL_ENCODE_FIRST_ARG_NAME, + dict, &dict->dv_copyID, &mpstack, copyID, kMPConvDict, + objname); + if (te_csr_ret != NOTDONE) { + if (te_csr_ret == FAIL) { + goto encode_vim_to__error_ret; + } else { + continue; + } + } TYPVAL_ENCODE_CONV_DICT_START(dict->dv_hashtab.ht_used); _mp_push(mpstack, ((MPConvStackVal) { .type = kMPConvDict, - .tv = tv, + .tv = NULL, .data = { .d = { .dict = dict, @@ -644,7 +699,8 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( } assert(cur_tv != NULL); if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE(TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, - cur_tv, copyID, objname) == FAIL) { + cur_mpsv, cur_tv, copyID, objname) + == FAIL) { goto encode_vim_to__error_ret; } } diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h index 8fb37de93e..9208cdc752 100644 --- a/src/nvim/eval/typval_encode.h +++ b/src/nvim/eval/typval_encode.h @@ -249,16 +249,26 @@ static inline size_t tv_strlen(const typval_T *const tv) /// 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_CHECK_SELF_REFERENCE(val, copyID_attr, copyID, \ - conv_type) \ +#define _TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(val, copyID_attr, copyID, \ + conv_type) \ do { \ - if ((val)->copyID_attr == (copyID)) { \ - TYPVAL_ENCODE_CONV_RECURSE((val), conv_type); \ - return OK; \ + 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; \ } \ - (val)->copyID_attr = (copyID); \ } 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) -- cgit From 67b53361bacf1f14951f0b8c2419dbdb99b19459 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 3 Jan 2017 04:29:25 +0300 Subject: eval/typval_encode: Rename some \*tv variables Renames `tv` function argument to `top_tv` and `cur_tv` variable to `tv`, so `tv` will mean something more or less the same in both _TYPVAL_ENCODE_CONVERT_ONE_VALUE and _TYPVAL_ENCODE_ENCODE functions. --- src/nvim/eval/typval_encode.c.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index 95dc227450..5c807bb169 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -541,26 +541,26 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( /// @param TYPVAL_ENCODE_FIRST_ARG_NAME First argument, defined by the /// includer. Only meaningful to macros /// defined by the includer. -/// @param tv Converted value. +/// @param top_tv Converted value. /// @param[in] objname Object name, used for error reporting. /// /// @return OK in case of success, FAIL in case of failure. TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME, - typval_T *const tv, const char *const objname) + typval_T *const top_tv, const char *const objname) { const int copyID = get_copyID(); MPConvStack mpstack; _mp_init(mpstack); if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE(TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, NULL, - tv, copyID, objname) + top_tv, copyID, objname) == FAIL) { goto encode_vim_to__error_ret; } while (_mp_size(mpstack)) { MPConvStackVal *cur_mpsv = &_mp_last(mpstack); - typval_T *cur_tv = NULL; + typval_T *tv = NULL; switch (cur_mpsv->type) { case kMPConvDict: { if (!cur_mpsv->data.d.todo) { @@ -581,7 +581,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( 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; + tv = &di->di_tv; break; } case kMPConvList: { @@ -593,7 +593,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( } 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; + tv = &cur_mpsv->data.l.li->li_tv; cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; break; } @@ -617,7 +617,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( goto encode_vim_to__error_ret; } TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(); - cur_tv = &kv_pair->lv_last->li_tv; + tv = &kv_pair->lv_last->li_tv; cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; break; } @@ -692,14 +692,14 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( } else if (cur_mpsv->data.a.argv != cur_mpsv->data.a.arg) { TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(); } - cur_tv = cur_mpsv->data.a.arg++; + tv = cur_mpsv->data.a.arg++; cur_mpsv->data.a.todo--; break; } } - assert(cur_tv != NULL); + assert(tv != NULL); if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE(TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, - cur_mpsv, cur_tv, copyID, objname) + cur_mpsv, tv, copyID, objname) == FAIL) { goto encode_vim_to__error_ret; } -- cgit From ff8944105d50f34ca114c4ebeaee6df8cb029dd5 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 3 Jan 2017 06:35:32 +0300 Subject: eval/typval_encode: Refactor arguments to argument macroses Fixed local test failures somewhere in process. --- src/nvim/eval/encode.c | 116 ++++++++++++++-------------- src/nvim/eval/typval_encode.c.h | 165 +++++++++++++++++++++++++--------------- src/nvim/eval/typval_encode.h | 9 +++ 3 files changed, 171 insertions(+), 119 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index 38f0863195..73133b7b29 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -280,7 +280,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, : OK); } -#define TYPVAL_ENCODE_CONV_STRING(buf, len) \ +#define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \ do { \ const char *const buf_ = (const char *) buf; \ if (buf == NULL) { \ @@ -299,19 +299,19 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, } \ } while (0) -#define TYPVAL_ENCODE_CONV_STR_STRING(buf, len) \ - TYPVAL_ENCODE_CONV_STRING(buf, len) +#define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len) \ + TYPVAL_ENCODE_CONV_STRING(tv, buf, len) -#define TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type) +#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type) -#define TYPVAL_ENCODE_CONV_NUMBER(num) \ +#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ do { \ char numbuf[NUMBUFLEN]; \ vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%" PRId64, (int64_t) (num)); \ ga_concat(gap, numbuf); \ } while (0) -#define TYPVAL_ENCODE_CONV_FLOAT(flt) \ +#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ do { \ const float_T flt_ = (flt); \ switch (fpclassify(flt_)) { \ @@ -334,65 +334,65 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, } \ } while (0) -#define TYPVAL_ENCODE_CONV_FUNC_START(fun, is_partial, pt) \ +#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ do { \ ga_concat(gap, "function("); \ - TYPVAL_ENCODE_CONV_STRING(fun, STRLEN(fun)); \ + TYPVAL_ENCODE_CONV_STRING(tv, fun, STRLEN(fun)); \ } while (0) -#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(len) \ +#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len) \ do { \ if (len != 0) { \ ga_concat(gap, ", "); \ } \ } while (0) -#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(len) \ +#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len) \ do { \ if ((ptrdiff_t)len != -1) { \ ga_concat(gap, ", "); \ } \ } while (0) -#define TYPVAL_ENCODE_CONV_FUNC_END() \ +#define TYPVAL_ENCODE_CONV_FUNC_END(tv) \ ga_append(gap, ')') -#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \ +#define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \ ga_concat(gap, "[]") -#define TYPVAL_ENCODE_CONV_LIST_START(len) \ +#define TYPVAL_ENCODE_CONV_LIST_START(tv, dict) \ ga_append(gap, '[') -#define TYPVAL_ENCODE_CONV_EMPTY_DICT() \ +#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv) \ ga_concat(gap, "{}") -#define TYPVAL_ENCODE_CONV_NIL() \ +#define TYPVAL_ENCODE_CONV_NIL(tv) \ ga_concat(gap, "v:null") -#define TYPVAL_ENCODE_CONV_BOOL(num) \ +#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ ga_concat(gap, ((num)? "v:true": "v:false")) -#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(num) +#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num) -#define TYPVAL_ENCODE_CONV_DICT_START(len) \ +#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \ ga_append(gap, '{') -#define TYPVAL_ENCODE_CONV_DICT_END() \ +#define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \ ga_append(gap, '}') -#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY() \ +#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict) \ ga_concat(gap, ": ") -#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS() \ +#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) \ ga_concat(gap, ", ") -#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, key) +#define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(label, key) -#define TYPVAL_ENCODE_CONV_LIST_END() \ +#define TYPVAL_ENCODE_CONV_LIST_END(tv) \ ga_append(gap, ']') -#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS() \ - TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS() +#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) \ + TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, NULL) #define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ do { \ @@ -493,15 +493,15 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, #define TYPVAL_ENCODE_ALLOW_SPECIALS true #undef TYPVAL_ENCODE_CONV_NIL -#define TYPVAL_ENCODE_CONV_NIL() \ +#define TYPVAL_ENCODE_CONV_NIL(tv) \ ga_concat(gap, "null") #undef TYPVAL_ENCODE_CONV_BOOL -#define TYPVAL_ENCODE_CONV_BOOL(num) \ +#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ ga_concat(gap, ((num)? "true": "false")) #undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER -#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(num) \ +#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num) \ do { \ char numbuf[NUMBUFLEN]; \ vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%" PRIu64, (num)); \ @@ -509,7 +509,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, } while (0) #undef TYPVAL_ENCODE_CONV_FLOAT -#define TYPVAL_ENCODE_CONV_FLOAT(flt) \ +#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ do { \ const float_T flt_ = (flt); \ switch (fpclassify(flt_)) { \ @@ -698,7 +698,7 @@ static inline int convert_to_json_string(garray_T *const gap, } #undef TYPVAL_ENCODE_CONV_STRING -#define TYPVAL_ENCODE_CONV_STRING(buf, len) \ +#define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \ do { \ if (convert_to_json_string(gap, (const char *) (buf), (len)) != OK) { \ return FAIL; \ @@ -706,7 +706,7 @@ static inline int convert_to_json_string(garray_T *const gap, } while (0) #undef TYPVAL_ENCODE_CONV_EXT_STRING -#define TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type) \ +#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type) \ do { \ xfree(buf); \ EMSG(_("E474: Unable to convert EXT string to JSON")); \ @@ -714,7 +714,7 @@ static inline int convert_to_json_string(garray_T *const gap, } while (0) #undef TYPVAL_ENCODE_CONV_FUNC_START -#define TYPVAL_ENCODE_CONV_FUNC_START(fun, is_partial, pt) \ +#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ return conv_error(_("E474: Error while dumping %s, %s: " \ "attempt to dump function reference"), \ mpstack, objname) @@ -757,8 +757,8 @@ bool encode_check_json_key(const typval_T *const tv) return true; } -#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK -#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, key) \ +#undef TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK +#define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(label, key) \ do { \ if (!encode_check_json_key(&key)) { \ EMSG(_("E474: Invalid key in special dictionary")); \ @@ -797,7 +797,7 @@ bool encode_check_json_key(const typval_T *const tv) #undef TYPVAL_ENCODE_CONV_DICT_END #undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY #undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS -#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK +#undef TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK #undef TYPVAL_ENCODE_CONV_LIST_END #undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS #undef TYPVAL_ENCODE_CONV_RECURSE @@ -875,7 +875,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) return (char *) ga.ga_data; } -#define TYPVAL_ENCODE_CONV_STRING(buf, len) \ +#define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \ do { \ if (buf == NULL) { \ msgpack_pack_bin(packer, 0); \ @@ -886,7 +886,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) } \ } while (0) -#define TYPVAL_ENCODE_CONV_STR_STRING(buf, len) \ +#define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len) \ do { \ if (buf == NULL) { \ msgpack_pack_str(packer, 0); \ @@ -897,7 +897,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) } \ } while (0) -#define TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type) \ +#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type) \ do { \ if (buf == NULL) { \ msgpack_pack_ext(packer, 0, (int8_t) type); \ @@ -908,34 +908,34 @@ char *encode_tv2json(typval_T *tv, size_t *len) } \ } while (0) -#define TYPVAL_ENCODE_CONV_NUMBER(num) \ +#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ msgpack_pack_int64(packer, (int64_t) (num)) -#define TYPVAL_ENCODE_CONV_FLOAT(flt) \ +#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ msgpack_pack_double(packer, (double) (flt)) -#define TYPVAL_ENCODE_CONV_FUNC_START(fun, is_partial, pt) \ +#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ return conv_error(_("E5004: Error while dumping %s, %s: " \ "attempt to dump function reference"), \ mpstack, objname) -#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(len) -#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(len) -#define TYPVAL_ENCODE_CONV_FUNC_END() +#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len) +#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len) +#define TYPVAL_ENCODE_CONV_FUNC_END(tv) -#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \ +#define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \ msgpack_pack_array(packer, 0) -#define TYPVAL_ENCODE_CONV_LIST_START(len) \ +#define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ msgpack_pack_array(packer, (size_t) (len)) -#define TYPVAL_ENCODE_CONV_EMPTY_DICT() \ +#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv) \ msgpack_pack_map(packer, 0) -#define TYPVAL_ENCODE_CONV_NIL() \ +#define TYPVAL_ENCODE_CONV_NIL(tv) \ msgpack_pack_nil(packer) -#define TYPVAL_ENCODE_CONV_BOOL(num) \ +#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ do { \ if ((num)) { \ msgpack_pack_true(packer); \ @@ -944,23 +944,23 @@ char *encode_tv2json(typval_T *tv, size_t *len) } \ } while (0) -#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(num) \ +#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num) \ msgpack_pack_uint64(packer, (num)) -#define TYPVAL_ENCODE_CONV_DICT_START(len) \ +#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \ msgpack_pack_map(packer, (size_t) (len)) -#define TYPVAL_ENCODE_CONV_DICT_END() +#define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) -#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY() +#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict) -#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS() +#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) -#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, key) +#define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(label, key) -#define TYPVAL_ENCODE_CONV_LIST_END() +#define TYPVAL_ENCODE_CONV_LIST_END(tv) -#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS() +#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) #define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ return conv_error(_("E5005: Unable to dump %s: " \ @@ -1000,7 +1000,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) #undef TYPVAL_ENCODE_CONV_DICT_END #undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY #undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS -#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK +#undef TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK #undef TYPVAL_ENCODE_CONV_LIST_END #undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS #undef TYPVAL_ENCODE_CONV_RECURSE diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index 5c807bb169..8caffaf7f5 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -8,8 +8,10 @@ /// @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. +/// is false) and `v:null`. +/// +/// @param tv Pointer to typval where value is stored. May not be NULL. May +/// point to special dictionary. /// @def TYPVAL_ENCODE_CONV_BOOL /// @brief Macros used to convert boolean value @@ -17,12 +19,16 @@ /// Is called both for special dictionary (unless #TYPVAL_ENCODE_ALLOW_SPECIALS /// is false) and `v:true`/`v:false`. /// +/// @param tv Pointer to typval where value is stored. May not be NULL. May +/// point to a special dictionary. /// @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 tv Pointer to typval where value is stored. May not be NULL. May +/// point to a special dictionary. /// @param num Integer to convert, must accept both varnumber_T and int64_t. /// @def TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER @@ -31,11 +37,15 @@ /// Not used if #TYPVAL_ENCODE_ALLOW_SPECIALS is false, but still must be /// defined. /// +/// @param tv Pointer to typval where value is stored. May not be NULL. Points +/// to a special dictionary. /// @param num Integer to convert, must accept uint64_t. /// @def TYPVAL_ENCODE_CONV_FLOAT /// @brief Macros used to convert floating-point number /// +/// @param tv Pointer to typval where value is stored. May not be NULL. May +/// point to a special dictionary. /// @param flt Number to convert, must accept float_T. /// @def TYPVAL_ENCODE_CONV_STRING @@ -44,6 +54,8 @@ /// Is used to convert VAR_STRING objects as well as BIN strings represented as /// special dictionary. /// +/// @param tv Pointer to typval where value is stored. May not be NULL. May +/// point to a special dictionary. /// @param buf String to convert. Is a char[] buffer, not NUL-terminated. /// @param len String length. @@ -52,6 +64,11 @@ /// /// Is used to convert dictionary keys and STR strings represented as special /// dictionaries. +/// +/// @param tv Pointer to typval where value is stored. May be NULL. May +/// point to a special dictionary. +/// @param buf String to convert. Is a char[] buffer, not NUL-terminated. +/// @param len String length. /// @def TYPVAL_ENCODE_CONV_EXT_STRING /// @brief Macros used to convert EXT string @@ -60,31 +77,29 @@ /// actually used if #TYPVAL_ENCODE_ALLOW_SPECIALS is false, but still must be /// defined. /// +/// @param tv Pointer to typval where value is stored. May not be NULL. Points +/// to a special dictionary. /// @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_FUNC_START /// @brief Macros used when starting to convert a funcref or a partial /// +/// @param tv Pointer to typval where value is stored. May not be NULL. /// @param fun Function name. -/// @param is_partial True if converted function is a partial. -/// @param pt Pointer to partial or NULL. /// @def TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS /// @brief Macros used before starting to convert partial arguments /// +/// @param tv Pointer to typval where value is stored. May not be NULL. /// @param len Number of arguments. Zero for absent arguments or when /// converting a funcref. /// @def TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF /// @brief Macros used before starting to convert self dictionary /// +/// @param tv Pointer to typval where value is stored. May not be NULL. /// @param len Number of arguments. May be zero for empty dictionary or -1 for /// missing self dictionary, also when converting function /// reference. @@ -92,40 +107,47 @@ /// @def TYPVAL_ENCODE_CONV_FUNC_END /// @brief Macros used after converting a funcref or a partial /// -/// Accepts no arguments, but still must be a function-like macros. +/// @param tv Pointer to typval where value is stored. May not be NULL. /// @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. +/// @param tv Pointer to typval where value is stored. May not be NULL. /// @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. +/// @param tv Pointer to typval where value is stored. May not be NULL. May +/// point to a special dictionary. /// @def TYPVAL_ENCODE_CONV_LIST_START /// @brief Macros used before starting to convert non-empty list /// +/// @param tv Pointer to typval where value is stored. May be NULL. May +/// point to a special dictionary. /// @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. +/// @param tv Pointer to typval where list is stored. May be NULL. /// @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. +/// @param tv Pointer to typval where list is stored. May be NULL. /// @def TYPVAL_ENCODE_CONV_DICT_START /// @brief Macros used before starting to convert non-empty dictionary /// +/// @param tv Pointer to typval where dictionary is stored. May be NULL. May +/// point to a special dictionary. +/// @param dict Converted dictionary, lvalue or &#TYPVAL_ENCODE_NODICT_VAR +/// (for dictionaries represented as special lists). /// @param len Dictionary length. Is an expression which evaluates to an /// integer. -/// @def TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK +/// @def TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK /// @brief Macros used to check special dictionary key /// /// @param label Label for goto in case check was not successfull. @@ -134,17 +156,26 @@ /// @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. +/// @param tv Pointer to typval where dictionary is stored. May be NULL. May +/// point to a special dictionary. +/// @param dict Converted dictionary, lvalue or &#TYPVAL_ENCODE_NODICT_VAR +/// (for dictionaries represented as special lists). /// @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. +/// @param tv Pointer to typval where dictionary is stored. May be NULL. May +/// point to a special dictionary. +/// @param dict Converted dictionary, lvalue or &#TYPVAL_ENCODE_NODICT_VAR +/// (for dictionaries represented as special lists). /// @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. +/// @param tv Pointer to typval where dictionary is stored. May be NULL. May +/// point to a special dictionary. +/// @param dict Converted dictionary, lvalue or &#TYPVAL_ENCODE_NODICT_VAR +/// (for dictionaries represented as special lists). /// @def TYPVAL_ENCODE_CONV_RECURSE /// @brief Macros used when self-containing container is detected @@ -193,6 +224,8 @@ #include "nvim/func_attr.h" #include "nvim/eval/typval_encode.h" +const dict_T *const TYPVAL_ENCODE_NODICT_VAR = NULL; + static inline int _TYPVAL_ENCODE_CHECK_SELF_REFERENCE( TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME, void *const val, int *const val_copyID, @@ -263,28 +296,28 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( { switch (tv->v_type) { case VAR_STRING: { - TYPVAL_ENCODE_CONV_STRING(tv->vval.v_string, tv_strlen(tv)); + TYPVAL_ENCODE_CONV_STRING(tv, tv->vval.v_string, tv_strlen(tv)); break; } case VAR_NUMBER: { - TYPVAL_ENCODE_CONV_NUMBER(tv->vval.v_number); + TYPVAL_ENCODE_CONV_NUMBER(tv, tv->vval.v_number); break; } case VAR_FLOAT: { - TYPVAL_ENCODE_CONV_FLOAT(tv->vval.v_float); + TYPVAL_ENCODE_CONV_FLOAT(tv, tv->vval.v_float); break; } case VAR_FUNC: { - TYPVAL_ENCODE_CONV_FUNC_START(tv->vval.v_string, false, NULL); - TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(0); - TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(-1); - TYPVAL_ENCODE_CONV_FUNC_END(); + TYPVAL_ENCODE_CONV_FUNC_START(tv, tv->vval.v_string); + TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, 0); + TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, -1); + TYPVAL_ENCODE_CONV_FUNC_END(tv); break; } case VAR_PARTIAL: { partial_T *const pt = tv->vval.v_partial; (void)pt; - TYPVAL_ENCODE_CONV_FUNC_START(pt->pt_name, true, pt); + TYPVAL_ENCODE_CONV_FUNC_START(tv, pt->pt_name); _mp_push(*mpstack, ((MPConvStackVal) { .type = kMPConvPartial, .tv = tv, @@ -299,12 +332,12 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( } case VAR_LIST: { if (tv->vval.v_list == NULL || tv->vval.v_list->lv_len == 0) { - TYPVAL_ENCODE_CONV_EMPTY_LIST(); + TYPVAL_ENCODE_CONV_EMPTY_LIST(tv); break; } _TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, copyID, kMPConvList); - TYPVAL_ENCODE_CONV_LIST_START(tv->vval.v_list->lv_len); + TYPVAL_ENCODE_CONV_LIST_START(tv, tv->vval.v_list->lv_len); _mp_push(*mpstack, ((MPConvStackVal) { .type = kMPConvList, .tv = tv, @@ -320,12 +353,12 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( case VAR_SPECIAL: { switch (tv->vval.v_special) { case kSpecialVarNull: { - TYPVAL_ENCODE_CONV_NIL(); + TYPVAL_ENCODE_CONV_NIL(tv); break; } case kSpecialVarTrue: case kSpecialVarFalse: { - TYPVAL_ENCODE_CONV_BOOL(tv->vval.v_special == kSpecialVarTrue); + TYPVAL_ENCODE_CONV_BOOL(tv, tv->vval.v_special == kSpecialVarTrue); break; } } @@ -334,7 +367,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( case VAR_DICT: { if (tv->vval.v_dict == NULL || tv->vval.v_dict->dv_hashtab.ht_used == 0) { - TYPVAL_ENCODE_CONV_EMPTY_DICT(); + TYPVAL_ENCODE_CONV_EMPTY_DICT(tv); break; } const dictitem_T *type_di; @@ -357,14 +390,14 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( } switch ((MessagePackType)i) { case kMPNil: { - TYPVAL_ENCODE_CONV_NIL(); + TYPVAL_ENCODE_CONV_NIL(tv); break; } case kMPBoolean: { if (val_di->di_tv.v_type != VAR_NUMBER) { goto _convert_one_value_regular_dict; } - TYPVAL_ENCODE_CONV_BOOL(val_di->di_tv.vval.v_number); + TYPVAL_ENCODE_CONV_BOOL(tv, val_di->di_tv.vval.v_number); break; } case kMPInteger: { @@ -397,9 +430,9 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( | (uint64_t)(((uint64_t)high_bits) << 31) | (uint64_t)low_bits); if (sign > 0) { - TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(number); + TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, number); } else { - TYPVAL_ENCODE_CONV_NUMBER(-number); + TYPVAL_ENCODE_CONV_NUMBER(tv, -number); } break; } @@ -407,7 +440,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( if (val_di->di_tv.v_type != VAR_FLOAT) { goto _convert_one_value_regular_dict; } - TYPVAL_ENCODE_CONV_FLOAT(val_di->di_tv.vval.v_float); + TYPVAL_ENCODE_CONV_FLOAT(tv, val_di->di_tv.vval.v_float); break; } case kMPString: @@ -423,9 +456,9 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( goto _convert_one_value_regular_dict; } if (is_string) { - TYPVAL_ENCODE_CONV_STR_STRING(buf, len); + TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len); } else { - TYPVAL_ENCODE_CONV_STRING(buf, len); + TYPVAL_ENCODE_CONV_STRING(tv, buf, len); } xfree(buf); break; @@ -437,7 +470,8 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( _TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, lv_copyID, copyID, kMPConvList); - TYPVAL_ENCODE_CONV_LIST_START(val_di->di_tv.vval.v_list->lv_len); + TYPVAL_ENCODE_CONV_LIST_START(tv, + val_di->di_tv.vval.v_list->lv_len); _mp_push(*mpstack, ((MPConvStackVal) { .tv = tv, .type = kMPConvList, @@ -456,7 +490,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( } 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(); + TYPVAL_ENCODE_CONV_EMPTY_DICT(tv); break; } for (const listitem_T *li = val_list->lv_first; li != NULL; @@ -468,7 +502,8 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( } _TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(val_list, lv_copyID, copyID, kMPConvPairs); - TYPVAL_ENCODE_CONV_DICT_START(val_list->lv_len); + TYPVAL_ENCODE_CONV_DICT_START(tv, TYPVAL_ENCODE_NODICT_VAR, + val_list->lv_len); _mp_push(*mpstack, ((MPConvStackVal) { .tv = tv, .type = kMPConvPairs, @@ -499,7 +534,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( &len, &buf)) { goto _convert_one_value_regular_dict; } - TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type); + TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type); xfree(buf); break; } @@ -509,7 +544,8 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( _convert_one_value_regular_dict: _TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, copyID, kMPConvDict); - TYPVAL_ENCODE_CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); + TYPVAL_ENCODE_CONV_DICT_START(tv, tv->vval.v_dict, + tv->vval.v_dict->dv_hashtab.ht_used); _mp_push(*mpstack, ((MPConvStackVal) { .tv = tv, .type = kMPConvDict, @@ -566,11 +602,12 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( if (!cur_mpsv->data.d.todo) { (void)_mp_pop(mpstack); cur_mpsv->data.d.dict->dv_copyID = copyID - 1; - TYPVAL_ENCODE_CONV_DICT_END(); + TYPVAL_ENCODE_CONV_DICT_END(cur_mpsv->tv, cur_mpsv->tv->vval.v_dict); continue; } else if (cur_mpsv->data.d.todo != cur_mpsv->data.d.dict->dv_hashtab.ht_used) { - TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(); + TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(cur_mpsv->tv, + cur_mpsv->tv->vval.v_dict); } while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) { cur_mpsv->data.d.hi++; @@ -578,9 +615,10 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( 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], + TYPVAL_ENCODE_CONV_STR_STRING(NULL, &di->di_key[0], strlen((char *)&di->di_key[0])); - TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(); + TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(cur_mpsv->tv, + cur_mpsv->tv->vval.v_dict); tv = &di->di_tv; break; } @@ -588,10 +626,10 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( 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(); + TYPVAL_ENCODE_CONV_LIST_END(cur_mpsv->tv); continue; } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { - TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(); + TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(cur_mpsv->tv); } tv = &cur_mpsv->data.l.li->li_tv; cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; @@ -601,13 +639,14 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( 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(); + TYPVAL_ENCODE_CONV_DICT_END(cur_mpsv->tv, TYPVAL_ENCODE_NODICT_VAR); continue; } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { - TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(); + TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS( + cur_mpsv->tv, TYPVAL_ENCODE_NODICT_VAR); } 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_SPECIAL_DICT_KEY_CHECK( encode_vim_to__error_ret, kv_pair->lv_first->li_tv); if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE(TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, cur_mpsv, @@ -616,19 +655,22 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( objname) == FAIL) { goto encode_vim_to__error_ret; } - TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(); + TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(cur_mpsv->tv, + TYPVAL_ENCODE_NODICT_VAR); tv = &kv_pair->lv_last->li_tv; cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; break; } case kMPConvPartial: { partial_T *const pt = cur_mpsv->data.p.pt; + tv = cur_mpsv->tv; switch (cur_mpsv->data.p.stage) { case kMPConvPartialArgs: { - TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(pt == NULL ? 0 : pt->pt_argc); + TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, + pt == NULL ? 0 : pt->pt_argc); cur_mpsv->data.p.stage = kMPConvPartialSelf; if (pt != NULL && pt->pt_argc > 0) { - TYPVAL_ENCODE_CONV_LIST_START(pt->pt_argc); + TYPVAL_ENCODE_CONV_LIST_START(NULL, pt->pt_argc); _mp_push(mpstack, ((MPConvStackVal) { .type = kMPConvPartialList, .tv = NULL, @@ -647,7 +689,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( cur_mpsv->data.p.stage = kMPConvPartialEnd; dict_T *const dict = pt == NULL ? NULL : pt->pt_dict; if (dict != NULL) { - TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(dict->dv_hashtab.ht_used); + TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, dict->dv_hashtab.ht_used); const int te_csr_ret = _TYPVAL_ENCODE_CHECK_SELF_REFERENCE( TYPVAL_ENCODE_FIRST_ARG_NAME, dict, &dict->dv_copyID, &mpstack, copyID, kMPConvDict, @@ -659,7 +701,8 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( continue; } } - TYPVAL_ENCODE_CONV_DICT_START(dict->dv_hashtab.ht_used); + TYPVAL_ENCODE_CONV_DICT_START(NULL, pt->pt_dict, + dict->dv_hashtab.ht_used); _mp_push(mpstack, ((MPConvStackVal) { .type = kMPConvDict, .tv = NULL, @@ -672,12 +715,12 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( }, })); } else { - TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(-1); + TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, -1); } break; } case kMPConvPartialEnd: { - TYPVAL_ENCODE_CONV_FUNC_END(); + TYPVAL_ENCODE_CONV_FUNC_END(tv); (void)_mp_pop(mpstack); break; } @@ -687,10 +730,10 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( case kMPConvPartialList: { if (!cur_mpsv->data.a.todo) { (void)_mp_pop(mpstack); - TYPVAL_ENCODE_CONV_LIST_END(); + TYPVAL_ENCODE_CONV_LIST_END(NULL); continue; } else if (cur_mpsv->data.a.argv != cur_mpsv->data.a.arg) { - TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(); + TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(NULL); } tv = cur_mpsv->data.a.arg++; cur_mpsv->data.a.todo--; diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h index 9208cdc752..5813059cda 100644 --- a/src/nvim/eval/typval_encode.h +++ b/src/nvim/eval/typval_encode.h @@ -284,4 +284,13 @@ static inline size_t tv_strlen(const typval_T *const tv) #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 -- cgit From a52238707c5438fb3aaa945ebb550cdbd8660cf3 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 3 Jan 2017 06:36:58 +0300 Subject: eval/encode: Fix 4 new linter failures --- src/nvim/eval/encode.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index 73133b7b29..ef1e77459a 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -909,10 +909,10 @@ char *encode_tv2json(typval_T *tv, size_t *len) } while (0) #define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ - msgpack_pack_int64(packer, (int64_t) (num)) + msgpack_pack_int64(packer, (int64_t)(num)) #define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ - msgpack_pack_double(packer, (double) (flt)) + msgpack_pack_double(packer, (double)(flt)) #define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ return conv_error(_("E5004: Error while dumping %s, %s: " \ @@ -927,7 +927,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) msgpack_pack_array(packer, 0) #define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ - msgpack_pack_array(packer, (size_t) (len)) + msgpack_pack_array(packer, (size_t)(len)) #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv) \ msgpack_pack_map(packer, 0) @@ -948,7 +948,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) msgpack_pack_uint64(packer, (num)) #define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \ - msgpack_pack_map(packer, (size_t) (len)) + msgpack_pack_map(packer, (size_t)(len)) #define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) -- cgit From 9c84f3ba3e517b6c6b196387ac50d40daeacf165 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 3 Jan 2017 07:41:05 +0300 Subject: eval/typval_encode: Provide proper values as dict argument --- src/nvim/eval/typval_encode.c.h | 8 +++++--- src/nvim/eval/typval_encode.h | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index 8caffaf7f5..74d0aac083 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -552,6 +552,7 @@ _convert_one_value_regular_dict: .data = { .d = { .dict = tv->vval.v_dict, + .dictp = &tv->vval.v_dict, .hi = tv->vval.v_dict->dv_hashtab.ht_array, .todo = tv->vval.v_dict->dv_hashtab.ht_used, }, @@ -602,12 +603,12 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( if (!cur_mpsv->data.d.todo) { (void)_mp_pop(mpstack); cur_mpsv->data.d.dict->dv_copyID = copyID - 1; - TYPVAL_ENCODE_CONV_DICT_END(cur_mpsv->tv, cur_mpsv->tv->vval.v_dict); + TYPVAL_ENCODE_CONV_DICT_END(cur_mpsv->tv, *cur_mpsv->data.d.dictp); continue; } else if (cur_mpsv->data.d.todo != cur_mpsv->data.d.dict->dv_hashtab.ht_used) { TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(cur_mpsv->tv, - cur_mpsv->tv->vval.v_dict); + *cur_mpsv->data.d.dictp); } while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) { cur_mpsv->data.d.hi++; @@ -618,7 +619,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( TYPVAL_ENCODE_CONV_STR_STRING(NULL, &di->di_key[0], strlen((char *)&di->di_key[0])); TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(cur_mpsv->tv, - cur_mpsv->tv->vval.v_dict); + *cur_mpsv->data.d.dictp); tv = &di->di_tv; break; } @@ -709,6 +710,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( .data = { .d = { .dict = dict, + .dictp = &pt->pt_dict, .hi = dict->dv_hashtab.ht_array, .todo = dict->dv_hashtab.ht_used, }, diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h index 5813059cda..c2629caa39 100644 --- a/src/nvim/eval/typval_encode.h +++ b/src/nvim/eval/typval_encode.h @@ -192,6 +192,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. -- cgit From 06cca5dc59ae3bcfb81796b331a3f882ba1f0ca2 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 3 Jan 2017 07:44:54 +0300 Subject: eval/typval_encode: Handle NULL partials properly --- src/nvim/eval/typval_encode.c.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index 74d0aac083..69f805498a 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -87,7 +87,7 @@ /// @brief Macros used when starting to convert a funcref or a partial /// /// @param tv Pointer to typval where value is stored. May not be NULL. -/// @param fun Function name. +/// @param fun Function name. May be NULL. /// @def TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS /// @brief Macros used before starting to convert partial arguments @@ -317,7 +317,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( case VAR_PARTIAL: { partial_T *const pt = tv->vval.v_partial; (void)pt; - TYPVAL_ENCODE_CONV_FUNC_START(tv, pt->pt_name); + TYPVAL_ENCODE_CONV_FUNC_START(tv, (pt == NULL ? NULL : pt->pt_name)); _mp_push(*mpstack, ((MPConvStackVal) { .type = kMPConvPartial, .tv = tv, -- cgit From f21725946c575884e04e79942850e7d0bc040ef9 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 3 Jan 2017 16:13:21 +0300 Subject: eval/encode: Fail when stringifying NULL functions --- src/nvim/eval/encode.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index ef1e77459a..828bde3124 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -336,8 +336,14 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, #define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ do { \ - ga_concat(gap, "function("); \ - TYPVAL_ENCODE_CONV_STRING(tv, fun, STRLEN(fun)); \ + const char *const fun_ = (const char *)(fun); \ + if (fun_ == NULL) { \ + EMSG2(_(e_intern2), "string(): NULL function name"); \ + ga_concat(gap, "function(NULL"); \ + } else { \ + ga_concat(gap, "function("); \ + TYPVAL_ENCODE_CONV_STRING(tv, fun_, strlen(fun_)); \ + }\ } while (0) #define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len) \ -- cgit From efc624c2fe029a4ab494672c43366e8c57c19108 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 3 Jan 2017 17:28:57 +0300 Subject: eval: Fix errorneous early exit when converting lists and dictionaries --- src/nvim/eval/typval_encode.c.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index 69f805498a..5795d339f0 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -565,7 +565,10 @@ _convert_one_value_regular_dict: return FAIL; } } +typval_encode_stop_converting_one_item: return OK; + // Prevent “unused label” warnings. + goto typval_encode_stop_converting_one_item; } TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( @@ -595,6 +598,9 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( == FAIL) { goto encode_vim_to__error_ret; } +/// Label common for this and convert_one_value functions, used for escaping +/// from macros like TYPVAL_ENCODE_CONV_DICT_START. +typval_encode_stop_converting_one_item: while (_mp_size(mpstack)) { MPConvStackVal *cur_mpsv = &_mp_last(mpstack); typval_T *tv = NULL; @@ -754,5 +760,7 @@ TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE( encode_vim_to__error_ret: _mp_destroy(mpstack); return FAIL; + // Prevent “unused label” warnings. + goto typval_encode_stop_converting_one_item; } #endif // NVIM_EVAL_TYPVAL_ENCODE_C_H -- cgit From 358097ac5fd12bb9bd3beca8ef672f189f313beb Mon Sep 17 00:00:00 2001 From: ZyX Date: Wed, 4 Jan 2017 19:01:04 +0300 Subject: eval/encode: Always check the return value of encode_vim_to_\* --- src/nvim/eval/encode.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index 828bde3124..d11db0296a 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -366,7 +366,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, #define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \ ga_concat(gap, "[]") -#define TYPVAL_ENCODE_CONV_LIST_START(tv, dict) \ +#define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ ga_append(gap, '[') #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv) \ @@ -824,6 +824,7 @@ char *encode_tv2string(typval_T *tv, size_t *len) const int evs_ret = encode_vim_to_string(&ga, tv, "encode_tv2string() argument"); (void)evs_ret; + assert(evs_ret == OK); did_echo_string_emsg = false; if (len != NULL) { *len = (size_t) ga.ga_len; @@ -851,6 +852,7 @@ char *encode_tv2echo(typval_T *tv, size_t *len) } else { const int eve_ret = encode_vim_to_echo(&ga, tv, ":echo argument"); (void)eve_ret; + assert(eve_ret == OK); } if (len != NULL) { *len = (size_t) ga.ga_len; @@ -872,13 +874,15 @@ char *encode_tv2json(typval_T *tv, size_t *len) garray_T ga; ga_init(&ga, (int)sizeof(char), 80); const int evj_ret = encode_vim_to_json(&ga, tv, "encode_tv2json() argument"); - (void)evj_ret; + if (!evj_ret) { + ga_clear(&ga); + } did_echo_string_emsg = false; if (len != NULL) { - *len = (size_t) ga.ga_len; + *len = (size_t)ga.ga_len; } ga_append(&ga, '\0'); - return (char *) ga.ga_data; + return (char *)ga.ga_data; } #define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \ -- cgit From c93ce07628d3e27bfd903743c1248c2f8e45aa2d Mon Sep 17 00:00:00 2001 From: ZyX Date: Wed, 4 Jan 2017 19:04:15 +0300 Subject: *: Remove `// fname()` comments near typval_encode includes --- src/nvim/eval/encode.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index d11db0296a..e3fd857529 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -435,8 +435,6 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, #define TYPVAL_ENCODE_NAME string #define TYPVAL_ENCODE_FIRST_ARG_TYPE garray_T *const #define TYPVAL_ENCODE_FIRST_ARG_NAME gap -// _string_convert_one_value() -// encode_vim_to_string() #include "nvim/eval/typval_encode.c.h" #undef TYPVAL_ENCODE_SCOPE #undef TYPVAL_ENCODE_NAME @@ -475,8 +473,6 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, #define TYPVAL_ENCODE_NAME echo #define TYPVAL_ENCODE_FIRST_ARG_TYPE garray_T *const #define TYPVAL_ENCODE_FIRST_ARG_NAME gap -// _echo_convert_one_value() -// encode_vim_to_echo() #include "nvim/eval/typval_encode.c.h" #undef TYPVAL_ENCODE_SCOPE #undef TYPVAL_ENCODE_NAME @@ -776,8 +772,6 @@ bool encode_check_json_key(const typval_T *const tv) #define TYPVAL_ENCODE_NAME json #define TYPVAL_ENCODE_FIRST_ARG_TYPE garray_T *const #define TYPVAL_ENCODE_FIRST_ARG_NAME gap -// _json_convert_one_value() -// encode_vim_to_json() #include "nvim/eval/typval_encode.c.h" #undef TYPVAL_ENCODE_SCOPE #undef TYPVAL_ENCODE_NAME @@ -983,8 +977,6 @@ char *encode_tv2json(typval_T *tv, size_t *len) #define TYPVAL_ENCODE_NAME msgpack #define TYPVAL_ENCODE_FIRST_ARG_TYPE msgpack_packer *const #define TYPVAL_ENCODE_FIRST_ARG_NAME packer -// _msgpack_convert_one_value() -// encode_vim_to_msgpack() #include "nvim/eval/typval_encode.c.h" #undef TYPVAL_ENCODE_SCOPE #undef TYPVAL_ENCODE_NAME -- cgit From 7f11ec00fd483b70d463de5f7661966ffc10a5d1 Mon Sep 17 00:00:00 2001 From: ZyX Date: Fri, 6 Jan 2017 22:38:46 +0300 Subject: eval/typval_encode.h: Remove documentation that is located in *.c.h --- src/nvim/eval/typval_encode.h | 159 +----------------------------------------- 1 file changed, 2 insertions(+), 157 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h index c2629caa39..6517efa961 100644 --- a/src/nvim/eval/typval_encode.h +++ b/src/nvim/eval/typval_encode.h @@ -1,162 +1,7 @@ /// @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_FUNC_START -/// @brief Macros used when starting to convert a funcref or a partial -/// -/// @param fun Function name. -/// @param is_partial True if converted function is a partial. -/// @param pt Pointer to partial or NULL. - -/// @def TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS -/// @brief Macros used before starting to convert partial arguments -/// -/// @param len Number of arguments. Zero for absent arguments or when -/// converting a funcref. - -/// @def TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF -/// @brief Macros used before starting to convert self dictionary -/// -/// @param len Number of arguments. May be zero for empty dictionary or -1 for -/// missing self dictionary, also when converting function -/// reference. - -/// @def TYPVAL_ENCODE_CONV_FUNC_END -/// @brief Macros used after converting a funcref or a partial -/// -/// Accepts no arguments, but still must be a function-like macros. - -/// @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 -- cgit From 6584fb723ad9fcdc96bbefdf79c638b840bc5655 Mon Sep 17 00:00:00 2001 From: ZyX Date: Fri, 6 Jan 2017 22:48:50 +0300 Subject: eval/typval_encode: Use TYPVAL_ENCODE_CONV_EMPTY_DICT for partials --- src/nvim/eval/encode.c | 4 ++-- src/nvim/eval/typval_encode.c.h | 50 ++++++++++++++++++++++++----------------- 2 files changed, 32 insertions(+), 22 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index e3fd857529..071fbc3923 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -369,7 +369,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, #define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ ga_append(gap, '[') -#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv) \ +#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ ga_concat(gap, "{}") #define TYPVAL_ENCODE_CONV_NIL(tv) \ @@ -933,7 +933,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) #define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ msgpack_pack_array(packer, (size_t)(len)) -#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv) \ +#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ msgpack_pack_map(packer, 0) #define TYPVAL_ENCODE_CONV_NIL(tv) \ diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index 5795d339f0..668bdfb26a 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -117,8 +117,10 @@ /// @def TYPVAL_ENCODE_CONV_EMPTY_DICT /// @brief Macros used to convert an empty dictionary /// -/// @param tv Pointer to typval where value is stored. May not be NULL. May +/// @param tv Pointer to typval where value is stored. May be NULL. May /// point to a special dictionary. +/// @param dict Converted dictionary, lvalue or #TYPVAL_ENCODE_NODICT_VAR +/// (for dictionaries represented as special lists). /// @def TYPVAL_ENCODE_CONV_LIST_START /// @brief Macros used before starting to convert non-empty list @@ -142,7 +144,7 @@ /// /// @param tv Pointer to typval where dictionary is stored. May be NULL. May /// point to a special dictionary. -/// @param dict Converted dictionary, lvalue or &#TYPVAL_ENCODE_NODICT_VAR +/// @param dict Converted dictionary, lvalue or #TYPVAL_ENCODE_NODICT_VAR /// (for dictionaries represented as special lists). /// @param len Dictionary length. Is an expression which evaluates to an /// integer. @@ -158,7 +160,7 @@ /// /// @param tv Pointer to typval where dictionary is stored. May be NULL. May /// point to a special dictionary. -/// @param dict Converted dictionary, lvalue or &#TYPVAL_ENCODE_NODICT_VAR +/// @param dict Converted dictionary, lvalue or #TYPVAL_ENCODE_NODICT_VAR /// (for dictionaries represented as special lists). /// @def TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS @@ -166,7 +168,7 @@ /// /// @param tv Pointer to typval where dictionary is stored. May be NULL. May /// point to a special dictionary. -/// @param dict Converted dictionary, lvalue or &#TYPVAL_ENCODE_NODICT_VAR +/// @param dict Converted dictionary, lvalue or #TYPVAL_ENCODE_NODICT_VAR /// (for dictionaries represented as special lists). /// @def TYPVAL_ENCODE_CONV_DICT_END @@ -174,7 +176,7 @@ /// /// @param tv Pointer to typval where dictionary is stored. May be NULL. May /// point to a special dictionary. -/// @param dict Converted dictionary, lvalue or &#TYPVAL_ENCODE_NODICT_VAR +/// @param dict Converted dictionary, lvalue or #TYPVAL_ENCODE_NODICT_VAR /// (for dictionaries represented as special lists). /// @def TYPVAL_ENCODE_CONV_RECURSE @@ -224,6 +226,10 @@ #include "nvim/func_attr.h" #include "nvim/eval/typval_encode.h" +/// Dummy variable used because some macros need lvalue +/// +/// Must not be written to, if needed one must check that address of the +/// macros argument is (not) equal to `&TYPVAL_ENCODE_NODICT_VAR`. const dict_T *const TYPVAL_ENCODE_NODICT_VAR = NULL; static inline int _TYPVAL_ENCODE_CHECK_SELF_REFERENCE( @@ -367,7 +373,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( case VAR_DICT: { if (tv->vval.v_dict == NULL || tv->vval.v_dict->dv_hashtab.ht_used == 0) { - TYPVAL_ENCODE_CONV_EMPTY_DICT(tv); + TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, tv->vval.v_dict); break; } const dictitem_T *type_di; @@ -490,7 +496,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( } 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(tv); + TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, TYPVAL_ENCODE_NODICT_VAR); break; } for (const listitem_T *li = val_list->lv_first; li != NULL; @@ -708,20 +714,24 @@ typval_encode_stop_converting_one_item: continue; } } - TYPVAL_ENCODE_CONV_DICT_START(NULL, pt->pt_dict, - dict->dv_hashtab.ht_used); - _mp_push(mpstack, ((MPConvStackVal) { - .type = kMPConvDict, - .tv = NULL, - .data = { - .d = { - .dict = dict, - .dictp = &pt->pt_dict, - .hi = dict->dv_hashtab.ht_array, - .todo = dict->dv_hashtab.ht_used, + if (dict->dv_hashtab.ht_used == 0) { + TYPVAL_ENCODE_CONV_EMPTY_DICT(NULL, pt->pt_dict); + } else { + TYPVAL_ENCODE_CONV_DICT_START(NULL, pt->pt_dict, + dict->dv_hashtab.ht_used); + _mp_push(mpstack, ((MPConvStackVal) { + .type = kMPConvDict, + .tv = NULL, + .data = { + .d = { + .dict = dict, + .dictp = &pt->pt_dict, + .hi = dict->dv_hashtab.ht_array, + .todo = dict->dv_hashtab.ht_used, + }, }, - }, - })); + })); + } } else { TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, -1); } -- cgit From 1052009b3733fb7c4f2fa03faea8fb177f596dd6 Mon Sep 17 00:00:00 2001 From: ZyX Date: Fri, 6 Jan 2017 23:32:04 +0300 Subject: eval/typval_encode: Dump empty dictionary before checking for refcycle Otherwise copyID will stay forever on empty dictionaries. --- src/nvim/eval/typval_encode.c.h | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index 668bdfb26a..3e1170b8fa 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -703,6 +703,10 @@ typval_encode_stop_converting_one_item: dict_T *const dict = pt == NULL ? NULL : pt->pt_dict; if (dict != NULL) { TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, dict->dv_hashtab.ht_used); + if (dict->dv_hashtab.ht_used == 0) { + TYPVAL_ENCODE_CONV_EMPTY_DICT(NULL, pt->pt_dict); + continue; + } const int te_csr_ret = _TYPVAL_ENCODE_CHECK_SELF_REFERENCE( TYPVAL_ENCODE_FIRST_ARG_NAME, dict, &dict->dv_copyID, &mpstack, copyID, kMPConvDict, @@ -714,24 +718,20 @@ typval_encode_stop_converting_one_item: continue; } } - if (dict->dv_hashtab.ht_used == 0) { - TYPVAL_ENCODE_CONV_EMPTY_DICT(NULL, pt->pt_dict); - } else { - TYPVAL_ENCODE_CONV_DICT_START(NULL, pt->pt_dict, - dict->dv_hashtab.ht_used); - _mp_push(mpstack, ((MPConvStackVal) { - .type = kMPConvDict, - .tv = NULL, - .data = { - .d = { - .dict = dict, - .dictp = &pt->pt_dict, - .hi = dict->dv_hashtab.ht_array, - .todo = dict->dv_hashtab.ht_used, - }, + TYPVAL_ENCODE_CONV_DICT_START(NULL, pt->pt_dict, + dict->dv_hashtab.ht_used); + _mp_push(mpstack, ((MPConvStackVal) { + .type = kMPConvDict, + .tv = NULL, + .data = { + .d = { + .dict = dict, + .dictp = &pt->pt_dict, + .hi = dict->dv_hashtab.ht_array, + .todo = dict->dv_hashtab.ht_used, }, - })); - } + }, + })); } else { TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, -1); } -- cgit