aboutsummaryrefslogtreecommitdiff
path: root/src/api/vim.c
diff options
context:
space:
mode:
authorThiago de Arruda <tpadilha84@gmail.com>2014-05-08 11:12:03 -0300
committerThiago de Arruda <tpadilha84@gmail.com>2014-05-12 21:26:56 -0300
commitba11128077845d286d9f1a8282e1404d2c80b2a5 (patch)
tree967af0e44e7e248b462bbc8df686ec0fc0186d2c /src/api/vim.c
parentd98ca3ea98aee41354a45124cfd9f8f6dfb3017a (diff)
downloadrneovim-ba11128077845d286d9f1a8282e1404d2c80b2a5.tar.gz
rneovim-ba11128077845d286d9f1a8282e1404d2c80b2a5.tar.bz2
rneovim-ba11128077845d286d9f1a8282e1404d2c80b2a5.zip
API: Implement vim_eval
The vimscript object conversion function was adapted from the version found in 'if_py_both.h' in the upstream source. It was also required to re-add the `dict_lookup` function that was lost during the initial import.
Diffstat (limited to 'src/api/vim.c')
-rw-r--r--src/api/vim.c154
1 files changed, 153 insertions, 1 deletions
diff --git a/src/api/vim.c b/src/api/vim.c
index 31bdbecd68..ee3dca30a4 100644
--- a/src/api/vim.c
+++ b/src/api/vim.c
@@ -1,6 +1,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
+#include <string.h>
#include "api/vim.h"
#include "api/defs.h"
@@ -9,8 +10,13 @@
#include "ascii.h"
#include "ex_docmd.h"
#include "screen.h"
+#include "eval.h"
#include "memory.h"
+#include "lib/khash.h"
+
+KHASH_SET_INIT_INT64(Lookup)
+
/// Start block that may cause vimscript exceptions
static void try_start(void);
@@ -21,6 +27,21 @@ static void try_start(void);
/// @return true if an error occurred
static bool try_end(Error *err);
+/// Convert a vim object to an `Object` instance, recursively expanding
+/// Arrays/Dictionaries.
+///
+/// @param obj The source object
+/// @return The converted value
+static Object vim_to_object(typval_T *vim_obj);
+
+/// 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 vim_push_keys(String str)
{
abort();
@@ -41,7 +62,23 @@ void vim_command(String str, Error *err)
Object vim_eval(String str, Error *err)
{
- abort();
+ Object rv;
+
+ char expr_str[str.size + 1];
+ memcpy(expr_str, str.data, str.size);
+ expr_str[str.size] = NUL;
+ // Evaluate the expression
+ try_start();
+ typval_T *expr_result = eval_expr((char_u *)expr_str, NULL);
+
+ if (!try_end(err)) {
+ // No errors, convert the result
+ rv = vim_to_object(expr_result);
+ }
+
+ // Free the vim object
+ free_tv(expr_result);
+ return rv;
}
int64_t vim_strwidth(String str)
@@ -209,3 +246,118 @@ static bool try_end(Error *err)
return err->set;
}
+
+static 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;
+}