aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2021-10-26 12:52:49 +0200
committerBjörn Linse <bjorn.linse@gmail.com>2021-10-29 15:52:28 +0200
commitc3a3e654282e774ff400443cbfcbe78630fe4206 (patch)
treefe25a069ca7dd58fcd4210851e6576ea605fff8d
parentd1c470957b49380ec5ceba603dbd85a14f60f09b (diff)
downloadrneovim-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.c348
-rw-r--r--src/nvim/api/private/converter.h11
-rw-r--r--src/nvim/api/private/helpers.c332
-rw-r--r--src/nvim/api/private/helpers.h2
-rw-r--r--src/nvim/api/vim.c1
-rw-r--r--src/nvim/channel.c1
-rw-r--r--src/nvim/context.c1
-rw-r--r--src/nvim/eval/funcs.c1
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"