aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/api/vimscript.c4
-rw-r--r--src/nvim/eval.c144
-rw-r--r--src/nvim/eval.h5
-rw-r--r--src/nvim/eval/funcs.c2
-rw-r--r--src/nvim/eval/userfunc.c15
-rw-r--r--src/nvim/eval/vars.c29
-rw-r--r--src/nvim/ex_cmds.lua2
-rw-r--r--src/nvim/ex_eval.c2
-rw-r--r--src/nvim/quickfix.c2
-rw-r--r--test/unit/eval/helpers.lua2
10 files changed, 112 insertions, 95 deletions
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index 2438a5cf1d..1740429ef6 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -172,7 +172,7 @@ Object nvim_eval(String expr, Error *err)
int ok;
TRY_WRAP(err, {
- ok = eval0(expr.data, &rettv, NULL, true);
+ ok = eval0(expr.data, &rettv, NULL, EVAL_EVALUATE);
});
if (!ERROR_SET(err)) {
@@ -290,7 +290,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err)
switch (dict.type) {
case kObjectTypeString:
try_start();
- if (eval0(dict.data.string.data, &rettv, NULL, true) == FAIL) {
+ if (eval0(dict.data.string.data, &rettv, NULL, EVAL_EVALUATE) == FAIL) {
api_set_error(err, kErrorTypeException,
"Failed to evaluate dict expression");
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index ff33fdeccb..796c010f74 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -706,7 +706,7 @@ int eval_to_bool(char *arg, bool *error, char **nextcmd, int skip)
if (skip) {
emsg_skip++;
}
- if (eval0(arg, &tv, nextcmd, !skip) == FAIL) {
+ if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL) {
*error = true;
} else {
*error = false;
@@ -730,7 +730,7 @@ static int eval1_emsg(char **arg, typval_T *rettv, bool evaluate)
const int did_emsg_before = did_emsg;
const int called_emsg_before = called_emsg;
- const int ret = eval1(arg, rettv, evaluate);
+ const int ret = eval1(arg, rettv, evaluate ? EVAL_EVALUATE : 0);
if (ret == FAIL) {
// Report the invalid expression unless the expression evaluation has
// been cancelled due to an aborting error, an interrupt, or an
@@ -832,7 +832,7 @@ char *eval_to_string_skip(const char *arg, const char **nextcmd, const bool skip
if (skip) {
emsg_skip++;
}
- if (eval0((char *)arg, &tv, (char **)nextcmd, !skip) == FAIL || skip) {
+ if (eval0((char *)arg, &tv, (char **)nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL || skip) {
retval = NULL;
} else {
retval = xstrdup(tv_get_string(&tv));
@@ -853,7 +853,7 @@ int skip_expr(char **pp)
typval_T rettv;
*pp = skipwhite(*pp);
- return eval1(pp, &rettv, false);
+ return eval1(pp, &rettv, 0);
}
/// Top level evaluation function, returning a string.
@@ -868,7 +868,7 @@ char *eval_to_string(char *arg, char **nextcmd, bool convert)
char *retval;
garray_T ga;
- if (eval0(arg, &tv, nextcmd, true) == FAIL) {
+ if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL) {
retval = NULL;
} else {
if (convert && tv.v_type == VAR_LIST) {
@@ -929,7 +929,7 @@ varnumber_T eval_to_number(char *expr)
emsg_off++;
- if (eval1(&p, &rettv, true) == FAIL) {
+ if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL) {
retval = -1;
} else {
retval = tv_get_number_chk(&rettv, NULL);
@@ -947,7 +947,7 @@ varnumber_T eval_to_number(char *expr)
typval_T *eval_expr(char *arg)
{
typval_T *tv = xmalloc(sizeof(*tv));
- if (eval0(arg, tv, NULL, true) == FAIL) {
+ if (eval0(arg, tv, NULL, EVAL_EVALUATE) == FAIL) {
XFREE_CLEAR(tv);
}
return tv;
@@ -1024,7 +1024,7 @@ list_T *eval_spell_expr(char *badword, char *expr)
emsg_off++;
}
- if (eval1(&p, &rettv, true) == OK) {
+ if (eval1(&p, &rettv, EVAL_EVALUATE) == OK) {
if (rettv.v_type != VAR_LIST) {
tv_clear(&rettv);
} else {
@@ -1171,7 +1171,7 @@ int eval_foldexpr(char *arg, int *cp)
}
textlock++;
*cp = NUL;
- if (eval0(arg, &tv, NULL, true) == FAIL) {
+ if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL) {
retval = 0;
} else {
// If the result is a number, just return the number.
@@ -1346,7 +1346,7 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const
empty1 = true;
} else {
empty1 = false;
- if (eval1(&p, &var1, true) == FAIL) { // Recursive!
+ if (eval1(&p, &var1, EVAL_EVALUATE) == FAIL) { // Recursive!
return NULL;
}
if (!tv_check_str(&var1)) {
@@ -1380,7 +1380,8 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const
lp->ll_empty2 = true;
} else {
lp->ll_empty2 = false;
- if (eval1(&p, &var2, true) == FAIL) { // Recursive!
+ // Recursive!
+ if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL) {
tv_clear(&var1);
return NULL;
}
@@ -1799,7 +1800,7 @@ void *eval_for_line(const char *arg, bool *errp, char **nextcmdp, int skip)
if (skip) {
emsg_skip++;
}
- if (eval0(skipwhite(expr + 2), &tv, nextcmdp, !skip) == OK) {
+ if (eval0(skipwhite(expr + 2), &tv, nextcmdp, skip ? 0 : EVAL_EVALUATE) == OK) {
*errp = false;
if (!skip) {
if (tv.v_type == VAR_LIST) {
@@ -2164,9 +2165,10 @@ int pattern_match(const char *pat, const char *text, bool ic)
///
/// @return OK or FAIL.
static int eval_func(char **const arg, char *const name, const int name_len, typval_T *const rettv,
- const bool evaluate, typval_T *const basetv)
+ const int flags, typval_T *const basetv)
FUNC_ATTR_NONNULL_ARG(1, 2, 4)
{
+ const bool evaluate = flags & EVAL_EVALUATE;
char *s = name;
int len = name_len;
@@ -2223,8 +2225,10 @@ static int eval_func(char **const arg, char *const name, const int name_len, typ
/// Put the result in "rettv" when returning OK and "evaluate" is true.
/// Note: "rettv.v_lock" is not set.
///
+/// @param flags has EVAL_EVALUATE and similar flags.
+///
/// @return OK or FAIL.
-int eval0(char *arg, typval_T *rettv, char **nextcmd, int evaluate)
+int eval0(char *arg, typval_T *rettv, char **nextcmd, const int flags)
{
int ret;
char *p;
@@ -2233,7 +2237,7 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, int evaluate)
bool end_error = false;
p = skipwhite(arg);
- ret = eval1(&p, rettv, evaluate);
+ ret = eval1(&p, rettv, flags);
if (ret != FAIL) {
end_error = !ends_excmd(*p);
@@ -2246,7 +2250,8 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, int evaluate)
// been cancelled due to an aborting error, an interrupt, or an
// exception, or we already gave a more specific error.
// Also check called_emsg for when using assert_fails().
- if (!aborting() && did_emsg == did_emsg_before
+ if (!aborting()
+ && did_emsg == did_emsg_before
&& called_emsg == called_emsg_before) {
if (end_error) {
semsg(_(e_trailing_arg), p);
@@ -2272,18 +2277,20 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, int evaluate)
/// Note: "rettv.v_lock" is not set.
///
/// @return OK or FAIL.
-int eval1(char **arg, typval_T *rettv, int evaluate)
+int eval1(char **arg, typval_T *rettv, const int flags)
{
typval_T var2;
// Get the first variable.
- if (eval2(arg, rettv, evaluate) == FAIL) {
+ if (eval2(arg, rettv, flags) == FAIL) {
return FAIL;
}
if ((*arg)[0] == '?') {
+ const bool evaluate = flags & EVAL_EVALUATE;
+
bool result = false;
- if (evaluate) {
+ if (flags & EVAL_EVALUATE) {
bool error = false;
if (tv_get_number_chk(rettv, &error) != 0) {
@@ -2295,9 +2302,9 @@ int eval1(char **arg, typval_T *rettv, int evaluate)
}
}
- // Get the second variable.
+ // Get the second variable. Recursive!
*arg = skipwhite(*arg + 1);
- if (eval1(arg, rettv, evaluate && result) == FAIL) { // recursive!
+ if (eval1(arg, rettv, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) {
return FAIL;
}
@@ -2310,9 +2317,9 @@ int eval1(char **arg, typval_T *rettv, int evaluate)
return FAIL;
}
- // Get the third variable.
+ // Get the third variable. Recursive!
*arg = skipwhite(*arg + 1);
- if (eval1(arg, &var2, evaluate && !result) == FAIL) { // Recursive!
+ if (eval1(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) {
if (evaluate && result) {
tv_clear(rettv);
}
@@ -2333,13 +2340,13 @@ int eval1(char **arg, typval_T *rettv, int evaluate)
/// "arg" is advanced to the next non-white after the recognized expression.
///
/// @return OK or FAIL.
-static int eval2(char **arg, typval_T *rettv, int evaluate)
+static int eval2(char **arg, typval_T *rettv, const int flags)
{
typval_T var2;
bool error = false;
// Get the first variable.
- if (eval3(arg, rettv, evaluate) == FAIL) {
+ if (eval3(arg, rettv, flags) == FAIL) {
return FAIL;
}
@@ -2347,6 +2354,8 @@ static int eval2(char **arg, typval_T *rettv, int evaluate)
bool first = true;
bool result = false;
while ((*arg)[0] == '|' && (*arg)[1] == '|') {
+ const bool evaluate = flags & EVAL_EVALUATE;
+
if (evaluate && first) {
if (tv_get_number_chk(rettv, &error) != 0) {
result = true;
@@ -2360,7 +2369,7 @@ static int eval2(char **arg, typval_T *rettv, int evaluate)
// Get the second variable.
*arg = skipwhite(*arg + 2);
- if (eval3(arg, &var2, evaluate && !result) == FAIL) {
+ if (eval3(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) {
return FAIL;
}
@@ -2390,13 +2399,13 @@ static int eval2(char **arg, typval_T *rettv, int evaluate)
/// `arg` is advanced to the next non-white after the recognized expression.
///
/// @return OK or FAIL.
-static int eval3(char **arg, typval_T *rettv, int evaluate)
+static int eval3(char **arg, typval_T *rettv, const int flags)
{
typval_T var2;
bool error = false;
// Get the first variable.
- if (eval4(arg, rettv, evaluate) == FAIL) {
+ if (eval4(arg, rettv, flags) == FAIL) {
return FAIL;
}
@@ -2404,6 +2413,8 @@ static int eval3(char **arg, typval_T *rettv, int evaluate)
bool first = true;
bool result = true;
while ((*arg)[0] == '&' && (*arg)[1] == '&') {
+ const bool evaluate = flags & EVAL_EVALUATE;
+
if (evaluate && first) {
if (tv_get_number_chk(rettv, &error) == 0) {
result = false;
@@ -2417,7 +2428,7 @@ static int eval3(char **arg, typval_T *rettv, int evaluate)
// Get the second variable.
*arg = skipwhite(*arg + 2);
- if (eval4(arg, &var2, evaluate && result) == FAIL) {
+ if (eval4(arg, &var2, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) {
return FAIL;
}
@@ -2456,7 +2467,7 @@ static int eval3(char **arg, typval_T *rettv, int evaluate)
/// "arg" is advanced to the next non-white after the recognized expression.
///
/// @return OK or FAIL.
-static int eval4(char **arg, typval_T *rettv, int evaluate)
+static int eval4(char **arg, typval_T *rettv, const int flags)
{
typval_T var2;
char *p;
@@ -2464,7 +2475,7 @@ static int eval4(char **arg, typval_T *rettv, int evaluate)
int len = 2;
// Get the first variable.
- if (eval5(arg, rettv, evaluate) == FAIL) {
+ if (eval5(arg, rettv, flags) == FAIL) {
return FAIL;
}
@@ -2528,11 +2539,11 @@ static int eval4(char **arg, typval_T *rettv, int evaluate)
// Get the second variable.
*arg = skipwhite(p + len);
- if (eval5(arg, &var2, evaluate) == FAIL) {
+ if (eval5(arg, &var2, flags) == FAIL) {
tv_clear(rettv);
return FAIL;
}
- if (evaluate) {
+ if (flags & EVAL_EVALUATE) {
const int ret = typval_compare(rettv, &var2, type, ic);
tv_clear(&var2);
@@ -2586,7 +2597,7 @@ static int eval_addlist(typval_T *tv1, typval_T *tv2)
/// `arg` is advanced to the next non-white after the recognized expression.
///
/// @return OK or FAIL.
-static int eval5(char **arg, typval_T *rettv, int evaluate)
+static int eval5(char **arg, typval_T *rettv, const int flags)
{
typval_T var2;
varnumber_T n1, n2;
@@ -2594,7 +2605,7 @@ static int eval5(char **arg, typval_T *rettv, int evaluate)
char *p;
// Get the first variable.
- if (eval6(arg, rettv, evaluate, false) == FAIL) {
+ if (eval6(arg, rettv, flags, false) == FAIL) {
return FAIL;
}
@@ -2606,7 +2617,7 @@ static int eval5(char **arg, typval_T *rettv, int evaluate)
}
if ((op != '+' || (rettv->v_type != VAR_LIST && rettv->v_type != VAR_BLOB))
- && (op == '.' || rettv->v_type != VAR_FLOAT) && evaluate) {
+ && (op == '.' || rettv->v_type != VAR_FLOAT) && (flags & EVAL_EVALUATE)) {
// For "list + ...", an illegal use of the first operand as
// a number cannot be determined before evaluating the 2nd
// operand: if this is also a list, all is ok.
@@ -2625,12 +2636,12 @@ static int eval5(char **arg, typval_T *rettv, int evaluate)
(*arg)++;
}
*arg = skipwhite(*arg + 1);
- if (eval6(arg, &var2, evaluate, op == '.') == FAIL) {
+ if (eval6(arg, &var2, flags, op == '.') == FAIL) {
tv_clear(rettv);
return FAIL;
}
- if (evaluate) {
+ if (flags & EVAL_EVALUATE) {
// Compute the result.
if (op == '.') {
char buf1[NUMBUFLEN];
@@ -2724,11 +2735,10 @@ static int eval5(char **arg, typval_T *rettv, int evaluate)
/// expression. Is advanced to the next non-whitespace
/// character after the recognized expression.
/// @param[out] rettv Location where result is saved.
-/// @param[in] evaluate If not true, rettv is not populated.
/// @param[in] want_string True if "." is string_concatenation, otherwise
/// float
/// @return OK or FAIL.
-static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string)
+static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string)
FUNC_ATTR_NO_SANITIZE_UNDEFINED
{
typval_T var2;
@@ -2739,7 +2749,7 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string)
bool error = false;
// Get the first variable.
- if (eval7(arg, rettv, evaluate, want_string) == FAIL) {
+ if (eval7(arg, rettv, flags, want_string) == FAIL) {
return FAIL;
}
@@ -2750,7 +2760,7 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string)
break;
}
- if (evaluate) {
+ if (flags & EVAL_EVALUATE) {
if (rettv->v_type == VAR_FLOAT) {
f1 = rettv->vval.v_float;
use_float = true;
@@ -2768,11 +2778,11 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string)
// Get the second variable.
*arg = skipwhite(*arg + 1);
- if (eval7(arg, &var2, evaluate, false) == FAIL) {
+ if (eval7(arg, &var2, flags, false) == FAIL) {
return FAIL;
}
- if (evaluate) {
+ if (flags & EVAL_EVALUATE) {
if (var2.v_type == VAR_FLOAT) {
if (!use_float) {
f1 = (float_T)n1;
@@ -2859,8 +2869,9 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string)
/// @param want_string after "." operator
///
/// @return OK or FAIL.
-static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
+static int eval7(char **arg, typval_T *rettv, const int flags, bool want_string)
{
+ const bool evaluate = flags & EVAL_EVALUATE;
int ret = OK;
static int recurse = 0;
@@ -2922,14 +2933,14 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
// List: [expr, expr]
case '[':
- ret = get_list_tv(arg, rettv, evaluate);
+ ret = get_list_tv(arg, rettv, flags);
break;
// Dictionary: #{key: val, key: val}
case '#':
if ((*arg)[1] == '{') {
(*arg)++;
- ret = eval_dict(arg, rettv, evaluate, true);
+ ret = eval_dict(arg, rettv, flags, true);
} else {
ret = NOTDONE;
}
@@ -2940,7 +2951,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
case '{':
ret = get_lambda_tv(arg, rettv, evaluate);
if (ret == NOTDONE) {
- ret = eval_dict(arg, rettv, evaluate, false);
+ ret = eval_dict(arg, rettv, flags, false);
}
break;
@@ -2968,7 +2979,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
// nested expression: (expression).
case '(':
*arg = skipwhite(*arg + 1);
- ret = eval1(arg, rettv, evaluate); // recursive!
+ ret = eval1(arg, rettv, flags); // recursive!
if (**arg == ')') {
(*arg)++;
} else if (ret == OK) {
@@ -2997,7 +3008,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
ret = FAIL;
} else {
if (**arg == '(') { // recursive!
- ret = eval_func(arg, s, len, rettv, evaluate, NULL);
+ ret = eval_func(arg, s, len, rettv, flags, NULL);
} else if (evaluate) {
ret = get_var_tv(s, len, rettv, NULL, true, false);
} else {
@@ -3013,7 +3024,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
// Handle following '[', '(' and '.' for expr[expr], expr.name,
// expr(expr), expr->name(expr)
if (ret == OK) {
- ret = handle_subscript((const char **)arg, rettv, evaluate, true);
+ ret = handle_subscript((const char **)arg, rettv, flags, true);
}
// Apply logical NOT and unary '-', from right to left, ignore '+'.
@@ -3238,7 +3249,7 @@ static int eval_method(char **const arg, typval_T *const rettv, const bool evalu
}
ret = call_func_rettv(arg, rettv, evaluate, NULL, &base, lua_funcname);
} else {
- ret = eval_func(arg, name, len, rettv, evaluate, &base);
+ ret = eval_func(arg, name, len, rettv, evaluate ? EVAL_EVALUATE : 0, &base);
}
}
@@ -3257,8 +3268,9 @@ static int eval_method(char **const arg, typval_T *const rettv, const bool evalu
/// @param verbose give error messages
///
/// @returns FAIL or OK. "*arg" is advanced to after the ']'.
-static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose)
+static int eval_index(char **arg, typval_T *rettv, const int flags, bool verbose)
{
+ const bool evaluate = flags & EVAL_EVALUATE;
bool empty1 = false;
bool empty2 = false;
ptrdiff_t len = -1;
@@ -3313,7 +3325,7 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose)
*arg = skipwhite(*arg + 1);
if (**arg == ':') {
empty1 = true;
- } else if (eval1(arg, &var1, evaluate) == FAIL) { // Recursive!
+ } else if (eval1(arg, &var1, flags) == FAIL) { // Recursive!
return FAIL;
} else if (evaluate && !tv_check_str(&var1)) {
// Not a number or string.
@@ -3327,7 +3339,7 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose)
*arg = skipwhite(*arg + 1);
if (**arg == ']') {
empty2 = true;
- } else if (eval1(arg, &var2, evaluate) == FAIL) { // Recursive!
+ } else if (eval1(arg, &var2, flags) == FAIL) { // Recursive!
if (!empty1) {
tv_clear(&var1);
}
@@ -3930,8 +3942,9 @@ void partial_unref(partial_T *pt)
/// Allocate a variable for a List and fill it from "*arg".
///
/// @return OK or FAIL.
-static int get_list_tv(char **arg, typval_T *rettv, int evaluate)
+static int get_list_tv(char **arg, typval_T *rettv, const int flags)
{
+ const bool evaluate = flags & EVAL_EVALUATE;
list_T *l = NULL;
if (evaluate) {
@@ -3941,7 +3954,7 @@ static int get_list_tv(char **arg, typval_T *rettv, int evaluate)
*arg = skipwhite(*arg + 1);
while (**arg != ']' && **arg != NUL) {
typval_T tv;
- if (eval1(arg, &tv, evaluate) == FAIL) { // Recursive!
+ if (eval1(arg, &tv, flags) == FAIL) { // Recursive!
goto failret;
}
if (evaluate) {
@@ -4576,8 +4589,9 @@ static int get_literal_key(char **arg, typval_T *tv)
/// "literal" is true for #{key: val}
///
/// @return OK or FAIL. Returns NOTDONE for {expr}.
-static int eval_dict(char **arg, typval_T *rettv, int evaluate, bool literal)
+static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal)
{
+ const bool evaluate = flags & EVAL_EVALUATE;
typval_T tv;
char *key = NULL;
char *curly_expr = skipwhite(*arg + 1);
@@ -4591,7 +4605,7 @@ static int eval_dict(char **arg, typval_T *rettv, int evaluate, bool literal)
// "#{abc}" is never a curly-braces expression.
if (*curly_expr != '}'
&& !literal
- && eval1(&curly_expr, &tv, false) == OK
+ && eval1(&curly_expr, &tv, 0) == OK
&& *skipwhite(curly_expr) == '}') {
return NOTDONE;
}
@@ -4608,7 +4622,7 @@ static int eval_dict(char **arg, typval_T *rettv, int evaluate, bool literal)
while (**arg != '}' && **arg != NUL) {
if ((literal
? get_literal_key(arg, &tvkey)
- : eval1(arg, &tvkey, evaluate)) == FAIL) { // recursive!
+ : eval1(arg, &tvkey, flags)) == FAIL) { // recursive!
goto failret;
}
if (**arg != ':') {
@@ -4626,7 +4640,7 @@ static int eval_dict(char **arg, typval_T *rettv, int evaluate, bool literal)
}
*arg = skipwhite(*arg + 1);
- if (eval1(arg, &tv, evaluate) == FAIL) { // Recursive!
+ if (eval1(arg, &tv, flags) == FAIL) { // Recursive!
if (evaluate) {
tv_clear(&tvkey);
}
@@ -6937,12 +6951,12 @@ int check_luafunc_name(const char *const str, const bool paren)
///
/// Can all be combined in any order: dict.func(expr)[idx]['func'](expr)->len()
///
-/// @param evaluate do more than finding the end
/// @param verbose give error messages
/// @param start_leader start of '!' and '-' prefixes
/// @param end_leaderp end of '!' and '-' prefixes
-int handle_subscript(const char **const arg, typval_T *rettv, int evaluate, int verbose)
+int handle_subscript(const char **const arg, typval_T *rettv, const int flags, bool verbose)
{
+ const bool evaluate = flags & EVAL_EVALUATE;
int ret = OK;
dict_T *selfdict = NULL;
const char *lua_funcname = NULL;
@@ -7002,7 +7016,7 @@ int handle_subscript(const char **const arg, typval_T *rettv, int evaluate, int
} else {
selfdict = NULL;
}
- if (eval_index((char **)arg, rettv, evaluate, verbose) == FAIL) {
+ if (eval_index((char **)arg, rettv, flags, verbose) == FAIL) {
tv_clear(rettv);
ret = FAIL;
}
@@ -7385,7 +7399,7 @@ void ex_echo(exarg_T *eap)
{
char *p = arg;
- if (eval1(&arg, &rettv, !eap->skip) == FAIL) {
+ if (eval1(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE) == FAIL) {
// Report the invalid expression unless the expression evaluation
// has been cancelled due to an aborting error, an interrupt, or an
// exception.
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index aa034cb2b3..973a4a1fc3 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -266,6 +266,11 @@ typedef int (*ex_unletlock_callback)(lval_T *, char *, exarg_T *, int);
// Used for checking if local variables or arguments used in a lambda.
extern bool *eval_lavars_used;
+/// Flag for expression evaluation.
+enum {
+ EVAL_EVALUATE = 1, ///< when missing don't actually evaluate
+};
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval.h.generated.h"
#endif
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 7f224f371c..52e38b73ba 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -1550,7 +1550,7 @@ static void f_eval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
const char *const expr_start = s;
- if (s == NULL || eval1((char **)&s, rettv, true) == FAIL) {
+ if (s == NULL || eval1((char **)&s, rettv, EVAL_EVALUATE) == FAIL) {
if (expr_start != NULL && !aborting()) {
semsg(_(e_invexpr2), expr_start);
}
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index f09da6b79b..f82ab08d2d 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -152,7 +152,7 @@ static int get_function_args(char **argp, char endchar, garray_T *newargs, int *
p = skipwhite(p) + 1;
p = skipwhite(p);
char *expr = p;
- if (eval1(&p, &rettv, false) != FAIL) {
+ if (eval1(&p, &rettv, 0) != FAIL) {
ga_grow(default_args, 1);
// trim trailing whitespace
@@ -463,7 +463,8 @@ int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, funcexe_
if (*argp == ')' || *argp == ',' || *argp == NUL) {
break;
}
- if (eval1(&argp, &argvars[argcount], funcexe->fe_evaluate) == FAIL) {
+ if (eval1(&argp, &argvars[argcount],
+ funcexe->fe_evaluate ? EVAL_EVALUATE : 0) == FAIL) {
ret = FAIL;
break;
}
@@ -972,7 +973,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
default_expr = ((char **)(fp->uf_def_args.ga_data))
[ai + fp->uf_def_args.ga_len];
- if (eval1(&default_expr, &def_rettv, true) == FAIL) {
+ if (eval1(&default_expr, &def_rettv, EVAL_EVALUATE) == FAIL) {
default_arg_err = true;
break;
}
@@ -1109,7 +1110,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
// A Lambda always has the command "return {expr}". It is much faster
// to evaluate {expr} directly.
ex_nesting_level++;
- (void)eval1(&p, rettv, true);
+ (void)eval1(&p, rettv, EVAL_EVALUATE);
ex_nesting_level--;
} else {
// call do_cmdline() to execute the lines
@@ -2953,7 +2954,7 @@ void ex_return(exarg_T *eap)
eap->nextcmd = NULL;
if ((*arg != NUL && *arg != '|' && *arg != '\n')
- && eval0(arg, &rettv, &eap->nextcmd, !eap->skip) != FAIL) {
+ && eval0(arg, &rettv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) != FAIL) {
if (!eap->skip) {
returning = do_return(eap, false, true, &rettv);
} else {
@@ -3004,7 +3005,7 @@ void ex_call(exarg_T *eap)
// instead to skip to any following command, e.g. for:
// :if 0 | call dict.foo().bar() | endif.
emsg_skip++;
- if (eval0(eap->arg, &rettv, &eap->nextcmd, false) != FAIL) {
+ if (eval0(eap->arg, &rettv, &eap->nextcmd, 0) != FAIL) {
tv_clear(&rettv);
}
emsg_skip--;
@@ -3071,7 +3072,7 @@ void ex_call(exarg_T *eap)
}
// Handle a function returning a Funcref, Dictionary or List.
- if (handle_subscript((const char **)&arg, &rettv, true, true)
+ if (handle_subscript((const char **)&arg, &rettv, EVAL_EVALUATE, true)
== FAIL) {
failed = true;
break;
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index 9120cc4471..a3dc0cfc04 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -175,21 +175,13 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
/// ":let var ..= expr" assignment command.
/// ":let [var1, var2] = expr" unpack list.
/// ":let [name, ..., ; lastname] = expr" unpack list.
-void ex_let(exarg_T *eap)
-{
- ex_let_const(eap, false);
-}
-
+///
/// ":cons[t] var = expr1" define constant
/// ":cons[t] [name1, name2, ...] = expr1" define constants unpacking list
/// ":cons[t] [name, ..., ; lastname] = expr" define constants unpacking list
-void ex_const(exarg_T *eap)
-{
- ex_let_const(eap, true);
-}
-
-static void ex_let_const(exarg_T *eap, const bool is_const)
+void ex_let(exarg_T *eap)
{
+ const bool is_const = eap->cmdidx == CMD_const;
char *arg = eap->arg;
char *expr = NULL;
typval_T rettv;
@@ -208,8 +200,10 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
argend--;
}
expr = skipwhite(argend);
- if (*expr != '=' && !((vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL
- && expr[1] == '=') || strncmp(expr, "..=", 3) == 0)) {
+ bool concat = strncmp(expr, "..=", 3) == 0;
+ bool has_assign = *expr == '=' || (vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL
+ && expr[1] == '=');
+ if (!has_assign && !concat) {
// ":let" without "=": list variables
if (*arg == '[') {
emsg(_(e_invarg));
@@ -240,6 +234,8 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
tv_clear(&rettv);
}
} else {
+ rettv.v_type = VAR_UNKNOWN;
+
op[0] = '=';
op[1] = NUL;
if (*expr != '=') {
@@ -259,7 +255,8 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
if (eap->skip) {
emsg_skip++;
}
- i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip);
+ int eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
+ i = eval0(expr, &rettv, &eap->nextcmd, eval_flags);
if (eap->skip) {
if (i != FAIL) {
tv_clear(&rettv);
@@ -506,7 +503,7 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
} else {
// handle d.key, l[idx], f(expr)
const char *const arg_subsc = arg;
- if (handle_subscript(&arg, &tv, true, true) == FAIL) {
+ if (handle_subscript(&arg, &tv, EVAL_EVALUATE, true) == FAIL) {
error = true;
} else {
if (arg == arg_subsc && len == 2 && name[1] == ':') {
@@ -1713,7 +1710,7 @@ bool var_exists(const char *var)
n = get_var_tv(name, len, &tv, NULL, false, true) == OK;
if (n) {
// Handle d.key, l[idx], f(expr).
- n = handle_subscript(&var, &tv, true, false) == OK;
+ n = handle_subscript(&var, &tv, EVAL_EVALUATE, false) == OK;
if (n) {
tv_clear(&tv);
}
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index bdc1174de3..be6299db0e 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -634,7 +634,7 @@ module.cmds = {
command='const',
flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN, LOCK_OK),
addr_type='ADDR_NONE',
- func='ex_const',
+ func='ex_let',
},
{
command='copen',
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index fed8f549e6..6772b78c33 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -793,7 +793,7 @@ void ex_eval(exarg_T *eap)
{
typval_T tv;
- if (eval0(eap->arg, &tv, &eap->nextcmd, !eap->skip) == OK) {
+ if (eval0(eap->arg, &tv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) == OK) {
tv_clear(&tv);
}
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 262d87ba61..cfaa3b5781 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -6958,7 +6958,7 @@ void ex_cexpr(exarg_T *eap)
// Evaluate the expression. When the result is a string or a list we can
// use it to fill the errorlist.
typval_T tv;
- if (eval0(eap->arg, &tv, &eap->nextcmd, true) == FAIL) {
+ if (eval0(eap->arg, &tv, &eap->nextcmd, EVAL_EVALUATE) == FAIL) {
return;
}
diff --git a/test/unit/eval/helpers.lua b/test/unit/eval/helpers.lua
index 9dd6b76de2..0694fceaec 100644
--- a/test/unit/eval/helpers.lua
+++ b/test/unit/eval/helpers.lua
@@ -512,7 +512,7 @@ end
local function eval0(expr)
local tv = ffi.gc(ffi.new('typval_T', {v_type=eval.VAR_UNKNOWN}),
eval.tv_clear)
- if eval.eval0(to_cstr(expr), tv, nil, true) == 0 then
+ if eval.eval0(to_cstr(expr), tv, nil, eval.EVAL_EVALUATE) == 0 then
return nil
else
return tv