aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/private/helpers.c20
-rw-r--r--src/nvim/encode.c31
-rw-r--r--src/nvim/encode.h3
-rw-r--r--src/nvim/eval.c209
-rw-r--r--src/nvim/eval.h12
-rw-r--r--src/nvim/eval_defs.h47
-rw-r--r--src/nvim/version.c14
7 files changed, 225 insertions, 111 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index c770618ce4..a8082655fd 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -651,6 +651,22 @@ static Object vim_to_object_rec(typval_T *obj, PMap(ptr_t) *lookup)
}
switch (obj->v_type) {
+ case VAR_SPECIAL:
+ switch (obj->vval.v_special) {
+ case kSpecialVarTrue:
+ case kSpecialVarFalse: {
+ rv.type = kObjectTypeBoolean;
+ rv.data.boolean = (obj->vval.v_special == kSpecialVarTrue);
+ break;
+ }
+ case kSpecialVarNull:
+ case kSpecialVarNone: {
+ rv.type = kObjectTypeNil;
+ break;
+ }
+ }
+ break;
+
case VAR_STRING:
rv.type = kObjectTypeString;
rv.data.string = cstr_to_string((char *) obj->vval.v_string);
@@ -730,6 +746,10 @@ static Object vim_to_object_rec(typval_T *obj, PMap(ptr_t) *lookup)
}
}
break;
+
+ case VAR_UNKNOWN:
+ case VAR_FUNC:
+ break;
}
return rv;
diff --git a/src/nvim/encode.c b/src/nvim/encode.c
index 6fdbe67ec8..c80e9783e0 100644
--- a/src/nvim/encode.c
+++ b/src/nvim/encode.c
@@ -8,10 +8,12 @@
#include <msgpack.h>
#include <inttypes.h>
+#include <assert.h>
#include "nvim/encode.h"
#include "nvim/buffer_defs.h" // vimconv_T
#include "nvim/eval.h"
+#include "nvim/eval_defs.h"
#include "nvim/garray.h"
#include "nvim/mbyte.h"
#include "nvim/message.h"
@@ -53,6 +55,13 @@ typedef struct {
/// Stack used to convert VimL values to messagepack.
typedef kvec_t(MPConvStackVal) MPConvStack;
+const char *const encode_special_var_names[] = {
+ [kSpecialVarNull] = "null",
+ [kSpecialVarNone] = "none",
+ [kSpecialVarTrue] = "true",
+ [kSpecialVarFalse] = "false",
+};
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "encode.c.generated.h"
#endif
@@ -355,7 +364,7 @@ static int name##_convert_one_value(firstargtype firstargname, \
break; \
} \
case kSpecialVarNone: { \
- CONV_NONE(); \
+ CONV_NONE_VAL(); \
break; \
} \
} \
@@ -558,8 +567,7 @@ scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \
const char *const objname) \
FUNC_ATTR_WARN_UNUSED_RESULT \
{ \
- current_copyID += COPYID_INC; \
- const int copyID = current_copyID; \
+ const int copyID = get_copyID(); \
MPConvStack mpstack; \
kv_init(mpstack); \
if (name##_convert_one_value(firstargname, &mpstack, tv, copyID, objname) \
@@ -717,13 +725,13 @@ encode_vim_to_##name##_error_ret: \
ga_concat(gap, "{}")
#define CONV_NIL() \
- ga_append(gap, "v:null")
+ ga_concat(gap, "v:null")
#define CONV_BOOL(num) \
- ga_append(gap, ((num)? "v:true": "v:false"))
+ ga_concat(gap, ((num)? "v:true": "v:false"))
-#define CONV_NONE() \
- ga_append(gap, "v:none")
+#define CONV_NONE_VAL() \
+ ga_concat(gap, "v:none")
#define CONV_UNSIGNED_NUMBER(num)
@@ -1069,8 +1077,8 @@ static inline bool check_json_key(const typval_T *const tv)
} \
} while (0)
-#undef CONV_NONE
-#define CONV_NONE()
+#undef CONV_NONE_VAL
+#define CONV_NONE_VAL()
DEFINE_VIML_CONV_FUNCTIONS(static, json, garray_T *const, gap)
@@ -1085,7 +1093,7 @@ DEFINE_VIML_CONV_FUNCTIONS(static, json, garray_T *const, gap)
#undef CONV_EMPTY_DICT
#undef CONV_NIL
#undef CONV_BOOL
-#undef CONV_NONE
+#undef CONV_NONE_VAL
#undef CONV_UNSIGNED_NUMBER
#undef CONV_DICT_START
#undef CONV_DICT_END
@@ -1221,7 +1229,7 @@ char *encode_tv2json(typval_T *tv, size_t *len)
#define CONV_NIL() \
msgpack_pack_nil(packer)
-#define CONV_NONE() \
+#define CONV_NONE_VAL() \
return conv_error(_("E953: Attempt to convert v:none in %s, %s"), \
mpstack, objname)
@@ -1272,6 +1280,7 @@ DEFINE_VIML_CONV_FUNCTIONS(, msgpack, msgpack_packer *const, packer)
#undef CONV_EMPTY_DICT
#undef CONV_NIL
#undef CONV_BOOL
+#undef CONV_NONE_VAL
#undef CONV_UNSIGNED_NUMBER
#undef CONV_DICT_START
#undef CONV_DICT_END
diff --git a/src/nvim/encode.h b/src/nvim/encode.h
index 799850aab9..5b81ed84dc 100644
--- a/src/nvim/encode.h
+++ b/src/nvim/encode.h
@@ -51,6 +51,9 @@ static inline ListReaderState encode_init_lrstate(const list_T *const list)
};
}
+/// Array mapping values from SpecialVarValue enum to names
+extern const char *const encode_special_var_names[];
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "encode.h.generated.h"
#endif
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 114368d621..819b3059e2 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -178,8 +178,6 @@ static dictitem_T globvars_var; /* variable used for g: */
*/
static hashtab_T compat_hashtab;
-int current_copyID = 0;
-
hashtab_T func_hashtab;
/*
@@ -366,11 +364,16 @@ static struct vimvar {
{ VV_NAME("errors", VAR_LIST), 0 },
{ VV_NAME("msgpack_types", VAR_DICT), VV_RO },
{ VV_NAME("event", VAR_DICT), VV_RO },
+ { VV_NAME("false", VAR_SPECIAL), VV_RO },
+ { VV_NAME("true", VAR_SPECIAL), VV_RO },
+ { VV_NAME("null", VAR_SPECIAL), VV_RO },
+ { VV_NAME("none", VAR_SPECIAL), VV_RO },
};
/* shorthand */
#define vv_type vv_di.di_tv.v_type
#define vv_nr vv_di.di_tv.vval.v_number
+#define vv_special vv_di.di_tv.vval.v_special
#define vv_float vv_di.di_tv.vval.v_float
#define vv_str vv_di.di_tv.vval.v_string
#define vv_list vv_di.di_tv.vval.v_list
@@ -506,7 +509,13 @@ void eval_init(void)
set_vim_var_list(VV_ERRORS, list_alloc());
set_vim_var_nr(VV_SEARCHFORWARD, 1L);
set_vim_var_nr(VV_HLSEARCH, 1L);
- set_reg_var(0); /* default for v:register is not 0 but '"' */
+
+ set_vim_var_special(VV_FALSE, kSpecialVarFalse);
+ set_vim_var_special(VV_TRUE, kSpecialVarTrue);
+ set_vim_var_special(VV_NONE, kSpecialVarNone);
+ set_vim_var_special(VV_NULL, kSpecialVarNull);
+
+ set_reg_var(0); // default for v:register is not 0 but '"'
}
#if defined(EXITFREE)
@@ -2368,11 +2377,12 @@ static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
char_u numbuf[NUMBUFLEN];
char_u *s;
- /* Can't do anything with a Funcref or a Dict on the right. */
+ // 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_SPECIAL:
break;
case VAR_LIST:
@@ -2440,6 +2450,9 @@ static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
tv1->vval.v_float -= f;
}
return OK;
+
+ case VAR_UNKNOWN:
+ assert(false);
}
}
@@ -3077,6 +3090,15 @@ static void item_lock(typval_T *tv, int deep, int lock)
}
}
}
+ break;
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_STRING:
+ case VAR_FUNC:
+ case VAR_SPECIAL:
+ break;
+ case VAR_UNKNOWN:
+ assert(false);
}
--recurse;
}
@@ -4306,6 +4328,11 @@ eval_index (
if (verbose)
EMSG(_(e_float_as_string));
return FAIL;
+ } else if (rettv->v_type == VAR_SPECIAL) {
+ if (verbose) {
+ EMSG(_("E15: Cannot index a special value"));
+ }
+ return FAIL;
}
init_tv(&var1);
@@ -4496,6 +4523,11 @@ eval_index (
*rettv = var1;
}
break;
+ case VAR_FUNC:
+ case VAR_FLOAT:
+ case VAR_UNKNOWN:
+ case VAR_SPECIAL:
+ assert(false);
}
}
@@ -5040,6 +5072,12 @@ tv_equal (
s1 = get_tv_string_buf(tv1, buf1);
s2 = get_tv_string_buf(tv2, buf2);
return (ic ? mb_stricmp(s1, s2) : STRCMP(s1, s2)) == 0;
+
+ case VAR_SPECIAL:
+ return tv1->vval.v_special == tv2->vval.v_special;
+
+ case VAR_UNKNOWN:
+ break;
}
EMSG2(_(e_intern2), "tv_equal()");
@@ -5505,6 +5543,22 @@ static int list_join(garray_T *const gap, list_T *const l,
return retval;
}
+/// Get next (unique) copy ID
+///
+/// Used for traversing nested structures e.g. when serializing them or garbage
+/// collecting.
+int get_copyID(void)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // CopyID for recursively traversing lists and dicts
+ //
+ // This value is needed to avoid endless recursiveness. Last bit is used for
+ // previous_funccal and normally ignored when comparing.
+ static int current_copyID = 0;
+ current_copyID += COPYID_INC;
+ return current_copyID;
+}
+
/*
* Garbage collection for lists and dictionaries.
*
@@ -5540,8 +5594,7 @@ bool garbage_collect(void)
// We advance by two because we add one for items referenced through
// previous_funccal.
- current_copyID += COPYID_INC;
- int copyID = current_copyID;
+ const int copyID = get_copyID();
// 1. Go through all accessible variables and mark all lists and dicts
// with copyID.
@@ -5886,6 +5939,15 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack,
}
break;
}
+
+ case VAR_FUNC:
+ case VAR_UNKNOWN:
+ case VAR_SPECIAL:
+ case VAR_FLOAT:
+ case VAR_NUMBER:
+ case VAR_STRING: {
+ break;
+ }
}
return abort;
}
@@ -8260,9 +8322,8 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv)
if (noref < 0 || noref > 1)
EMSG(_(e_invarg));
else {
- current_copyID += COPYID_INC;
var_item_copy(NULL, &argvars[0], rettv, true, (noref == 0
- ? current_copyID
+ ? get_copyID()
: 0));
}
}
@@ -8477,7 +8538,7 @@ static void f_empty(typval_T *argvars, typval_T *rettv)
case VAR_SPECIAL:
n = argvars[0].vval.v_special != kSpecialVarTrue;
break;
- default:
+ case VAR_UNKNOWN:
EMSG2(_(e_intern2), "f_empty()");
n = 0;
}
@@ -16386,13 +16447,28 @@ static void f_type(typval_T *argvars, typval_T *rettv)
int n;
switch (argvars[0].v_type) {
- case VAR_NUMBER: n = 0; break;
- case VAR_STRING: n = 1; break;
- case VAR_FUNC: n = 2; break;
- case VAR_LIST: n = 3; break;
- case VAR_DICT: n = 4; break;
- case VAR_FLOAT: n = 5; break;
- default: EMSG2(_(e_intern2), "f_type()"); n = 0; break;
+ case VAR_NUMBER: n = 0; break;
+ case VAR_STRING: n = 1; break;
+ case VAR_FUNC: n = 2; break;
+ case VAR_LIST: n = 3; break;
+ case VAR_DICT: n = 4; break;
+ case VAR_FLOAT: n = 5; break;
+ case VAR_SPECIAL: {
+ switch (argvars[0].vval.v_special) {
+ case kSpecialVarTrue:
+ case kSpecialVarFalse: {
+ n = 6;
+ break;
+ }
+ case kSpecialVarNone:
+ case kSpecialVarNull: {
+ n = 7;
+ break;
+ }
+ }
+ break;
+ }
+ case VAR_UNKNOWN: EMSG2(_(e_intern2), "f_type()"); n = 0; break;
}
rettv->vval.v_number = n;
}
@@ -17226,6 +17302,12 @@ void set_vim_var_nr(int idx, long val)
vimvars[idx].vv_nr = val;
}
+/// Set special v: variable to "val"
+void set_vim_var_special(const int idx, const SpecialVarValue val)
+{
+ vimvars[idx].vv_special = val;
+}
+
/*
* Get number v: variable value.
*/
@@ -17574,7 +17656,7 @@ handle_subscript (
void free_tv(typval_T *varp)
{
if (varp != NULL) {
- switch ((VarType) varp->v_type) {
+ switch (varp->v_type) {
case VAR_FUNC:
func_unref(varp->vval.v_string);
/*FALLTHROUGH*/
@@ -17592,9 +17674,6 @@ void free_tv(typval_T *varp)
case VAR_FLOAT:
case VAR_UNKNOWN:
break;
- default:
- EMSG2(_(e_intern2), "free_tv()");
- break;
}
xfree(varp);
}
@@ -17632,10 +17711,11 @@ void clear_tv(typval_T *varp)
case VAR_FLOAT:
varp->vval.v_float = 0.0;
break;
+ case VAR_SPECIAL:
+ varp->vval.v_special = kSpecialVarFalse;
+ break;
case VAR_UNKNOWN:
break;
- default:
- EMSG2(_(e_intern2), "clear_tv()");
}
varp->v_lock = 0;
}
@@ -17690,7 +17770,19 @@ long get_tv_number_chk(typval_T *varp, int *denote)
case VAR_DICT:
EMSG(_("E728: Using a Dictionary as a Number"));
break;
- default:
+ case VAR_SPECIAL:
+ switch (varp->vval.v_special) {
+ case kSpecialVarTrue: {
+ return 1;
+ }
+ case kSpecialVarFalse:
+ case kSpecialVarNone:
+ case kSpecialVarNull: {
+ return 0;
+ }
+ }
+ break;
+ case VAR_UNKNOWN:
EMSG2(_(e_intern2), "get_tv_number()");
break;
}
@@ -17796,7 +17888,10 @@ static char_u *get_tv_string_buf_chk(const typval_T *varp, char_u *buf)
if (varp->vval.v_string != NULL)
return varp->vval.v_string;
return (char_u *)"";
- default:
+ case VAR_SPECIAL:
+ STRCPY(buf, encode_special_var_names[varp->vval.v_special]);
+ return buf;
+ case VAR_UNKNOWN:
EMSG2(_(e_intern2), "get_tv_string_buf()");
break;
}
@@ -18345,42 +18440,34 @@ void copy_tv(typval_T *from, typval_T *to)
{
to->v_type = from->v_type;
to->v_lock = 0;
+ memmove(&to->vval, &from->vval, sizeof(to->vval));
switch (from->v_type) {
- case VAR_NUMBER:
- to->vval.v_number = from->vval.v_number;
- break;
- case VAR_FLOAT:
- to->vval.v_float = from->vval.v_float;
- break;
- case VAR_STRING:
- case VAR_FUNC:
- if (from->vval.v_string == NULL)
- to->vval.v_string = NULL;
- else {
- to->vval.v_string = vim_strsave(from->vval.v_string);
- if (from->v_type == VAR_FUNC)
- func_ref(to->vval.v_string);
- }
- break;
- case VAR_LIST:
- if (from->vval.v_list == NULL)
- to->vval.v_list = NULL;
- else {
- to->vval.v_list = from->vval.v_list;
- ++to->vval.v_list->lv_refcount;
- }
- break;
- case VAR_DICT:
- if (from->vval.v_dict == NULL)
- to->vval.v_dict = NULL;
- else {
- to->vval.v_dict = from->vval.v_dict;
- ++to->vval.v_dict->dv_refcount;
- }
- break;
- default:
- EMSG2(_(e_intern2), "copy_tv()");
- break;
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_SPECIAL:
+ break;
+ case VAR_STRING:
+ case VAR_FUNC:
+ if (from->vval.v_string != NULL) {
+ to->vval.v_string = vim_strsave(from->vval.v_string);
+ if (from->v_type == VAR_FUNC) {
+ func_ref(to->vval.v_string);
+ }
+ }
+ break;
+ case VAR_LIST:
+ if (from->vval.v_list != NULL) {
+ to->vval.v_list->lv_refcount++;
+ }
+ break;
+ case VAR_DICT:
+ if (from->vval.v_dict != NULL) {
+ to->vval.v_dict->dv_refcount++;
+ }
+ break;
+ case VAR_UNKNOWN:
+ EMSG2(_(e_intern2), "copy_tv()");
+ break;
}
}
@@ -18420,6 +18507,7 @@ int var_item_copy(const vimconv_T *const conv,
case VAR_NUMBER:
case VAR_FLOAT:
case VAR_FUNC:
+ case VAR_SPECIAL:
copy_tv(from, to);
break;
case VAR_STRING:
@@ -18466,7 +18554,7 @@ int var_item_copy(const vimconv_T *const conv,
if (to->vval.v_dict == NULL)
ret = FAIL;
break;
- default:
+ case VAR_UNKNOWN:
EMSG2(_(e_intern2), "var_item_copy()");
ret = FAIL;
}
@@ -21705,4 +21793,3 @@ static bool is_watched(dict_T *d)
{
return d && !QUEUE_EMPTY(&d->watchers);
}
-
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index e8b5964775..89aa263434 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -15,12 +15,6 @@
// All user-defined functions are found in this hashtable.
extern hashtab_T func_hashtab;
-/// CopyID for recursively traversing lists and dicts
-///
-/// This value is needed to avoid endless recursiveness. Last bit is used for
-/// previous_funccal and normally ignored when comparing.
-extern int current_copyID;
-
// Structure to hold info for a user function.
typedef struct ufunc ufunc_T;
@@ -127,7 +121,11 @@ enum {
VV_ERRORS,
VV_MSGPACK_TYPES,
VV_EVENT,
- VV_LEN, // number of v: vars
+ VV_FALSE,
+ VV_TRUE,
+ VV_NULL,
+ VV_NONE,
+ VV_LEN, ///< Number of v: variables
};
/// All recognized msgpack types
diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h
index 56833f97d8..bcd9e80f9a 100644
--- a/src/nvim/eval_defs.h
+++ b/src/nvim/eval_defs.h
@@ -18,12 +18,32 @@ typedef struct dictvar_S dict_T;
/// Special variable values
typedef enum {
- kSpecialVarNull, ///< v:null
- kSpecialVarNone, ///< v:none
kSpecialVarFalse, ///< v:false
kSpecialVarTrue, ///< v:true
+ kSpecialVarNone, ///< v:none
+ kSpecialVarNull, ///< v:null
} SpecialVarValue;
+/// Variable lock status for typval_T.v_lock
+typedef enum {
+ VAR_UNLOCKED = 0, ///< Not locked.
+ VAR_LOCKED, ///< User lock, can be unlocked.
+ VAR_FIXED, ///< 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 referene, .v_string is used for 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, none), .v_special
+ ///< is used.
+} VarType;
+
/// Structure that holds an internal variable value
typedef struct {
VarType v_type; ///< Variable type.
@@ -38,34 +58,11 @@ typedef struct {
} vval; ///< Actual value.
} typval_T;
-/// VimL variable types, for use in typval_T.v_type
-///
-/// @warning Numbers are part of the user API (returned by type()), so they must
-/// not be changed.
-typedef enum {
- VAR_UNKNOWN = 0, ///< Unknown (unspecified) value.
- VAR_NUMBER = 1, ///< Number, .v_number is used.
- VAR_STRING = 2, ///< String, .v_string is used.
- VAR_FUNC = 3, ///< Function referene, .v_string is used for function name.
- VAR_LIST = 4, ///< List, .v_list is used.
- VAR_DICT = 5, ///< Dictionary, .v_dict is used.
- VAR_FLOAT = 6, ///< Floating-point value, .v_float is used.
- VAR_SPECIAL = 7, ///< Special value (true, false, null, none), .v_special
- ///< is used.
-} VarType;
-
/* Values for "dv_scope". */
#define VAR_SCOPE 1 /* a:, v:, s:, etc. scope dictionaries */
#define VAR_DEF_SCOPE 2 /* l:, g: scope dictionaries: here funcrefs are not
allowed to mask existing functions */
-/// Variable lock status for typval_T.v_lock
-typedef enum {
- VAR_UNLOCKED = 0, ///< Not locked.
- VAR_LOCKED, ///< User lock, can be unlocked.
- VAR_FIXED, ///< Locked forever.
-} VarLockStatus;
-
/*
* Structure to hold an item of a list: an internal variable without a name.
*/
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 8f45620570..9ccd53f76b 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -195,18 +195,18 @@ static int included_patches[] = {
// 1170 NA
// 1169 NA
1168,
- // 1167,
- // 1166,
+ 1167,
+ 1166,
// 1165 NA
- // 1164,
- // 1163,
+ 1164,
+ 1163,
// 1162 NA
// 1161,
- // 1160,
+ 1160,
// 1159 NA
// 1158 NA
- // 1157,
- // 1156,
+ 1157,
+ // 1156 NA
// 1155 NA
// 1154,
// 1153,