mirror of
https://github.com/neovim/neovim.git
synced 2025-09-14 15:28:17 +00:00
eval/typval_encode: Make partial conversions not recursive
Is known to crash in the current state. Ref #5825.
This commit is contained in:
@@ -357,11 +357,12 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
|
|||||||
#define TYPVAL_ENCODE_CONV_EXT_STRING(str, len, type) \
|
#define TYPVAL_ENCODE_CONV_EXT_STRING(str, len, type) \
|
||||||
TYPVAL_ENCODE_CONV_NIL()
|
TYPVAL_ENCODE_CONV_NIL()
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_FUNC(fun) \
|
#define TYPVAL_ENCODE_CONV_FUNC_START(fun, is_partial, pt) \
|
||||||
TYPVAL_ENCODE_CONV_NIL()
|
TYPVAL_ENCODE_CONV_NIL()
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_PARTIAL(partial) \
|
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(len)
|
||||||
TYPVAL_ENCODE_CONV_NIL()
|
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(len)
|
||||||
|
#define TYPVAL_ENCODE_CONV_FUNC_END()
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
||||||
kv_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 })))
|
kv_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 })))
|
||||||
@@ -484,8 +485,10 @@ TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, object, EncodedData *const, edata)
|
|||||||
#undef TYPVAL_ENCODE_CONV_EXT_STRING
|
#undef TYPVAL_ENCODE_CONV_EXT_STRING
|
||||||
#undef TYPVAL_ENCODE_CONV_NUMBER
|
#undef TYPVAL_ENCODE_CONV_NUMBER
|
||||||
#undef TYPVAL_ENCODE_CONV_FLOAT
|
#undef TYPVAL_ENCODE_CONV_FLOAT
|
||||||
#undef TYPVAL_ENCODE_CONV_FUNC
|
#undef TYPVAL_ENCODE_CONV_FUNC_START
|
||||||
#undef TYPVAL_ENCODE_CONV_PARTIAL
|
#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_EMPTY_LIST
|
||||||
#undef TYPVAL_ENCODE_CONV_LIST_START
|
#undef TYPVAL_ENCODE_CONV_LIST_START
|
||||||
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
||||||
|
@@ -19070,22 +19070,24 @@ void free_tv(typval_T *varp)
|
|||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_EXT_STRING(ignored1, ignored2, ignored3)
|
#define TYPVAL_ENCODE_CONV_EXT_STRING(ignored1, ignored2, ignored3)
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_FUNC(fun) \
|
#define TYPVAL_ENCODE_CONV_FUNC_START(fun, is_partial, pt) \
|
||||||
do { \
|
do { \
|
||||||
func_unref(fun); \
|
if (is_partial) { \
|
||||||
if (fun != empty_string) { \
|
partial_unref(pt); \
|
||||||
xfree(fun); \
|
tv->vval.v_partial = NULL; \
|
||||||
|
} else { \
|
||||||
|
func_unref(fun); \
|
||||||
|
if (fun != empty_string) { \
|
||||||
|
xfree(fun); \
|
||||||
|
} \
|
||||||
|
tv->vval.v_string = NULL; \
|
||||||
} \
|
} \
|
||||||
tv->vval.v_string = NULL; \
|
|
||||||
tv->v_lock = VAR_UNLOCKED; \
|
tv->v_lock = VAR_UNLOCKED; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_PARTIAL(pt) \
|
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(len)
|
||||||
do { \
|
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(len)
|
||||||
partial_unref(pt); \
|
#define TYPVAL_ENCODE_CONV_FUNC_END()
|
||||||
pt = NULL; \
|
|
||||||
tv->v_lock = VAR_UNLOCKED; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
||||||
do { \
|
do { \
|
||||||
@@ -19162,8 +19164,10 @@ TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, nothing, void *, ignored)
|
|||||||
#undef TYPVAL_ENCODE_CONV_STRING
|
#undef TYPVAL_ENCODE_CONV_STRING
|
||||||
#undef TYPVAL_ENCODE_CONV_STR_STRING
|
#undef TYPVAL_ENCODE_CONV_STR_STRING
|
||||||
#undef TYPVAL_ENCODE_CONV_EXT_STRING
|
#undef TYPVAL_ENCODE_CONV_EXT_STRING
|
||||||
#undef TYPVAL_ENCODE_CONV_FUNC
|
#undef TYPVAL_ENCODE_CONV_FUNC_START
|
||||||
#undef TYPVAL_ENCODE_CONV_PARTIAL
|
#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_EMPTY_LIST
|
||||||
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
||||||
#undef TYPVAL_ENCODE_CONV_LIST_START
|
#undef TYPVAL_ENCODE_CONV_LIST_START
|
||||||
|
@@ -108,9 +108,12 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack,
|
|||||||
{
|
{
|
||||||
garray_T msg_ga;
|
garray_T msg_ga;
|
||||||
ga_init(&msg_ga, (int)sizeof(char), 80);
|
ga_init(&msg_ga, (int)sizeof(char), 80);
|
||||||
char *const key_msg = _("key %s");
|
const char *const key_msg = _("key %s");
|
||||||
char *const key_pair_msg = _("key %s at index %i from special map");
|
const char *const key_pair_msg = _("key %s at index %i from special map");
|
||||||
char *const idx_msg = _("index %i");
|
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++) {
|
for (size_t i = 0; i < kv_size(*mpstack); i++) {
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
ga_concat(&msg_ga, ", ");
|
ga_concat(&msg_ga, ", ");
|
||||||
@@ -154,6 +157,29 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack,
|
|||||||
}
|
}
|
||||||
break;
|
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
|
EMSG3(msg, objname, (kv_size(*mpstack) == 0
|
||||||
@@ -308,67 +334,29 @@ int encode_read_from_list(ListReaderState *const state, char *const buf,
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_FUNC(fun) \
|
#define TYPVAL_ENCODE_CONV_FUNC_START(fun, is_partial, pt) \
|
||||||
do { \
|
do { \
|
||||||
ga_concat(gap, "function("); \
|
ga_concat(gap, "function("); \
|
||||||
TYPVAL_ENCODE_CONV_STRING(fun, STRLEN(fun)); \
|
TYPVAL_ENCODE_CONV_STRING(fun, STRLEN(fun)); \
|
||||||
ga_append(gap, ')'); \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_PARTIAL(pt) \
|
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(len) \
|
||||||
do { \
|
do { \
|
||||||
int i; \
|
if (len != 0) { \
|
||||||
ga_concat(gap, "function("); \
|
ga_concat(gap, ", "); \
|
||||||
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, ')'); \
|
|
||||||
} while (0)
|
} 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() \
|
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
||||||
ga_concat(gap, "[]")
|
ga_concat(gap, "[]")
|
||||||
|
|
||||||
@@ -709,18 +697,12 @@ static inline int convert_to_json_string(garray_T *const gap,
|
|||||||
return FAIL; \
|
return FAIL; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#undef TYPVAL_ENCODE_CONV_FUNC
|
#undef TYPVAL_ENCODE_CONV_FUNC_START
|
||||||
#define TYPVAL_ENCODE_CONV_FUNC(fun) \
|
#define TYPVAL_ENCODE_CONV_FUNC_START(fun, is_partial, pt) \
|
||||||
return conv_error(_("E474: Error while dumping %s, %s: " \
|
return conv_error(_("E474: Error while dumping %s, %s: " \
|
||||||
"attempt to dump function reference"), \
|
"attempt to dump function reference"), \
|
||||||
mpstack, objname)
|
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()
|
/// Check whether given key can be used in json_encode()
|
||||||
///
|
///
|
||||||
/// @param[in] tv Key to check.
|
/// @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_EXT_STRING
|
||||||
#undef TYPVAL_ENCODE_CONV_NUMBER
|
#undef TYPVAL_ENCODE_CONV_NUMBER
|
||||||
#undef TYPVAL_ENCODE_CONV_FLOAT
|
#undef TYPVAL_ENCODE_CONV_FLOAT
|
||||||
#undef TYPVAL_ENCODE_CONV_FUNC
|
#undef TYPVAL_ENCODE_CONV_FUNC_START
|
||||||
#undef TYPVAL_ENCODE_CONV_PARTIAL
|
#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_EMPTY_LIST
|
||||||
#undef TYPVAL_ENCODE_CONV_LIST_START
|
#undef TYPVAL_ENCODE_CONV_LIST_START
|
||||||
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
#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) \
|
#define TYPVAL_ENCODE_CONV_FLOAT(flt) \
|
||||||
msgpack_pack_double(packer, (double) (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: " \
|
return conv_error(_("E5004: Error while dumping %s, %s: " \
|
||||||
"attempt to dump function reference"), \
|
"attempt to dump function reference"), \
|
||||||
mpstack, objname)
|
mpstack, objname)
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_PARTIAL(partial) \
|
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(len)
|
||||||
return conv_error(_("E5004: Error while dumping %s, %s: " \
|
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(len)
|
||||||
"attempt to dump partial"), \
|
#define TYPVAL_ENCODE_CONV_FUNC_END()
|
||||||
mpstack, objname)
|
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
||||||
msgpack_pack_array(packer, 0)
|
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_EXT_STRING
|
||||||
#undef TYPVAL_ENCODE_CONV_NUMBER
|
#undef TYPVAL_ENCODE_CONV_NUMBER
|
||||||
#undef TYPVAL_ENCODE_CONV_FLOAT
|
#undef TYPVAL_ENCODE_CONV_FLOAT
|
||||||
#undef TYPVAL_ENCODE_CONV_FUNC
|
#undef TYPVAL_ENCODE_CONV_FUNC_START
|
||||||
#undef TYPVAL_ENCODE_CONV_PARTIAL
|
#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_EMPTY_LIST
|
||||||
#undef TYPVAL_ENCODE_CONV_LIST_START
|
#undef TYPVAL_ENCODE_CONV_LIST_START
|
||||||
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
||||||
|
@@ -69,10 +69,30 @@
|
|||||||
///
|
///
|
||||||
/// @param fun Function name.
|
/// @param fun Function name.
|
||||||
|
|
||||||
/// @def TYPVAL_ENCODE_CONV_PARTIAL
|
/// @def TYPVAL_ENCODE_CONV_FUNC_START
|
||||||
/// @brief Macros used to convert a partial
|
/// @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
|
/// @def TYPVAL_ENCODE_CONV_EMPTY_LIST
|
||||||
/// @brief Macros used to convert an empty list
|
/// @brief Macros used to convert an empty list
|
||||||
@@ -151,11 +171,20 @@
|
|||||||
|
|
||||||
/// Type of the stack entry
|
/// Type of the stack entry
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kMPConvDict, ///< Convert dict_T *dictionary.
|
kMPConvDict, ///< Convert dict_T *dictionary.
|
||||||
kMPConvList, ///< Convert list_T *list.
|
kMPConvList, ///< Convert list_T *list.
|
||||||
kMPConvPairs, ///< Convert mapping represented as a list_T* of pairs.
|
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;
|
} 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
|
/// Structure representing current VimL to messagepack conversion state
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MPConvStackValType type; ///< Type of the stack entry.
|
MPConvStackValType type; ///< Type of the stack entry.
|
||||||
@@ -170,6 +199,15 @@ typedef struct {
|
|||||||
list_T *list; ///< Currently converted list.
|
list_T *list; ///< Currently converted list.
|
||||||
listitem_T *li; ///< Currently converted list item.
|
listitem_T *li; ///< Currently converted list item.
|
||||||
} l; ///< State of list or generic mapping conversion.
|
} 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.
|
} data; ///< Data to convert.
|
||||||
} MPConvStackVal;
|
} MPConvStackVal;
|
||||||
|
|
||||||
@@ -250,11 +288,26 @@ static int name##_convert_one_value(firstargtype firstargname, \
|
|||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
case VAR_FUNC: { \
|
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; \
|
break; \
|
||||||
} \
|
} \
|
||||||
case VAR_PARTIAL: { \
|
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; \
|
break; \
|
||||||
} \
|
} \
|
||||||
case VAR_LIST: { \
|
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; \
|
cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \
|
||||||
break; \
|
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); \
|
assert(cur_tv != NULL); \
|
||||||
if (name##_convert_one_value(firstargname, &mpstack, cur_tv, copyID, \
|
if (name##_convert_one_value(firstargname, &mpstack, cur_tv, copyID, \
|
||||||
|
Reference in New Issue
Block a user