diff options
author | ZyX <kp-pav@yandex.ru> | 2016-12-25 19:37:13 +0300 |
---|---|---|
committer | ZyX <kp-pav@yandex.ru> | 2017-01-03 06:39:23 +0300 |
commit | c5c75513b81398f05a4e63b2f7207ae74de25ecc (patch) | |
tree | 336a14150e8b59d04fdc9b8bae28a8dd99ccc5c0 /src/nvim/eval/typval_encode.h | |
parent | efe1476d4293170496f0e933a4d3c955f0559b03 (diff) | |
download | rneovim-c5c75513b81398f05a4e63b2f7207ae74de25ecc.tar.gz rneovim-c5c75513b81398f05a4e63b2f7207ae74de25ecc.tar.bz2 rneovim-c5c75513b81398f05a4e63b2f7207ae74de25ecc.zip |
eval/typval_encode: Make partial conversions not recursive
Is known to crash in the current state.
Ref #5825.
Diffstat (limited to 'src/nvim/eval/typval_encode.h')
-rw-r--r-- | src/nvim/eval/typval_encode.h | 131 |
1 files changed, 124 insertions, 7 deletions
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, \ |