Merge branch 'master' into luaviml'/lua

This commit is contained in:
ZyX
2017-04-08 01:54:58 +03:00
207 changed files with 16096 additions and 9169 deletions

View File

@@ -2,10 +2,11 @@
#include <msgpack.h>
#include "nvim/eval_defs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/ascii.h"
#include "nvim/macros.h"
#include "nvim/message.h"
#include "nvim/globals.h"
#include "nvim/charset.h" // vim_str2nr
@@ -52,16 +53,16 @@ static inline void create_special_dict(typval_T *const rettv,
typval_T val)
FUNC_ATTR_NONNULL_ALL
{
dict_T *const dict = dict_alloc();
dictitem_T *const type_di = dictitem_alloc((char_u *) "_TYPE");
dict_T *const dict = tv_dict_alloc();
dictitem_T *const type_di = tv_dict_item_alloc_len(S_LEN("_TYPE"));
type_di->di_tv.v_type = VAR_LIST;
type_di->di_tv.v_lock = VAR_UNLOCKED;
type_di->di_tv.vval.v_list = (list_T *) eval_msgpack_type_lists[type];
type_di->di_tv.vval.v_list->lv_refcount++;
dict_add(dict, type_di);
dictitem_T *const val_di = dictitem_alloc((char_u *) "_VAL");
tv_dict_add(dict, type_di);
dictitem_T *const val_di = tv_dict_item_alloc_len(S_LEN("_VAL"));
val_di->di_tv = val;
dict_add(dict, val_di);
tv_dict_add(dict, val_di);
dict->dv_refcount++;
*rettv = (typval_T) {
.v_type = VAR_DICT,
@@ -119,18 +120,18 @@ static inline int json_decoder_pop(ValuesStackItem obj,
if (last_container.container.vval.v_list->lv_len != 0
&& !obj.didcomma) {
EMSG2(_("E474: Expected comma before list item: %s"), val_location);
clear_tv(&obj.val);
tv_clear(&obj.val);
return FAIL;
}
assert(last_container.special_val == NULL);
listitem_T *obj_li = listitem_alloc();
listitem_T *obj_li = tv_list_item_alloc();
obj_li->li_tv = obj.val;
list_append(last_container.container.vval.v_list, obj_li);
tv_list_append(last_container.container.vval.v_list, obj_li);
} else if (last_container.stack_index == kv_size(*stack) - 2) {
if (!obj.didcolon) {
EMSG2(_("E474: Expected colon before dictionary value: %s"),
val_location);
clear_tv(&obj.val);
tv_clear(&obj.val);
return FAIL;
}
ValuesStackItem key = kv_pop(*stack);
@@ -139,34 +140,35 @@ static inline int json_decoder_pop(ValuesStackItem obj,
assert(!(key.is_special_string
|| key.val.vval.v_string == NULL
|| *key.val.vval.v_string == NUL));
dictitem_T *obj_di = dictitem_alloc(key.val.vval.v_string);
clear_tv(&key.val);
if (dict_add(last_container.container.vval.v_dict, obj_di)
dictitem_T *const obj_di = tv_dict_item_alloc(
(const char *)key.val.vval.v_string);
tv_clear(&key.val);
if (tv_dict_add(last_container.container.vval.v_dict, obj_di)
== FAIL) {
assert(false);
}
obj_di->di_tv = obj.val;
} else {
list_T *const kv_pair = list_alloc();
list_append_list(last_container.special_val, kv_pair);
listitem_T *const key_li = listitem_alloc();
list_T *const kv_pair = tv_list_alloc();
tv_list_append_list(last_container.special_val, kv_pair);
listitem_T *const key_li = tv_list_item_alloc();
key_li->li_tv = key.val;
list_append(kv_pair, key_li);
listitem_T *const val_li = listitem_alloc();
tv_list_append(kv_pair, key_li);
listitem_T *const val_li = tv_list_item_alloc();
val_li->li_tv = obj.val;
list_append(kv_pair, val_li);
tv_list_append(kv_pair, val_li);
}
} else {
// Object with key only
if (!obj.is_special_string && obj.val.v_type != VAR_STRING) {
EMSG2(_("E474: Expected string key: %s"), *pp);
clear_tv(&obj.val);
tv_clear(&obj.val);
return FAIL;
} else if (!obj.didcomma
&& (last_container.special_val == NULL
&& (DICT_LEN(last_container.container.vval.v_dict) != 0))) {
EMSG2(_("E474: Expected comma before dictionary key: %s"), val_location);
clear_tv(&obj.val);
tv_clear(&obj.val);
return FAIL;
}
// Handle empty key and key represented as special dictionary
@@ -174,16 +176,16 @@ static inline int json_decoder_pop(ValuesStackItem obj,
&& (obj.is_special_string
|| obj.val.vval.v_string == NULL
|| *obj.val.vval.v_string == NUL
|| dict_find(last_container.container.vval.v_dict,
obj.val.vval.v_string, -1))) {
clear_tv(&obj.val);
|| tv_dict_find(last_container.container.vval.v_dict,
(const char *)obj.val.vval.v_string, -1))) {
tv_clear(&obj.val);
// Restart
(void) kv_pop(*container_stack);
ValuesStackItem last_container_val =
kv_A(*stack, last_container.stack_index);
while (kv_size(*stack) > last_container.stack_index) {
clear_tv(&(kv_pop(*stack).val));
tv_clear(&(kv_pop(*stack).val));
}
*pp = last_container.s;
*didcomma = last_container_val.didcomma;
@@ -228,7 +230,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
list_T *decode_create_map_special_dict(typval_T *const ret_tv)
FUNC_ATTR_NONNULL_ALL
{
list_T *const list = list_alloc();
list_T *const list = tv_list_alloc();
list->lv_refcount++;
create_special_dict(ret_tv, kMPMap, ((typval_T) {
.v_type = VAR_LIST,
@@ -264,7 +266,7 @@ typval_T decode_string(const char *const s, const size_t len,
? memchr(s, NUL, len) != NULL
: (bool)hasnul);
if (really_hasnul) {
list_T *const list = list_alloc();
list_T *const list = tv_list_alloc();
list->lv_refcount++;
typval_T tv;
create_special_dict(&tv, binary ? kMPBinary : kMPString, ((typval_T) {
@@ -277,7 +279,7 @@ typval_T decode_string(const char *const s, const size_t len,
xfree((void *)s);
}
if (elw_ret == -1) {
clear_tv(&tv);
tv_clear(&tv);
return (typval_T) { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED };
}
return tv;
@@ -502,9 +504,8 @@ static inline int parse_json_string(vimconv_T *const conv,
str_end = new_str + str_len;
}
*str_end = NUL;
typval_T obj;
obj = decode_string(str, (size_t)(str_end - str), hasnul ? kTrue : kFalse,
false, true);
typval_T obj = decode_string(
str, (size_t)(str_end - str), hasnul ? kTrue : kFalse, false, true);
if (obj.v_type == VAR_UNKNOWN) {
goto parse_json_string_fail;
}
@@ -864,7 +865,7 @@ json_decode_string_cycle_start:
break;
}
case '[': {
list_T *list = list_alloc();
list_T *list = tv_list_alloc();
list->lv_refcount++;
typval_T tv = {
.v_type = VAR_LIST,
@@ -887,7 +888,7 @@ json_decode_string_cycle_start:
next_map_special = false;
val_list = decode_create_map_special_dict(&tv);
} else {
dict_T *dict = dict_alloc();
dict_T *dict = tv_dict_alloc();
dict->dv_refcount++;
tv = (typval_T) {
.v_type = VAR_DICT,
@@ -939,7 +940,7 @@ json_decode_string_after_cycle:
json_decode_string_fail:
ret = FAIL;
while (kv_size(stack)) {
clear_tv(&(kv_pop(stack).val));
tv_clear(&(kv_pop(stack).val));
}
json_decode_string_ret:
kv_destroy(stack);
@@ -985,7 +986,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
.vval = { .v_number = (varnumber_T) mobj.via.u64 },
};
} else {
list_T *const list = list_alloc();
list_T *const list = tv_list_alloc();
list->lv_refcount++;
create_special_dict(rettv, kMPInteger, ((typval_T) {
.v_type = VAR_LIST,
@@ -993,10 +994,10 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
.vval = { .v_list = list },
}));
uint64_t n = mobj.via.u64;
list_append_number(list, 1);
list_append_number(list, (varnumber_T) ((n >> 62) & 0x3));
list_append_number(list, (varnumber_T) ((n >> 31) & 0x7FFFFFFF));
list_append_number(list, (varnumber_T) (n & 0x7FFFFFFF));
tv_list_append_number(list, 1);
tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
}
break;
}
@@ -1008,22 +1009,28 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
.vval = { .v_number = (varnumber_T) mobj.via.i64 },
};
} else {
list_T *const list = list_alloc();
list_T *const list = tv_list_alloc();
list->lv_refcount++;
create_special_dict(rettv, kMPInteger, ((typval_T) {
.v_type = VAR_LIST,
.v_lock = VAR_UNLOCKED,
.vval = { .v_list = list },
}));
uint64_t n = -((uint64_t) mobj.via.i64);
list_append_number(list, -1);
list_append_number(list, (varnumber_T) ((n >> 62) & 0x3));
list_append_number(list, (varnumber_T) ((n >> 31) & 0x7FFFFFFF));
list_append_number(list, (varnumber_T) (n & 0x7FFFFFFF));
uint64_t n = -((uint64_t)mobj.via.i64);
tv_list_append_number(list, -1);
tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
}
break;
}
case MSGPACK_OBJECT_FLOAT: {
#ifdef NVIM_MSGPACK_HAS_FLOAT32
case MSGPACK_OBJECT_FLOAT32:
case MSGPACK_OBJECT_FLOAT64:
#else
case MSGPACK_OBJECT_FLOAT:
#endif
{
*rettv = (typval_T) {
.v_type = VAR_FLOAT,
.v_lock = VAR_UNLOCKED,
@@ -1048,7 +1055,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
break;
}
case MSGPACK_OBJECT_ARRAY: {
list_T *const list = list_alloc();
list_T *const list = tv_list_alloc();
list->lv_refcount++;
*rettv = (typval_T) {
.v_type = VAR_LIST,
@@ -1056,9 +1063,9 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
.vval = { .v_list = list },
};
for (size_t i = 0; i < mobj.via.array.size; i++) {
listitem_T *const li = listitem_alloc();
listitem_T *const li = tv_list_item_alloc();
li->li_tv.v_type = VAR_UNKNOWN;
list_append(list, li);
tv_list_append(list, li);
if (msgpack_to_vim(mobj.via.array.ptr[i], &li->li_tv) == FAIL) {
return FAIL;
}
@@ -1074,7 +1081,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
goto msgpack_to_vim_generic_map;
}
}
dict_T *const dict = dict_alloc();
dict_T *const dict = tv_dict_alloc();
dict->dv_refcount++;
*rettv = (typval_T) {
.v_type = VAR_DICT,
@@ -1087,9 +1094,9 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
memcpy(&di->di_key[0], mobj.via.map.ptr[i].key.via.str.ptr,
mobj.via.map.ptr[i].key.via.str.size);
di->di_tv.v_type = VAR_UNKNOWN;
if (dict_add(dict, di) == FAIL) {
if (tv_dict_add(dict, di) == FAIL) {
// Duplicate key: fallback to generic map
clear_tv(rettv);
tv_clear(rettv);
xfree(di);
goto msgpack_to_vim_generic_map;
}
@@ -1101,14 +1108,14 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
msgpack_to_vim_generic_map: {}
list_T *const list = decode_create_map_special_dict(rettv);
for (size_t i = 0; i < mobj.via.map.size; i++) {
list_T *const kv_pair = list_alloc();
list_append_list(list, kv_pair);
listitem_T *const key_li = listitem_alloc();
list_T *const kv_pair = tv_list_alloc();
tv_list_append_list(list, kv_pair);
listitem_T *const key_li = tv_list_item_alloc();
key_li->li_tv.v_type = VAR_UNKNOWN;
list_append(kv_pair, key_li);
listitem_T *const val_li = listitem_alloc();
tv_list_append(kv_pair, key_li);
listitem_T *const val_li = tv_list_item_alloc();
val_li->li_tv.v_type = VAR_UNKNOWN;
list_append(kv_pair, val_li);
tv_list_append(kv_pair, val_li);
if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_li->li_tv) == FAIL) {
return FAIL;
}
@@ -1119,11 +1126,11 @@ msgpack_to_vim_generic_map: {}
break;
}
case MSGPACK_OBJECT_EXT: {
list_T *const list = list_alloc();
list_T *const list = tv_list_alloc();
list->lv_refcount++;
list_append_number(list, mobj.via.ext.type);
list_T *const ext_val_list = list_alloc();
list_append_list(list, ext_val_list);
tv_list_append_number(list, mobj.via.ext.type);
list_T *const ext_val_list = tv_list_alloc();
tv_list_append_list(list, ext_val_list);
create_special_dict(rettv, kMPExt, ((typval_T) {
.v_type = VAR_LIST,
.v_lock = VAR_UNLOCKED,

View File

@@ -5,7 +5,7 @@
#include <msgpack.h>
#include "nvim/eval_defs.h"
#include "nvim/eval/typval.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/decode.h.generated.h"

View File

@@ -13,7 +13,7 @@
#include "nvim/eval/encode.h"
#include "nvim/buffer_defs.h" // vimconv_T
#include "nvim/eval.h"
#include "nvim/eval_defs.h"
#include "nvim/eval/typval.h"
#include "nvim/garray.h"
#include "nvim/mbyte.h"
#include "nvim/message.h"
@@ -45,7 +45,8 @@ const char *const encode_special_var_names[] = {
#endif
/// Msgpack callback for writing to readfile()-style list
int encode_list_write(void *data, const char *buf, size_t len)
int encode_list_write(void *const data, const char *const buf, const size_t len)
FUNC_ATTR_NONNULL_ARG(1)
{
if (len == 0) {
return 0;
@@ -80,11 +81,11 @@ int encode_list_write(void *data, const char *buf, size_t len)
str = xmemdupz(line_start, line_length);
memchrsub(str, NUL, NL, line_length);
}
list_append_allocated_string(list, str);
tv_list_append_allocated_string(list, str);
line_end++;
}
if (line_end == end) {
list_append_allocated_string(list, NULL);
tv_list_append_allocated_string(list, NULL);
}
return 0;
}
@@ -743,11 +744,11 @@ bool encode_check_json_key(const typval_T *const tv)
}
const dictitem_T *type_di;
const dictitem_T *val_di;
if ((type_di = dict_find((dict_T *) spdict, (char_u *) "_TYPE", -1)) == NULL
if ((type_di = tv_dict_find(spdict, S_LEN("_TYPE"))) == NULL
|| type_di->di_tv.v_type != VAR_LIST
|| (type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPString]
&& type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPBinary])
|| (val_di = dict_find((dict_T *) spdict, (char_u *) "_VAL", -1)) == NULL
|| (val_di = tv_dict_find(spdict, S_LEN("_VAL"))) == NULL
|| val_di->di_tv.v_type != VAR_LIST) {
return false;
}

115
src/nvim/eval/executor.c Normal file
View File

@@ -0,0 +1,115 @@
#include "nvim/eval/typval.h"
#include "nvim/eval/executor.h"
#include "nvim/eval.h"
#include "nvim/message.h"
#include "nvim/vim.h"
#include "nvim/globals.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/executor.c.generated.h"
#endif
static char *e_letwrong = N_("E734: Wrong variable type for %s=");
char *e_listidx = N_("E684: list index out of range: %" PRId64);
/// Hanle tv1 += tv2, -=, .=
///
/// @param[in,out] tv1 First operand, modified typval.
/// @param[in] tv2 Second operand.
/// @param[in] op Used operator.
///
/// @return OK or FAIL.
int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2,
const char *const op)
FUNC_ATTR_NONNULL_ALL
{
// Can't do anything with a Funcref, a Dict or special value on the right.
if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT) {
switch (tv1->v_type) {
case VAR_DICT:
case VAR_FUNC:
case VAR_PARTIAL:
case VAR_SPECIAL: {
break;
}
case VAR_LIST: {
if (*op != '+' || tv2->v_type != VAR_LIST) {
break;
}
// List += List
if (tv1->vval.v_list != NULL && tv2->vval.v_list != NULL) {
tv_list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL);
}
return OK;
}
case VAR_NUMBER:
case VAR_STRING: {
if (tv2->v_type == VAR_LIST) {
break;
}
if (*op == '+' || *op == '-') {
// nr += nr or nr -= nr
varnumber_T n = tv_get_number(tv1);
if (tv2->v_type == VAR_FLOAT) {
float_T f = n;
if (*op == '+') {
f += tv2->vval.v_float;
} else {
f -= tv2->vval.v_float;
}
tv_clear(tv1);
tv1->v_type = VAR_FLOAT;
tv1->vval.v_float = f;
} else {
if (*op == '+') {
n += tv_get_number(tv2);
} else {
n -= tv_get_number(tv2);
}
tv_clear(tv1);
tv1->v_type = VAR_NUMBER;
tv1->vval.v_number = n;
}
} else {
// str .= str
if (tv2->v_type == VAR_FLOAT) {
break;
}
const char *tvs = tv_get_string(tv1);
char numbuf[NUMBUFLEN];
char *const s = (char *)concat_str(
(const char_u *)tvs, (const char_u *)tv_get_string_buf(tv2,
numbuf));
tv_clear(tv1);
tv1->v_type = VAR_STRING;
tv1->vval.v_string = (char_u *)s;
}
return OK;
}
case VAR_FLOAT: {
if (*op == '.' || (tv2->v_type != VAR_FLOAT
&& tv2->v_type != VAR_NUMBER
&& tv2->v_type != VAR_STRING)) {
break;
}
const float_T f = (tv2->v_type == VAR_FLOAT
? tv2->vval.v_float
: tv_get_number(tv2));
if (*op == '+') {
tv1->vval.v_float += f;
} else {
tv1->vval.v_float -= f;
}
return OK;
}
case VAR_UNKNOWN: {
assert(false);
}
}
}
EMSG2(_(e_letwrong), op);
return FAIL;
}

11
src/nvim/eval/executor.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef NVIM_EVAL_EXECUTOR_H
#define NVIM_EVAL_EXECUTOR_H
#include "nvim/eval/typval.h"
extern char *e_listidx;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/executor.h.generated.h"
#endif
#endif // NVIM_EVAL_EXECUTOR_H

11
src/nvim/eval/gc.c Normal file
View File

@@ -0,0 +1,11 @@
#include "nvim/eval/typval.h"
#include "nvim/eval/gc.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/gc.c.generated.h"
#endif
/// Head of list of all dictionaries
dict_T *gc_first_dict = NULL;
/// Head of list of all lists
list_T *gc_first_list = NULL;

12
src/nvim/eval/gc.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef NVIM_EVAL_GC_H
#define NVIM_EVAL_GC_H
#include "nvim/eval/typval.h"
extern dict_T *gc_first_dict;
extern list_T *gc_first_list;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/gc.h.generated.h"
#endif
#endif // NVIM_EVAL_GC_H

2556
src/nvim/eval/typval.c Normal file

File diff suppressed because it is too large Load Diff

429
src/nvim/eval/typval.h Normal file
View File

@@ -0,0 +1,429 @@
#ifndef NVIM_EVAL_TYPVAL_H
#define NVIM_EVAL_TYPVAL_H
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "nvim/types.h"
#include "nvim/hashtab.h"
#include "nvim/garray.h"
#include "nvim/mbyte.h"
#include "nvim/func_attr.h"
#include "nvim/lib/queue.h"
#include "nvim/profile.h" // for proftime_T
#include "nvim/pos.h" // for linenr_T
#include "nvim/gettext.h"
#include "nvim/message.h"
/// Type used for VimL VAR_NUMBER values
typedef int varnumber_T;
/// Type used for VimL VAR_FLOAT values
typedef double float_T;
/// Maximal possible value of varnumber_T variable
#define VARNUMBER_MAX INT_MAX
/// Mimimal possible value of varnumber_T variable
#define VARNUMBER_MIN INT_MIN
#define PRIdVARNUMBER "d"
/// %d printf format specifier for varnumber_T
#define PRIdVARNUMBER "d"
typedef struct listvar_S list_T;
typedef struct dictvar_S dict_T;
typedef struct partial_S partial_T;
typedef struct ufunc ufunc_T;
typedef enum {
kCallbackNone,
kCallbackFuncref,
kCallbackPartial,
} CallbackType;
typedef struct {
union {
char_u *funcref;
partial_T *partial;
} data;
CallbackType type;
} Callback;
#define CALLBACK_NONE ((Callback){ .type = kCallbackNone })
/// Structure holding dictionary watcher
typedef struct dict_watcher {
Callback callback;
char *key_pattern;
size_t key_pattern_len;
QUEUE node;
bool busy; // prevent recursion if the dict is changed in the callback
} DictWatcher;
/// Special variable values
typedef enum {
kSpecialVarFalse, ///< v:false
kSpecialVarTrue, ///< v:true
kSpecialVarNull, ///< v:null
} SpecialVarValue;
/// Variable lock status for typval_T.v_lock
typedef enum {
VAR_UNLOCKED = 0, ///< Not locked.
VAR_LOCKED = 1, ///< User lock, can be unlocked.
VAR_FIXED = 2, ///< Locked forever.
} VarLockStatus;
/// VimL variable types, for use in typval_T.v_type
typedef enum {
VAR_UNKNOWN = 0, ///< Unknown (unspecified) value.
VAR_NUMBER, ///< Number, .v_number is used.
VAR_STRING, ///< String, .v_string is used.
VAR_FUNC, ///< Function reference, .v_string is used as function name.
VAR_LIST, ///< List, .v_list is used.
VAR_DICT, ///< Dictionary, .v_dict is used.
VAR_FLOAT, ///< Floating-point value, .v_float is used.
VAR_SPECIAL, ///< Special value (true, false, null), .v_special
///< is used.
VAR_PARTIAL, ///< Partial, .v_partial is used.
} VarType;
/// Structure that holds an internal variable value
typedef struct {
VarType v_type; ///< Variable type.
VarLockStatus v_lock; ///< Variable lock status.
union typval_vval_union {
varnumber_T v_number; ///< Number, for VAR_NUMBER.
SpecialVarValue v_special; ///< Special value, for VAR_SPECIAL.
float_T v_float; ///< Floating-point number, for VAR_FLOAT.
char_u *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL.
list_T *v_list; ///< List for VAR_LIST, can be NULL.
dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL.
partial_T *v_partial; ///< Closure: function with args.
} vval; ///< Actual value.
} typval_T;
/// Values for (struct dictvar_S).dv_scope
typedef enum {
VAR_NO_SCOPE = 0, ///< Not a scope dictionary.
VAR_SCOPE = 1, ///< Scope dictionary which requires prefix (a:, v:, …).
VAR_DEF_SCOPE = 2, ///< Scope dictionary which may be accessed without prefix
///< (l:, g:).
} ScopeType;
/// Structure to hold an item of a list
typedef struct listitem_S listitem_T;
struct listitem_S {
listitem_T *li_next; ///< Next item in list.
listitem_T *li_prev; ///< Previous item in list.
typval_T li_tv; ///< Item value.
};
/// Structure used by those that are using an item in a list
typedef struct listwatch_S listwatch_T;
struct listwatch_S {
listitem_T *lw_item; ///< Item being watched.
listwatch_T *lw_next; ///< Next watcher.
};
/// Structure to hold info about a list
struct listvar_S {
listitem_T *lv_first; ///< First item, NULL if none.
listitem_T *lv_last; ///< Last item, NULL if none.
int lv_refcount; ///< Reference count.
int lv_len; ///< Number of items.
listwatch_T *lv_watch; ///< First watcher, NULL if none.
int lv_idx; ///< Index of a cached item, used for optimising repeated l[idx].
listitem_T *lv_idx_item; ///< When not NULL item at index "lv_idx".
int lv_copyID; ///< ID used by deepcopy().
list_T *lv_copylist; ///< Copied list used by deepcopy().
VarLockStatus lv_lock; ///< Zero, VAR_LOCKED, VAR_FIXED.
list_T *lv_used_next; ///< next list in used lists list.
list_T *lv_used_prev; ///< Previous list in used lists list.
};
// Static list with 10 items. Use init_static_list() to initialize.
typedef struct {
list_T sl_list; // must be first
listitem_T sl_items[10];
} staticList10_T;
// Structure to hold an item of a Dictionary.
// Also used for a variable.
// The key is copied into "di_key" to avoid an extra alloc/free for it.
struct dictitem_S {
typval_T di_tv; ///< type and value of the variable
char_u di_flags; ///< flags (only used for variable)
char_u di_key[1]; ///< key (actually longer!)
};
#define TV_DICTITEM_STRUCT(KEY_LEN) \
struct { \
typval_T di_tv; /* Structure that holds scope dictionary itself. */ \
uint8_t di_flags; /* Flags. */ \
char_u di_key[KEY_LEN]; /* Key value. */ \
}
/// Structure to hold a scope dictionary
///
/// @warning Must be compatible with dictitem_T.
///
/// For use in find_var_in_ht to pretend that it found dictionary item when it
/// finds scope dictionary.
typedef TV_DICTITEM_STRUCT(1) ScopeDictDictItem;
/// Structure to hold an item of a Dictionary
///
/// @warning Must be compatible with ScopeDictDictItem.
///
/// Also used for a variable.
typedef TV_DICTITEM_STRUCT() dictitem_T;
/// Flags for dictitem_T.di_flags
typedef enum {
DI_FLAGS_RO = 1, ///< Read-only value
DI_FLAGS_RO_SBX = 2, ///< Value, read-only in the sandbox
DI_FLAGS_FIX = 4, ///< Fixed value: cannot be :unlet or remove()d.
DI_FLAGS_LOCK = 8, ///< Locked value.
DI_FLAGS_ALLOC = 16, ///< Separately allocated.
} DictItemFlags;
/// Structure representing a Dictionary
struct dictvar_S {
VarLockStatus dv_lock; ///< Whole dictionary lock status.
ScopeType dv_scope; ///< Non-zero (#VAR_SCOPE, #VAR_DEF_SCOPE) if
///< dictionary represents a scope (i.e. g:, l: …).
int dv_refcount; ///< Reference count.
int dv_copyID; ///< ID used when recursivery traversing a value.
hashtab_T dv_hashtab; ///< Hashtab containing all items.
dict_T *dv_copydict; ///< Copied dict used by deepcopy().
dict_T *dv_used_next; ///< Next dictionary in used dictionaries list.
dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list.
QUEUE watchers; ///< Dictionary key watchers set by user code.
};
/// Type used for script ID
typedef int scid_T;
/// Format argument for scid_T
#define PRIdSCID "d"
// Structure to hold info for a function that is currently being executed.
typedef struct funccall_S funccall_T;
/// Structure to hold info for a user function.
struct ufunc {
int uf_varargs; ///< variable nr of arguments
int uf_flags;
int uf_calls; ///< nr of active calls
bool uf_cleared; ///< func_clear() was already called
garray_T uf_args; ///< arguments
garray_T uf_lines; ///< function lines
int uf_profiling; ///< true when func is being profiled
// Profiling the function as a whole.
int uf_tm_count; ///< nr of calls
proftime_T uf_tm_total; ///< time spent in function + children
proftime_T uf_tm_self; ///< time spent in function itself
proftime_T uf_tm_children; ///< time spent in children this call
// Profiling the function per line.
int *uf_tml_count; ///< nr of times line was executed
proftime_T *uf_tml_total; ///< time spent in a line + children
proftime_T *uf_tml_self; ///< time spent in a line itself
proftime_T uf_tml_start; ///< start time for current line
proftime_T uf_tml_children; ///< time spent in children for this line
proftime_T uf_tml_wait; ///< start wait time for current line
int uf_tml_idx; ///< index of line being timed; -1 if none
int uf_tml_execed; ///< line being timed was executed
scid_T uf_script_ID; ///< ID of script where function was defined,
///< used for s: variables
int uf_refcount; ///< reference count, see func_name_refcount()
funccall_T *uf_scoped; ///< l: local variables for closure
char_u uf_name[1]; ///< name of function (actually longer); can
///< start with <SNR>123_ (<SNR> is K_SPECIAL
///< KS_EXTRA KE_SNR)
};
/// Maximum number of function arguments
#define MAX_FUNC_ARGS 20
struct partial_S {
int pt_refcount; ///< Reference count.
char_u *pt_name; ///< Function name; when NULL use pt_func->name.
ufunc_T *pt_func; ///< Function pointer; when NULL lookup function with
///< pt_name.
bool pt_auto; ///< When true the partial was created by using dict.member
///< in handle_subscript().
int pt_argc; ///< Number of arguments.
typval_T *pt_argv; ///< Arguments in allocated array.
dict_T *pt_dict; ///< Dict for "self".
};
/// Structure used for explicit stack while garbage collecting hash tables
typedef struct ht_stack_S {
hashtab_T *ht;
struct ht_stack_S *prev;
} ht_stack_T;
/// Structure used for explicit stack while garbage collecting lists
typedef struct list_stack_S {
list_T *list;
struct list_stack_S *prev;
} list_stack_T;
// In a hashtab item "hi_key" points to "di_key" in a dictitem.
// This avoids adding a pointer to the hashtab item.
/// Convert a hashitem pointer to a dictitem pointer
#define TV_DICT_HI2DI(hi) \
((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key)))
static inline long tv_list_len(const list_T *const l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get the number of items in a list
///
/// @param[in] l List to check.
static inline long tv_list_len(const list_T *const l)
{
if (l == NULL) {
return 0;
}
return l->lv_len;
}
static inline long tv_dict_len(const dict_T *const d)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get the number of items in a Dictionary
///
/// @param[in] d Dictionary to check.
static inline long tv_dict_len(const dict_T *const d)
{
if (d == NULL) {
return 0L;
}
return (long)d->dv_hashtab.ht_used;
}
static inline bool tv_dict_is_watched(const dict_T *const d)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Check if dictionary is watched
///
/// @param[in] d Dictionary to check.
///
/// @return true if there is at least one watcher.
static inline bool tv_dict_is_watched(const dict_T *const d)
{
return d && !QUEUE_EMPTY(&d->watchers);
}
/// Initialize VimL object
///
/// Initializes to unlocked VAR_UNKNOWN object.
///
/// @param[out] tv Object to initialize.
static inline void tv_init(typval_T *const tv)
{
if (tv != NULL) {
memset(tv, 0, sizeof(*tv));
}
}
#define TV_INITIAL_VALUE \
((typval_T) { \
.v_type = VAR_UNKNOWN, \
.v_lock = VAR_UNLOCKED, \
})
/// Empty string
///
/// Needed for hack which allows not allocating empty string and still not
/// crashing when freeing it.
extern const char *const tv_empty_string;
/// Specifies that free_unref_items() function has (not) been entered
extern bool tv_in_free_unref_items;
/// Iterate over a dictionary
///
/// @param[in] d Dictionary to iterate over.
/// @param di Name of the variable with current dictitem_T entry.
/// @param code Cycle body.
#define TV_DICT_ITER(d, di, code) \
HASHTAB_ITER(&(d)->dv_hashtab, di##hi_, { \
{ \
dictitem_T *const di = TV_DICT_HI2DI(di##hi_); \
{ \
code \
} \
} \
})
static inline bool tv_get_float_chk(const typval_T *const tv,
float_T *const ret_f)
REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
// FIXME circular dependency, cannot import message.h.
bool emsgf(const char *const fmt, ...);
/// Get the float value
///
/// Raises an error if object is not number or floating-point.
///
/// @param[in] tv VimL object to get value from.
/// @param[out] ret_f Location where resulting float is stored.
///
/// @return true in case of success, false if tv is not a number or float.
static inline bool tv_get_float_chk(const typval_T *const tv,
float_T *const ret_f)
{
if (tv->v_type == VAR_FLOAT) {
*ret_f = tv->vval.v_float;
return true;
}
if (tv->v_type == VAR_NUMBER) {
*ret_f = (float_T)tv->vval.v_number;
return true;
}
emsgf(_("E808: Number or Float required"));
return false;
}
static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
REAL_FATTR_NONNULL_ALL REAL_FATTR_NONNULL_RET REAL_FATTR_PURE
REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE;
/// Compute the `DictWatcher` address from a QUEUE node.
///
/// This only exists for .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer
/// arithmetic).
static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
{
return QUEUE_DATA(q, DictWatcher, node);
}
static inline bool tv_is_func(const typval_T tv)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST;
/// Check whether given typval_T contains a function
///
/// That is, whether it contains VAR_FUNC or VAR_PARTIAL.
///
/// @param[in] tv Typval to check.
///
/// @return True if it is a function or a partial, false otherwise.
static inline bool tv_is_func(const typval_T tv)
{
return tv.v_type == VAR_FUNC || tv.v_type == VAR_PARTIAL;
}
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/typval.h.generated.h"
#endif
#endif // NVIM_EVAL_TYPVAL_H

View File

@@ -238,7 +238,7 @@
#include <assert.h>
#include "nvim/lib/kvec.h"
#include "nvim/eval_defs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/encode.h"
#include "nvim/func_attr.h"
#include "nvim/eval/typval_encode.h"
@@ -402,11 +402,11 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
const dictitem_T *val_di;
if (TYPVAL_ENCODE_ALLOW_SPECIALS
&& tv->vval.v_dict->dv_hashtab.ht_used == 2
&& (type_di = dict_find((dict_T *)tv->vval.v_dict,
(char_u *)"_TYPE", -1)) != NULL
&& (type_di = tv_dict_find((dict_T *)tv->vval.v_dict,
S_LEN("_TYPE"))) != NULL
&& type_di->di_tv.v_type == VAR_LIST
&& (val_di = dict_find((dict_T *)tv->vval.v_dict,
(char_u *)"_VAL", -1)) != NULL) {
&& (val_di = tv_dict_find((dict_T *)tv->vval.v_dict,
S_LEN("_VAL"))) != NULL) {
size_t i;
for (i = 0; i < ARRAY_SIZE(eval_msgpack_type_lists); i++) {
if (type_di->di_tv.vval.v_list == eval_msgpack_type_lists[i]) {
@@ -658,7 +658,7 @@ typval_encode_stop_converting_one_item:
while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) {
cur_mpsv->data.d.hi++;
}
dictitem_T *const di = HI2DI(cur_mpsv->data.d.hi);
dictitem_T *const di = TV_DICT_HI2DI(cur_mpsv->data.d.hi);
cur_mpsv->data.d.todo--;
cur_mpsv->data.d.hi++;
TYPVAL_ENCODE_CONV_STR_STRING(NULL, &di->di_key[0],

View File

@@ -11,7 +11,7 @@
#include <assert.h>
#include "nvim/lib/kvec.h"
#include "nvim/eval_defs.h"
#include "nvim/eval/typval.h"
#include "nvim/func_attr.h"
/// Type of the stack entry