aboutsummaryrefslogtreecommitdiff
path: root/src/api/helpers.c
diff options
context:
space:
mode:
authorThiago de Arruda <tpadilha84@gmail.com>2014-05-08 18:25:59 -0300
committerThiago de Arruda <tpadilha84@gmail.com>2014-05-13 09:33:41 -0300
commit5f5e39323ee799def35adde7cfee06698c2dfcc8 (patch)
tree75233a7524cf18b32ce74881b8e7acef9d356103 /src/api/helpers.c
parent57df213b86f08124010990665dd2f8f8b655810c (diff)
downloadrneovim-5f5e39323ee799def35adde7cfee06698c2dfcc8.tar.gz
rneovim-5f5e39323ee799def35adde7cfee06698c2dfcc8.tar.bz2
rneovim-5f5e39323ee799def35adde7cfee06698c2dfcc8.zip
API: Move vim_to_object to helpers.c
Diffstat (limited to 'src/api/helpers.c')
-rw-r--r--src/api/helpers.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/src/api/helpers.c b/src/api/helpers.c
index 9f41e55d39..2e189861a5 100644
--- a/src/api/helpers.c
+++ b/src/api/helpers.c
@@ -5,6 +5,20 @@
#include "api/helpers.h"
#include "api/defs.h"
#include "../vim.h"
+#include "memory.h"
+#include "eval.h"
+
+#include "lib/khash.h"
+
+KHASH_SET_INIT_INT64(Lookup)
+
+/// Recursion helper for the `vim_to_object`. This uses a pointer table
+/// to avoid infinite recursion due to cyclic references
+///
+/// @param obj The source object
+/// @param lookup Lookup table containing pointers to all processed objects
+/// @return The converted value
+static Object vim_to_object_rec(typval_T *obj, khash_t(Lookup) *lookup);
void try_start()
{
@@ -48,3 +62,117 @@ bool try_end(Error *err)
return err->set;
}
+Object vim_to_object(typval_T *obj)
+{
+ Object rv;
+ // We use a lookup table to break out of cyclic references
+ khash_t(Lookup) *lookup = kh_init(Lookup);
+ rv = vim_to_object_rec(obj, lookup);
+ // Free the table
+ kh_destroy(Lookup, lookup);
+ return rv;
+}
+
+static Object vim_to_object_rec(typval_T *obj, khash_t(Lookup) *lookup)
+{
+ Object rv = {.type = kObjectTypeNil};
+
+ if (obj->v_type == VAR_LIST || obj->v_type == VAR_DICT) {
+ int ret;
+ // Container object, add it to the lookup table
+ kh_put(Lookup, lookup, (uint64_t)obj, &ret);
+ if (!ret) {
+ // It's already present, meaning we alredy processed it so just return
+ // nil instead.
+ return rv;
+ }
+ }
+
+ switch (obj->v_type) {
+ case VAR_STRING:
+ if (obj->vval.v_string != NULL) {
+ rv.type = kObjectTypeString;
+ rv.data.string.data = xstrdup((char *)obj->vval.v_string);
+ rv.data.string.size = strlen(rv.data.string.data);
+ }
+ break;
+
+ case VAR_NUMBER:
+ rv.type = kObjectTypeInt;
+ rv.data.integer = obj->vval.v_number;
+ break;
+
+ case VAR_FLOAT:
+ rv.type = kObjectTypeFloat;
+ rv.data.floating_point = obj->vval.v_float;
+ break;
+
+ case VAR_LIST:
+ {
+ list_T *list = obj->vval.v_list;
+ listitem_T *item;
+
+ if (list != NULL) {
+ rv.type = kObjectTypeArray;
+ rv.data.array.size = list->lv_len;
+ rv.data.array.items = xmalloc(list->lv_len * sizeof(Object));
+
+ uint32_t i = 0;
+ for (item = list->lv_first; item != NULL; item = item->li_next) {
+ rv.data.array.items[i] = vim_to_object_rec(&item->li_tv, lookup);
+ i++;
+ }
+ }
+ }
+ break;
+
+ case VAR_DICT:
+ {
+ dict_T *dict = obj->vval.v_dict;
+ hashtab_T *ht;
+ uint64_t todo;
+ hashitem_T *hi;
+ dictitem_T *di;
+
+ if (dict != NULL) {
+ ht = &obj->vval.v_dict->dv_hashtab;
+ todo = ht->ht_used;
+ rv.type = kObjectTypeDictionary;
+
+ // Count items
+ rv.data.dictionary.size = 0;
+ for (hi = ht->ht_array; todo > 0; ++hi) {
+ if (!HASHITEM_EMPTY(hi)) {
+ todo--;
+ rv.data.dictionary.size++;
+ }
+ }
+
+ rv.data.dictionary.items =
+ xmalloc(rv.data.dictionary.size * sizeof(KeyValuePair));
+ todo = ht->ht_used;
+ uint32_t i = 0;
+
+ // Convert all
+ for (hi = ht->ht_array; todo > 0; ++hi) {
+ if (!HASHITEM_EMPTY(hi)) {
+ di = dict_lookup(hi);
+ // Convert key
+ rv.data.dictionary.items[i].key.data =
+ xstrdup((char *)hi->hi_key);
+ rv.data.dictionary.items[i].key.size =
+ strlen((char *)hi->hi_key);
+ // Convert value
+ rv.data.dictionary.items[i].value =
+ vim_to_object_rec(&di->di_tv, lookup);
+ todo--;
+ i++;
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ return rv;
+}