diff options
author | Björn Linse <bjorn.linse@gmail.com> | 2021-10-26 12:52:49 +0200 |
---|---|---|
committer | Björn Linse <bjorn.linse@gmail.com> | 2021-10-29 15:52:28 +0200 |
commit | c3a3e654282e774ff400443cbfcbe78630fe4206 (patch) | |
tree | fe25a069ca7dd58fcd4210851e6576ea605fff8d | |
parent | d1c470957b49380ec5ceba603dbd85a14f60f09b (diff) | |
download | rneovim-c3a3e654282e774ff400443cbfcbe78630fe4206.tar.gz rneovim-c3a3e654282e774ff400443cbfcbe78630fe4206.tar.bz2 rneovim-c3a3e654282e774ff400443cbfcbe78630fe4206.zip |
refactor(api): break out vim_to_object/object_to_vim to own file
-rw-r--r-- | src/nvim/api/private/converter.c | 348 | ||||
-rw-r--r-- | src/nvim/api/private/converter.h | 11 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.c | 332 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.h | 2 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 1 | ||||
-rw-r--r-- | src/nvim/channel.c | 1 | ||||
-rw-r--r-- | src/nvim/context.c | 1 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 1 |
8 files changed, 364 insertions, 333 deletions
diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c new file mode 100644 index 0000000000..0d054c7958 --- /dev/null +++ b/src/nvim/api/private/converter.c @@ -0,0 +1,348 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + +#include <assert.h> +#include <stddef.h> +#include <stdlib.h> + +#include "nvim/assert.h" +#include "nvim/api/private/defs.h" +#include "nvim/api/private/helpers.h" +#include "nvim/api/private/converter.h" +#include "nvim/eval/typval.h" + +/// Helper structure for vim_to_object +typedef struct { + kvec_withinit_t(Object, 2) stack; ///< Object stack. +} EncodedData; + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "api/private/converter.c.generated.h" +#endif + +#define TYPVAL_ENCODE_ALLOW_SPECIALS false + +#define TYPVAL_ENCODE_CONV_NIL(tv) \ + kvi_push(edata->stack, NIL) + +#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ + kvi_push(edata->stack, BOOLEAN_OBJ((Boolean)(num))) + +#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ + kvi_push(edata->stack, INTEGER_OBJ((Integer)(num))) + +#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER TYPVAL_ENCODE_CONV_NUMBER + +#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ + kvi_push(edata->stack, FLOAT_OBJ((Float)(flt))) + +#define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \ + do { \ + const size_t len_ = (size_t)(len); \ + const char *const str_ = (const char *)(str); \ + assert(len_ == 0 || str_ != NULL); \ + kvi_push(edata->stack, STRING_OBJ(cbuf_to_string((len_?str_:""), len_))); \ + } while (0) + +#define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING + +#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, str, len, type) \ + TYPVAL_ENCODE_CONV_NIL(tv) + +#define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \ + do { \ + const size_t len_ = (size_t)(len); \ + const blob_T *const blob_ = (blob); \ + kvi_push(edata->stack, STRING_OBJ(((String) { \ + .data = len_ != 0 ? xmemdup(blob_->bv_ga.ga_data, len_) : NULL, \ + .size = len_ \ + }))); \ + } while (0) + +#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ + do { \ + TYPVAL_ENCODE_CONV_NIL(tv); \ + goto typval_encode_stop_converting_one_item; \ + } while (0) + +#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(tv) \ + kvi_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 }))) + +#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ + kvi_push(edata->stack, \ + DICTIONARY_OBJ(((Dictionary) { .capacity = 0, .size = 0 }))) + +static inline void typval_encode_list_start(EncodedData *const edata, const size_t len) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + kvi_push(edata->stack, ARRAY_OBJ(((Array) { + .capacity = len, + .size = 0, + .items = xmalloc(len * sizeof(*((Object)OBJECT_INIT).data.array.items)), + }))); +} + +#define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ + typval_encode_list_start(edata, (size_t)(len)) + +#define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) + +static inline void typval_encode_between_list_items(EncodedData *const edata) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + Object item = kv_pop(edata->stack); + Object *const list = &kv_last(edata->stack); + assert(list->type == kObjectTypeArray); + assert(list->data.array.size < list->data.array.capacity); + list->data.array.items[list->data.array.size++] = item; +} + +#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) \ + typval_encode_between_list_items(edata) + +static inline void typval_encode_list_end(EncodedData *const edata) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + typval_encode_between_list_items(edata); +#ifndef NDEBUG + const Object *const list = &kv_last(edata->stack); + assert(list->data.array.size == list->data.array.capacity); +#endif +} + +#define TYPVAL_ENCODE_CONV_LIST_END(tv) \ + typval_encode_list_end(edata) + +static inline void typval_encode_dict_start(EncodedData *const edata, const size_t len) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + kvi_push(edata->stack, DICTIONARY_OBJ(((Dictionary) { + .capacity = len, + .size = 0, + .items = xmalloc(len * sizeof(*((Object)OBJECT_INIT).data.dictionary.items)), + }))); +} + +#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \ + typval_encode_dict_start(edata, (size_t)(len)) + +#define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv) + +#define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(label, kv_pair) + +static inline void typval_encode_after_key(EncodedData *const edata) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + Object key = kv_pop(edata->stack); + Object *const dict = &kv_last(edata->stack); + assert(dict->type == kObjectTypeDictionary); + assert(dict->data.dictionary.size < dict->data.dictionary.capacity); + if (key.type == kObjectTypeString) { + dict->data.dictionary.items[dict->data.dictionary.size].key + = key.data.string; + } else { + api_free_object(key); + dict->data.dictionary.items[dict->data.dictionary.size].key + = STATIC_CSTR_TO_STRING("__INVALID_KEY__"); + } +} + +#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict) \ + typval_encode_after_key(edata) + +static inline void typval_encode_between_dict_items(EncodedData *const edata) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + Object val = kv_pop(edata->stack); + Object *const dict = &kv_last(edata->stack); + assert(dict->type == kObjectTypeDictionary); + assert(dict->data.dictionary.size < dict->data.dictionary.capacity); + dict->data.dictionary.items[dict->data.dictionary.size++].value = val; +} + +#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) \ + typval_encode_between_dict_items(edata) + +static inline void typval_encode_dict_end(EncodedData *const edata) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + typval_encode_between_dict_items(edata); +#ifndef NDEBUG + const Object *const dict = &kv_last(edata->stack); + assert(dict->data.dictionary.size == dict->data.dictionary.capacity); +#endif +} + +#define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \ + typval_encode_dict_end(edata) + +#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ + TYPVAL_ENCODE_CONV_NIL(val) + +#define TYPVAL_ENCODE_SCOPE static +#define TYPVAL_ENCODE_NAME object +#define TYPVAL_ENCODE_FIRST_ARG_TYPE EncodedData *const +#define TYPVAL_ENCODE_FIRST_ARG_NAME edata +#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 +#undef TYPVAL_ENCODE_CONV_EXT_STRING +#undef TYPVAL_ENCODE_CONV_BLOB +#undef TYPVAL_ENCODE_CONV_NUMBER +#undef TYPVAL_ENCODE_CONV_FLOAT +#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_REAL_LIST_AFTER_START +#undef TYPVAL_ENCODE_CONV_EMPTY_DICT +#undef TYPVAL_ENCODE_CONV_NIL +#undef TYPVAL_ENCODE_CONV_BOOL +#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER +#undef TYPVAL_ENCODE_CONV_DICT_START +#undef TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START +#undef TYPVAL_ENCODE_CONV_DICT_END +#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY +#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS +#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 +#undef TYPVAL_ENCODE_ALLOW_SPECIALS + +/// Convert a vim object to an `Object` instance, recursively expanding +/// Arrays/Dictionaries. +/// +/// @param obj The source object +/// @return The converted value +Object vim_to_object(typval_T *obj) +{ + EncodedData edata; + kvi_init(edata.stack); + const int evo_ret = encode_vim_to_object(&edata, obj, + "vim_to_object argument"); + (void)evo_ret; + assert(evo_ret == OK); + Object ret = kv_A(edata.stack, 0); + assert(kv_size(edata.stack) == 1); + kvi_destroy(edata.stack); + return ret; +} + +/// Converts from type Object to a VimL value. +/// +/// @param obj Object to convert from. +/// @param tv Conversion result is placed here. On failure member v_type is +/// set to VAR_UNKNOWN (no allocation was made for this variable). +/// returns true if conversion is successful, otherwise false. +bool object_to_vim(Object obj, typval_T *tv, Error *err) +{ + tv->v_type = VAR_UNKNOWN; + tv->v_lock = VAR_UNLOCKED; + + switch (obj.type) { + case kObjectTypeNil: + tv->v_type = VAR_SPECIAL; + tv->vval.v_special = kSpecialVarNull; + break; + + case kObjectTypeBoolean: + tv->v_type = VAR_BOOL; + tv->vval.v_bool = obj.data.boolean? kBoolVarTrue: kBoolVarFalse; + break; + + case kObjectTypeBuffer: + case kObjectTypeWindow: + case kObjectTypeTabpage: + case kObjectTypeInteger: + STATIC_ASSERT(sizeof(obj.data.integer) <= sizeof(varnumber_T), + "Integer size must be <= VimL number size"); + tv->v_type = VAR_NUMBER; + tv->vval.v_number = (varnumber_T)obj.data.integer; + break; + + case kObjectTypeFloat: + tv->v_type = VAR_FLOAT; + tv->vval.v_float = obj.data.floating; + break; + + case kObjectTypeString: + tv->v_type = VAR_STRING; + if (obj.data.string.data == NULL) { + tv->vval.v_string = NULL; + } else { + tv->vval.v_string = xmemdupz(obj.data.string.data, + obj.data.string.size); + } + break; + + case kObjectTypeArray: { + list_T *const list = tv_list_alloc((ptrdiff_t)obj.data.array.size); + + for (uint32_t i = 0; i < obj.data.array.size; i++) { + Object item = obj.data.array.items[i]; + typval_T li_tv; + + if (!object_to_vim(item, &li_tv, err)) { + tv_list_free(list); + return false; + } + + tv_list_append_owned_tv(list, li_tv); + } + tv_list_ref(list); + + tv->v_type = VAR_LIST; + tv->vval.v_list = list; + break; + } + + case kObjectTypeDictionary: { + dict_T *const dict = tv_dict_alloc(); + + for (uint32_t i = 0; i < obj.data.dictionary.size; i++) { + KeyValuePair item = obj.data.dictionary.items[i]; + String key = item.key; + + if (key.size == 0) { + api_set_error(err, kErrorTypeValidation, + "Empty dictionary keys aren't allowed"); + // cleanup + tv_dict_free(dict); + return false; + } + + dictitem_T *const di = tv_dict_item_alloc(key.data); + + if (!object_to_vim(item.value, &di->di_tv, err)) { + // cleanup + tv_dict_item_free(di); + tv_dict_free(dict); + return false; + } + + tv_dict_add(dict, di); + } + dict->dv_refcount++; + + tv->v_type = VAR_DICT; + tv->vval.v_dict = dict; + break; + } + default: + abort(); + } + + return true; +} diff --git a/src/nvim/api/private/converter.h b/src/nvim/api/private/converter.h new file mode 100644 index 0000000000..80ee640295 --- /dev/null +++ b/src/nvim/api/private/converter.h @@ -0,0 +1,11 @@ +#ifndef NVIM_API_PRIVATE_CONVERTER_H +#define NVIM_API_PRIVATE_CONVERTER_H + +#include "nvim/api/private/defs.h" +#include "nvim/eval/typval.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "api/private/converter.h.generated.h" +#endif + +#endif // NVIM_API_PRIVATE_CONVERTER_H diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 745681c3f8..6b3f4a29d7 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -28,6 +28,7 @@ #include "nvim/mark.h" #include "nvim/memline.h" #include "nvim/memory.h" +#include "nvim/api/private/converter.h" #include "nvim/msgpack_rpc/helpers.h" #include "nvim/option.h" #include "nvim/option_defs.h" @@ -37,11 +38,6 @@ #include "nvim/vim.h" #include "nvim/window.h" -/// Helper structure for vim_to_object -typedef struct { - kvec_withinit_t(Object, 2) stack; ///< Object stack. -} EncodedData; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/funcs_metadata.generated.h" # include "api/private/helpers.c.generated.h" @@ -415,226 +411,6 @@ void set_option_to(uint64_t channel_id, void *to, int type, String name, Object current_sctx = save_current_sctx; } -#define TYPVAL_ENCODE_ALLOW_SPECIALS false - -#define TYPVAL_ENCODE_CONV_NIL(tv) \ - kvi_push(edata->stack, NIL) - -#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ - kvi_push(edata->stack, BOOLEAN_OBJ((Boolean)(num))) - -#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ - kvi_push(edata->stack, INTEGER_OBJ((Integer)(num))) - -#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER TYPVAL_ENCODE_CONV_NUMBER - -#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ - kvi_push(edata->stack, FLOAT_OBJ((Float)(flt))) - -#define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \ - do { \ - const size_t len_ = (size_t)(len); \ - const char *const str_ = (const char *)(str); \ - assert(len_ == 0 || str_ != NULL); \ - kvi_push(edata->stack, STRING_OBJ(cbuf_to_string((len_?str_:""), len_))); \ - } while (0) - -#define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING - -#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, str, len, type) \ - TYPVAL_ENCODE_CONV_NIL(tv) - -#define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \ - do { \ - const size_t len_ = (size_t)(len); \ - const blob_T *const blob_ = (blob); \ - kvi_push(edata->stack, STRING_OBJ(((String) { \ - .data = len_ != 0 ? xmemdup(blob_->bv_ga.ga_data, len_) : NULL, \ - .size = len_ \ - }))); \ - } while (0) - -#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ - do { \ - TYPVAL_ENCODE_CONV_NIL(tv); \ - goto typval_encode_stop_converting_one_item; \ - } while (0) - -#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(tv) \ - kvi_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 }))) - -#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ - kvi_push(edata->stack, \ - DICTIONARY_OBJ(((Dictionary) { .capacity = 0, .size = 0 }))) - -static inline void typval_encode_list_start(EncodedData *const edata, const size_t len) - FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL -{ - kvi_push(edata->stack, ARRAY_OBJ(((Array) { - .capacity = len, - .size = 0, - .items = xmalloc(len * sizeof(*((Object)OBJECT_INIT).data.array.items)), - }))); -} - -#define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ - typval_encode_list_start(edata, (size_t)(len)) - -#define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) - -static inline void typval_encode_between_list_items(EncodedData *const edata) - FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL -{ - Object item = kv_pop(edata->stack); - Object *const list = &kv_last(edata->stack); - assert(list->type == kObjectTypeArray); - assert(list->data.array.size < list->data.array.capacity); - list->data.array.items[list->data.array.size++] = item; -} - -#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) \ - typval_encode_between_list_items(edata) - -static inline void typval_encode_list_end(EncodedData *const edata) - FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL -{ - typval_encode_between_list_items(edata); -#ifndef NDEBUG - const Object *const list = &kv_last(edata->stack); - assert(list->data.array.size == list->data.array.capacity); -#endif -} - -#define TYPVAL_ENCODE_CONV_LIST_END(tv) \ - typval_encode_list_end(edata) - -static inline void typval_encode_dict_start(EncodedData *const edata, const size_t len) - FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL -{ - kvi_push(edata->stack, DICTIONARY_OBJ(((Dictionary) { - .capacity = len, - .size = 0, - .items = xmalloc(len * sizeof( - *((Object)OBJECT_INIT).data.dictionary.items)), - }))); -} - -#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \ - typval_encode_dict_start(edata, (size_t)(len)) - -#define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv) - -#define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(label, kv_pair) - -static inline void typval_encode_after_key(EncodedData *const edata) - FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL -{ - Object key = kv_pop(edata->stack); - Object *const dict = &kv_last(edata->stack); - assert(dict->type == kObjectTypeDictionary); - assert(dict->data.dictionary.size < dict->data.dictionary.capacity); - if (key.type == kObjectTypeString) { - dict->data.dictionary.items[dict->data.dictionary.size].key - = key.data.string; - } else { - api_free_object(key); - dict->data.dictionary.items[dict->data.dictionary.size].key - = STATIC_CSTR_TO_STRING("__INVALID_KEY__"); - } -} - -#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict) \ - typval_encode_after_key(edata) - -static inline void typval_encode_between_dict_items(EncodedData *const edata) - FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL -{ - Object val = kv_pop(edata->stack); - Object *const dict = &kv_last(edata->stack); - assert(dict->type == kObjectTypeDictionary); - assert(dict->data.dictionary.size < dict->data.dictionary.capacity); - dict->data.dictionary.items[dict->data.dictionary.size++].value = val; -} - -#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) \ - typval_encode_between_dict_items(edata) - -static inline void typval_encode_dict_end(EncodedData *const edata) - FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL -{ - typval_encode_between_dict_items(edata); -#ifndef NDEBUG - const Object *const dict = &kv_last(edata->stack); - assert(dict->data.dictionary.size == dict->data.dictionary.capacity); -#endif -} - -#define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \ - typval_encode_dict_end(edata) - -#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ - TYPVAL_ENCODE_CONV_NIL(val) - -#define TYPVAL_ENCODE_SCOPE static -#define TYPVAL_ENCODE_NAME object -#define TYPVAL_ENCODE_FIRST_ARG_TYPE EncodedData *const -#define TYPVAL_ENCODE_FIRST_ARG_NAME edata -#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 -#undef TYPVAL_ENCODE_CONV_EXT_STRING -#undef TYPVAL_ENCODE_CONV_BLOB -#undef TYPVAL_ENCODE_CONV_NUMBER -#undef TYPVAL_ENCODE_CONV_FLOAT -#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_REAL_LIST_AFTER_START -#undef TYPVAL_ENCODE_CONV_EMPTY_DICT -#undef TYPVAL_ENCODE_CONV_NIL -#undef TYPVAL_ENCODE_CONV_BOOL -#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER -#undef TYPVAL_ENCODE_CONV_DICT_START -#undef TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START -#undef TYPVAL_ENCODE_CONV_DICT_END -#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY -#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS -#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 -#undef TYPVAL_ENCODE_ALLOW_SPECIALS - -/// Convert a vim object to an `Object` instance, recursively expanding -/// Arrays/Dictionaries. -/// -/// @param obj The source object -/// @return The converted value -Object vim_to_object(typval_T *obj) -{ - EncodedData edata; - kvi_init(edata.stack); - const int evo_ret = encode_vim_to_object(&edata, obj, - "vim_to_object argument"); - (void)evo_ret; - assert(evo_ret == OK); - Object ret = kv_A(edata.stack, 0); - assert(kv_size(edata.stack) == 1); - kvi_destroy(edata.stack); - return ret; -} buf_T *find_buffer_by_handle(Buffer buffer, Error *err) { @@ -966,112 +742,6 @@ bool buf_collect_lines(buf_T *buf, size_t n, int64_t start, bool replace_nl, Arr return true; } -/// Converts from type Object to a VimL value. -/// -/// @param obj Object to convert from. -/// @param tv Conversion result is placed here. On failure member v_type is -/// set to VAR_UNKNOWN (no allocation was made for this variable). -/// returns true if conversion is successful, otherwise false. -bool object_to_vim(Object obj, typval_T *tv, Error *err) -{ - tv->v_type = VAR_UNKNOWN; - tv->v_lock = VAR_UNLOCKED; - - switch (obj.type) { - case kObjectTypeNil: - tv->v_type = VAR_SPECIAL; - tv->vval.v_special = kSpecialVarNull; - break; - - case kObjectTypeBoolean: - tv->v_type = VAR_BOOL; - tv->vval.v_bool = obj.data.boolean? kBoolVarTrue: kBoolVarFalse; - break; - - case kObjectTypeBuffer: - case kObjectTypeWindow: - case kObjectTypeTabpage: - case kObjectTypeInteger: - STATIC_ASSERT(sizeof(obj.data.integer) <= sizeof(varnumber_T), - "Integer size must be <= VimL number size"); - tv->v_type = VAR_NUMBER; - tv->vval.v_number = (varnumber_T)obj.data.integer; - break; - - case kObjectTypeFloat: - tv->v_type = VAR_FLOAT; - tv->vval.v_float = obj.data.floating; - break; - - case kObjectTypeString: - tv->v_type = VAR_STRING; - if (obj.data.string.data == NULL) { - tv->vval.v_string = NULL; - } else { - tv->vval.v_string = xmemdupz(obj.data.string.data, - obj.data.string.size); - } - break; - - case kObjectTypeArray: { - list_T *const list = tv_list_alloc((ptrdiff_t)obj.data.array.size); - - for (uint32_t i = 0; i < obj.data.array.size; i++) { - Object item = obj.data.array.items[i]; - typval_T li_tv; - - if (!object_to_vim(item, &li_tv, err)) { - tv_list_free(list); - return false; - } - - tv_list_append_owned_tv(list, li_tv); - } - tv_list_ref(list); - - tv->v_type = VAR_LIST; - tv->vval.v_list = list; - break; - } - - case kObjectTypeDictionary: { - dict_T *const dict = tv_dict_alloc(); - - for (uint32_t i = 0; i < obj.data.dictionary.size; i++) { - KeyValuePair item = obj.data.dictionary.items[i]; - String key = item.key; - - if (key.size == 0) { - api_set_error(err, kErrorTypeValidation, - "Empty dictionary keys aren't allowed"); - // cleanup - tv_dict_free(dict); - return false; - } - - dictitem_T *const di = tv_dict_item_alloc(key.data); - - if (!object_to_vim(item.value, &di->di_tv, err)) { - // cleanup - tv_dict_item_free(di); - tv_dict_free(dict); - return false; - } - - tv_dict_add(dict, di); - } - dict->dv_refcount++; - - tv->v_type = VAR_DICT; - tv->vval.v_dict = dict; - break; - } - default: - abort(); - } - - return true; -} void api_free_string(String value) { diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 08d2c8d90c..6d0aec9c90 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -1,8 +1,6 @@ #ifndef NVIM_API_PRIVATE_HELPERS_H #define NVIM_API_PRIVATE_HELPERS_H -#include <stdbool.h> - #include "nvim/api/private/defs.h" #include "nvim/decoration.h" #include "nvim/ex_eval.h" diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 7f442c8e52..cbaba72213 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -10,6 +10,7 @@ #include "nvim/api/buffer.h" #include "nvim/api/deprecated.h" +#include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 313eefd562..cfeaafe77a 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -1,6 +1,7 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include "nvim/api/private/converter.h" #include "nvim/api/private/helpers.h" #include "nvim/api/ui.h" #include "nvim/channel.h" diff --git a/src/nvim/context.c b/src/nvim/context.c index 1db7938ef4..911139dfdf 100644 --- a/src/nvim/context.c +++ b/src/nvim/context.c @@ -3,6 +3,7 @@ // Context: snapshot of the entire editor state as one big object/map +#include "nvim/api/private/converter.h" #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" #include "nvim/context.h" diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index d0f6c178df..b6ea3ad0dd 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4,6 +4,7 @@ #include <float.h> #include <math.h> +#include "nvim/api/private/converter.h" #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" #include "nvim/ascii.h" |