|
|
|
@ -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 ? 0 : EVAL_EVALUATE) == FAIL) {
|
|
|
|
|
if (eval0(arg, &tv, nextcmd, skip ? NULL : &EVALARG_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 ? EVAL_EVALUATE : 0);
|
|
|
|
|
const int ret = eval1(arg, rettv, evaluate ? &EVALARG_EVALUATE : NULL);
|
|
|
|
|
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,8 @@ 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 ? 0 : EVAL_EVALUATE) == FAIL || skip) {
|
|
|
|
|
if (eval0((char *)arg, &tv, (char **)nextcmd, skip ? NULL : &EVALARG_EVALUATE)
|
|
|
|
|
== FAIL || skip) {
|
|
|
|
|
retval = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
retval = xstrdup(tv_get_string(&tv));
|
|
|
|
@ -853,7 +854,7 @@ int skip_expr(char **pp)
|
|
|
|
|
typval_T rettv;
|
|
|
|
|
|
|
|
|
|
*pp = skipwhite(*pp);
|
|
|
|
|
return eval1(pp, &rettv, 0);
|
|
|
|
|
return eval1(pp, &rettv, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Top level evaluation function, returning a string.
|
|
|
|
@ -868,7 +869,7 @@ char *eval_to_string(char *arg, char **nextcmd, bool convert)
|
|
|
|
|
char *retval;
|
|
|
|
|
garray_T ga;
|
|
|
|
|
|
|
|
|
|
if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL) {
|
|
|
|
|
if (eval0(arg, &tv, nextcmd, &EVALARG_EVALUATE) == FAIL) {
|
|
|
|
|
retval = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
if (convert && tv.v_type == VAR_LIST) {
|
|
|
|
@ -929,7 +930,7 @@ varnumber_T eval_to_number(char *expr)
|
|
|
|
|
|
|
|
|
|
emsg_off++;
|
|
|
|
|
|
|
|
|
|
if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL) {
|
|
|
|
|
if (eval1(&p, &rettv, &EVALARG_EVALUATE) == FAIL) {
|
|
|
|
|
retval = -1;
|
|
|
|
|
} else {
|
|
|
|
|
retval = tv_get_number_chk(&rettv, NULL);
|
|
|
|
@ -947,7 +948,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, EVAL_EVALUATE) == FAIL) {
|
|
|
|
|
if (eval0(arg, tv, NULL, &EVALARG_EVALUATE) == FAIL) {
|
|
|
|
|
XFREE_CLEAR(tv);
|
|
|
|
|
}
|
|
|
|
|
return tv;
|
|
|
|
@ -1024,7 +1025,7 @@ list_T *eval_spell_expr(char *badword, char *expr)
|
|
|
|
|
emsg_off++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (eval1(&p, &rettv, EVAL_EVALUATE) == OK) {
|
|
|
|
|
if (eval1(&p, &rettv, &EVALARG_EVALUATE) == OK) {
|
|
|
|
|
if (rettv.v_type != VAR_LIST) {
|
|
|
|
|
tv_clear(&rettv);
|
|
|
|
|
} else {
|
|
|
|
@ -1171,7 +1172,7 @@ int eval_foldexpr(char *arg, int *cp)
|
|
|
|
|
}
|
|
|
|
|
textlock++;
|
|
|
|
|
*cp = NUL;
|
|
|
|
|
if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL) {
|
|
|
|
|
if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) {
|
|
|
|
|
retval = 0;
|
|
|
|
|
} else {
|
|
|
|
|
// If the result is a number, just return the number.
|
|
|
|
@ -1346,7 +1347,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, EVAL_EVALUATE) == FAIL) { // Recursive!
|
|
|
|
|
if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL) { // Recursive!
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
if (!tv_check_str(&var1)) {
|
|
|
|
@ -1381,7 +1382,7 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const
|
|
|
|
|
} else {
|
|
|
|
|
lp->ll_empty2 = false;
|
|
|
|
|
// Recursive!
|
|
|
|
|
if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL) {
|
|
|
|
|
if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL) {
|
|
|
|
|
tv_clear(&var1);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
@ -1784,6 +1785,7 @@ void *eval_for_line(const char *arg, bool *errp, char **nextcmdp, int skip)
|
|
|
|
|
typval_T tv;
|
|
|
|
|
list_T *l;
|
|
|
|
|
|
|
|
|
|
evalarg_T evalarg = { .eval_flags = skip ? 0 : EVAL_EVALUATE };
|
|
|
|
|
*errp = true; // Default: there is an error.
|
|
|
|
|
|
|
|
|
|
expr = skip_var_list(arg, &fi->fi_varcount, &fi->fi_semicolon);
|
|
|
|
@ -1800,7 +1802,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 ? 0 : EVAL_EVALUATE) == OK) {
|
|
|
|
|
if (eval0(skipwhite(expr + 2), &tv, nextcmdp, &evalarg) == OK) {
|
|
|
|
|
*errp = false;
|
|
|
|
|
if (!skip) {
|
|
|
|
|
if (tv.v_type == VAR_LIST) {
|
|
|
|
@ -2225,10 +2227,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.
|
|
|
|
|
/// @param evalarg can be NULL, &EVALARG_EVALUATE or a pointer.
|
|
|
|
|
///
|
|
|
|
|
/// @return OK or FAIL.
|
|
|
|
|
int eval0(char *arg, typval_T *rettv, char **nextcmd, const int flags)
|
|
|
|
|
int eval0(char *arg, typval_T *rettv, char **nextcmd, evalarg_T *const evalarg)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
char *p;
|
|
|
|
@ -2237,7 +2239,7 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, const int flags)
|
|
|
|
|
bool end_error = false;
|
|
|
|
|
|
|
|
|
|
p = skipwhite(arg);
|
|
|
|
|
ret = eval1(&p, rettv, flags);
|
|
|
|
|
ret = eval1(&p, rettv, evalarg);
|
|
|
|
|
|
|
|
|
|
if (ret != FAIL) {
|
|
|
|
|
end_error = !ends_excmd(*p);
|
|
|
|
@ -2277,20 +2279,20 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, const int flags)
|
|
|
|
|
/// Note: "rettv.v_lock" is not set.
|
|
|
|
|
///
|
|
|
|
|
/// @return OK or FAIL.
|
|
|
|
|
int eval1(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
int eval1(char **arg, typval_T *rettv, evalarg_T *const evalarg)
|
|
|
|
|
{
|
|
|
|
|
typval_T var2;
|
|
|
|
|
|
|
|
|
|
// Get the first variable.
|
|
|
|
|
if (eval2(arg, rettv, flags) == FAIL) {
|
|
|
|
|
if (eval2(arg, rettv, evalarg) == FAIL) {
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((*arg)[0] == '?') {
|
|
|
|
|
const bool evaluate = flags & EVAL_EVALUATE;
|
|
|
|
|
evalarg_T nested_evalarg = evalarg == NULL ? (evalarg_T){ 0 } : *evalarg;
|
|
|
|
|
const int orig_flags = evalarg == NULL ? 0 : evalarg->eval_flags;
|
|
|
|
|
const bool evaluate = nested_evalarg.eval_flags & EVAL_EVALUATE;
|
|
|
|
|
|
|
|
|
|
bool result = false;
|
|
|
|
|
if (flags & EVAL_EVALUATE) {
|
|
|
|
|
if (evaluate) {
|
|
|
|
|
bool error = false;
|
|
|
|
|
|
|
|
|
|
if (tv_get_number_chk(rettv, &error) != 0) {
|
|
|
|
@ -2304,7 +2306,8 @@ int eval1(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
|
|
|
|
|
// Get the second variable. Recursive!
|
|
|
|
|
*arg = skipwhite(*arg + 1);
|
|
|
|
|
if (eval1(arg, rettv, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) {
|
|
|
|
|
nested_evalarg.eval_flags = result ? orig_flags : orig_flags & ~EVAL_EVALUATE;
|
|
|
|
|
if (eval1(arg, rettv, &nested_evalarg) == FAIL) {
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2319,7 +2322,9 @@ int eval1(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
|
|
|
|
|
// Get the third variable. Recursive!
|
|
|
|
|
*arg = skipwhite(*arg + 1);
|
|
|
|
|
if (eval1(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) {
|
|
|
|
|
typval_T var2;
|
|
|
|
|
nested_evalarg.eval_flags = !result ? orig_flags : orig_flags & ~EVAL_EVALUATE;
|
|
|
|
|
if (eval1(arg, &var2, &nested_evalarg) == FAIL) {
|
|
|
|
|
if (evaluate && result) {
|
|
|
|
|
tv_clear(rettv);
|
|
|
|
|
}
|
|
|
|
@ -2340,13 +2345,13 @@ int eval1(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
/// "arg" is advanced to the next non-white after the recognized expression.
|
|
|
|
|
///
|
|
|
|
|
/// @return OK or FAIL.
|
|
|
|
|
static int eval2(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
static int eval2(char **arg, typval_T *rettv, evalarg_T *const evalarg)
|
|
|
|
|
{
|
|
|
|
|
typval_T var2;
|
|
|
|
|
bool error = false;
|
|
|
|
|
|
|
|
|
|
// Get the first variable.
|
|
|
|
|
if (eval3(arg, rettv, flags) == FAIL) {
|
|
|
|
|
if (eval3(arg, rettv, evalarg) == FAIL) {
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2354,7 +2359,9 @@ static int eval2(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
bool first = true;
|
|
|
|
|
bool result = false;
|
|
|
|
|
while ((*arg)[0] == '|' && (*arg)[1] == '|') {
|
|
|
|
|
const bool evaluate = flags & EVAL_EVALUATE;
|
|
|
|
|
evalarg_T nested_evalarg = evalarg == NULL ? (evalarg_T){ 0 } : *evalarg;
|
|
|
|
|
const int orig_flags = evalarg == NULL ? 0 : evalarg->eval_flags;
|
|
|
|
|
const bool evaluate = orig_flags & EVAL_EVALUATE;
|
|
|
|
|
|
|
|
|
|
if (evaluate && first) {
|
|
|
|
|
if (tv_get_number_chk(rettv, &error) != 0) {
|
|
|
|
@ -2369,7 +2376,8 @@ static int eval2(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
|
|
|
|
|
// Get the second variable.
|
|
|
|
|
*arg = skipwhite(*arg + 2);
|
|
|
|
|
if (eval3(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) {
|
|
|
|
|
nested_evalarg.eval_flags = !result ? orig_flags : orig_flags & ~EVAL_EVALUATE;
|
|
|
|
|
if (eval3(arg, &var2, &nested_evalarg) == FAIL) {
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2399,13 +2407,13 @@ static int eval2(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
/// `arg` is advanced to the next non-white after the recognized expression.
|
|
|
|
|
///
|
|
|
|
|
/// @return OK or FAIL.
|
|
|
|
|
static int eval3(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
static int eval3(char **arg, typval_T *rettv, evalarg_T *const evalarg)
|
|
|
|
|
{
|
|
|
|
|
typval_T var2;
|
|
|
|
|
bool error = false;
|
|
|
|
|
|
|
|
|
|
// Get the first variable.
|
|
|
|
|
if (eval4(arg, rettv, flags) == FAIL) {
|
|
|
|
|
if (eval4(arg, rettv, evalarg) == FAIL) {
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2413,7 +2421,9 @@ static int eval3(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
bool first = true;
|
|
|
|
|
bool result = true;
|
|
|
|
|
while ((*arg)[0] == '&' && (*arg)[1] == '&') {
|
|
|
|
|
const bool evaluate = flags & EVAL_EVALUATE;
|
|
|
|
|
evalarg_T nested_evalarg = evalarg == NULL ? (evalarg_T){ 0 } : *evalarg;
|
|
|
|
|
const int orig_flags = evalarg == NULL ? 0 : evalarg->eval_flags;
|
|
|
|
|
const bool evaluate = orig_flags & EVAL_EVALUATE;
|
|
|
|
|
|
|
|
|
|
if (evaluate && first) {
|
|
|
|
|
if (tv_get_number_chk(rettv, &error) == 0) {
|
|
|
|
@ -2428,7 +2438,8 @@ static int eval3(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
|
|
|
|
|
// Get the second variable.
|
|
|
|
|
*arg = skipwhite(*arg + 2);
|
|
|
|
|
if (eval4(arg, &var2, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) {
|
|
|
|
|
nested_evalarg.eval_flags = result ? orig_flags : orig_flags & ~EVAL_EVALUATE;
|
|
|
|
|
if (eval4(arg, &var2, &nested_evalarg) == FAIL) {
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2467,7 +2478,7 @@ static int eval3(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
/// "arg" is advanced to the next non-white after the recognized expression.
|
|
|
|
|
///
|
|
|
|
|
/// @return OK or FAIL.
|
|
|
|
|
static int eval4(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
static int eval4(char **arg, typval_T *rettv, evalarg_T *const evalarg)
|
|
|
|
|
{
|
|
|
|
|
typval_T var2;
|
|
|
|
|
char *p;
|
|
|
|
@ -2475,7 +2486,7 @@ static int eval4(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
int len = 2;
|
|
|
|
|
|
|
|
|
|
// Get the first variable.
|
|
|
|
|
if (eval5(arg, rettv, flags) == FAIL) {
|
|
|
|
|
if (eval5(arg, rettv, evalarg) == FAIL) {
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2539,11 +2550,11 @@ static int eval4(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
|
|
|
|
|
// Get the second variable.
|
|
|
|
|
*arg = skipwhite(p + len);
|
|
|
|
|
if (eval5(arg, &var2, flags) == FAIL) {
|
|
|
|
|
if (eval5(arg, &var2, evalarg) == FAIL) {
|
|
|
|
|
tv_clear(rettv);
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
if (flags & EVAL_EVALUATE) {
|
|
|
|
|
if (evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE)) {
|
|
|
|
|
const int ret = typval_compare(rettv, &var2, type, ic);
|
|
|
|
|
|
|
|
|
|
tv_clear(&var2);
|
|
|
|
@ -2597,27 +2608,25 @@ 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, const int flags)
|
|
|
|
|
static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg)
|
|
|
|
|
{
|
|
|
|
|
typval_T var2;
|
|
|
|
|
varnumber_T n1, n2;
|
|
|
|
|
float_T f1 = 0, f2 = 0;
|
|
|
|
|
char *p;
|
|
|
|
|
const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
|
|
|
|
|
|
|
|
|
|
// Get the first variable.
|
|
|
|
|
if (eval6(arg, rettv, flags, false) == FAIL) {
|
|
|
|
|
if (eval6(arg, rettv, evalarg, false) == FAIL) {
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Repeat computing, until no '+', '-' or '.' is following.
|
|
|
|
|
for (;;) {
|
|
|
|
|
int op = (uint8_t)(**arg);
|
|
|
|
|
if (op != '+' && op != '-' && op != '.') {
|
|
|
|
|
bool concat = op == '.';
|
|
|
|
|
if (op != '+' && op != '-' && !concat) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((op != '+' || (rettv->v_type != VAR_LIST && rettv->v_type != VAR_BLOB))
|
|
|
|
|
&& (op == '.' || rettv->v_type != VAR_FLOAT) && (flags & EVAL_EVALUATE)) {
|
|
|
|
|
&& (op == '.' || rettv->v_type != VAR_FLOAT) && 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.
|
|
|
|
@ -2636,12 +2645,13 @@ static int eval5(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
(*arg)++;
|
|
|
|
|
}
|
|
|
|
|
*arg = skipwhite(*arg + 1);
|
|
|
|
|
if (eval6(arg, &var2, flags, op == '.') == FAIL) {
|
|
|
|
|
typval_T var2;
|
|
|
|
|
if (eval6(arg, &var2, evalarg, op == '.') == FAIL) {
|
|
|
|
|
tv_clear(rettv);
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (flags & EVAL_EVALUATE) {
|
|
|
|
|
if (evaluate) {
|
|
|
|
|
// Compute the result.
|
|
|
|
|
if (op == '.') {
|
|
|
|
|
char buf1[NUMBUFLEN];
|
|
|
|
@ -2654,7 +2664,7 @@ static int eval5(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
tv_clear(&var2);
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
p = concat_str(s1, s2);
|
|
|
|
|
char *p = concat_str(s1, s2);
|
|
|
|
|
tv_clear(rettv);
|
|
|
|
|
rettv->v_type = VAR_STRING;
|
|
|
|
|
rettv->vval.v_string = p;
|
|
|
|
@ -2666,6 +2676,8 @@ static int eval5(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
bool error = false;
|
|
|
|
|
varnumber_T n1, n2;
|
|
|
|
|
float_T f1 = 0, f2 = 0;
|
|
|
|
|
|
|
|
|
|
if (rettv->v_type == VAR_FLOAT) {
|
|
|
|
|
f1 = rettv->vval.v_float;
|
|
|
|
@ -2738,7 +2750,7 @@ static int eval5(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
/// @param[in] want_string True if "." is string_concatenation, otherwise
|
|
|
|
|
/// float
|
|
|
|
|
/// @return OK or FAIL.
|
|
|
|
|
static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string)
|
|
|
|
|
static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool want_string)
|
|
|
|
|
FUNC_ATTR_NO_SANITIZE_UNDEFINED
|
|
|
|
|
{
|
|
|
|
|
typval_T var2;
|
|
|
|
@ -2749,18 +2761,19 @@ static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string)
|
|
|
|
|
bool error = false;
|
|
|
|
|
|
|
|
|
|
// Get the first variable.
|
|
|
|
|
if (eval7(arg, rettv, flags, want_string) == FAIL) {
|
|
|
|
|
if (eval7(arg, rettv, evalarg, want_string) == FAIL) {
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Repeat computing, until no '*', '/' or '%' is following.
|
|
|
|
|
for (;;) {
|
|
|
|
|
const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
|
|
|
|
|
op = (uint8_t)(**arg);
|
|
|
|
|
if (op != '*' && op != '/' && op != '%') {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (flags & EVAL_EVALUATE) {
|
|
|
|
|
if (evaluate) {
|
|
|
|
|
if (rettv->v_type == VAR_FLOAT) {
|
|
|
|
|
f1 = rettv->vval.v_float;
|
|
|
|
|
use_float = true;
|
|
|
|
@ -2778,11 +2791,11 @@ static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string)
|
|
|
|
|
|
|
|
|
|
// Get the second variable.
|
|
|
|
|
*arg = skipwhite(*arg + 1);
|
|
|
|
|
if (eval7(arg, &var2, flags, false) == FAIL) {
|
|
|
|
|
if (eval7(arg, &var2, evalarg, false) == FAIL) {
|
|
|
|
|
return FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (flags & EVAL_EVALUATE) {
|
|
|
|
|
if (evaluate) {
|
|
|
|
|
if (var2.v_type == VAR_FLOAT) {
|
|
|
|
|
if (!use_float) {
|
|
|
|
|
f1 = (float_T)n1;
|
|
|
|
@ -2869,9 +2882,10 @@ static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string)
|
|
|
|
|
/// @param want_string after "." operator
|
|
|
|
|
///
|
|
|
|
|
/// @return OK or FAIL.
|
|
|
|
|
static int eval7(char **arg, typval_T *rettv, const int flags, bool want_string)
|
|
|
|
|
static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool want_string)
|
|
|
|
|
{
|
|
|
|
|
const bool evaluate = flags & EVAL_EVALUATE;
|
|
|
|
|
const int flags = evalarg == NULL ? 0 : evalarg->eval_flags;
|
|
|
|
|
const bool evaluate = evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE);
|
|
|
|
|
int ret = OK;
|
|
|
|
|
static int recurse = 0;
|
|
|
|
|
|
|
|
|
@ -2979,7 +2993,7 @@ static int eval7(char **arg, typval_T *rettv, const int flags, bool want_string)
|
|
|
|
|
// nested expression: (expression).
|
|
|
|
|
case '(':
|
|
|
|
|
*arg = skipwhite(*arg + 1);
|
|
|
|
|
ret = eval1(arg, rettv, flags); // recursive!
|
|
|
|
|
ret = eval1(arg, rettv, evalarg); // recursive!
|
|
|
|
|
if (**arg == ')') {
|
|
|
|
|
(*arg)++;
|
|
|
|
|
} else if (ret == OK) {
|
|
|
|
@ -3319,13 +3333,15 @@ static int eval_index(char **arg, typval_T *rettv, const int flags, bool verbose
|
|
|
|
|
}
|
|
|
|
|
*arg = skipwhite(key + len);
|
|
|
|
|
} else {
|
|
|
|
|
evalarg_T evalarg = { .eval_flags = flags };
|
|
|
|
|
|
|
|
|
|
// something[idx]
|
|
|
|
|
//
|
|
|
|
|
// Get the (first) variable from inside the [].
|
|
|
|
|
*arg = skipwhite(*arg + 1);
|
|
|
|
|
if (**arg == ':') {
|
|
|
|
|
empty1 = true;
|
|
|
|
|
} else if (eval1(arg, &var1, flags) == FAIL) { // Recursive!
|
|
|
|
|
} else if (eval1(arg, &var1, &evalarg) == FAIL) { // Recursive!
|
|
|
|
|
return FAIL;
|
|
|
|
|
} else if (evaluate && !tv_check_str(&var1)) {
|
|
|
|
|
// Not a number or string.
|
|
|
|
@ -3339,7 +3355,7 @@ static int eval_index(char **arg, typval_T *rettv, const int flags, bool verbose
|
|
|
|
|
*arg = skipwhite(*arg + 1);
|
|
|
|
|
if (**arg == ']') {
|
|
|
|
|
empty2 = true;
|
|
|
|
|
} else if (eval1(arg, &var2, flags) == FAIL) { // Recursive!
|
|
|
|
|
} else if (eval1(arg, &var2, &evalarg) == FAIL) { // Recursive!
|
|
|
|
|
if (!empty1) {
|
|
|
|
|
tv_clear(&var1);
|
|
|
|
|
}
|
|
|
|
@ -3947,6 +3963,8 @@ static int get_list_tv(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
const bool evaluate = flags & EVAL_EVALUATE;
|
|
|
|
|
list_T *l = NULL;
|
|
|
|
|
|
|
|
|
|
evalarg_T evalarg = { .eval_flags = flags };
|
|
|
|
|
|
|
|
|
|
if (evaluate) {
|
|
|
|
|
l = tv_list_alloc(kListLenShouldKnow);
|
|
|
|
|
}
|
|
|
|
@ -3954,7 +3972,7 @@ static int get_list_tv(char **arg, typval_T *rettv, const int flags)
|
|
|
|
|
*arg = skipwhite(*arg + 1);
|
|
|
|
|
while (**arg != ']' && **arg != NUL) {
|
|
|
|
|
typval_T tv;
|
|
|
|
|
if (eval1(arg, &tv, flags) == FAIL) { // Recursive!
|
|
|
|
|
if (eval1(arg, &tv, &evalarg) == FAIL) { // Recursive!
|
|
|
|
|
goto failret;
|
|
|
|
|
}
|
|
|
|
|
if (evaluate) {
|
|
|
|
@ -4586,7 +4604,9 @@ static int get_literal_key(char **arg, typval_T *tv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Allocate a variable for a Dictionary and fill it from "*arg".
|
|
|
|
|
/// "literal" is true for #{key: val}
|
|
|
|
|
///
|
|
|
|
|
/// @param literal true for #{key: val}
|
|
|
|
|
/// @param flags can have EVAL_EVALUATE and other EVAL_ flags.
|
|
|
|
|
///
|
|
|
|
|
/// @return OK or FAIL. Returns NOTDONE for {expr}.
|
|
|
|
|
static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal)
|
|
|
|
@ -4597,6 +4617,8 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal)
|
|
|
|
|
char *curly_expr = skipwhite(*arg + 1);
|
|
|
|
|
char buf[NUMBUFLEN];
|
|
|
|
|
|
|
|
|
|
evalarg_T evalarg = { .eval_flags = flags };
|
|
|
|
|
|
|
|
|
|
// First check if it's not a curly-braces expression: {expr}.
|
|
|
|
|
// Must do this without evaluating, otherwise a function may be called
|
|
|
|
|
// twice. Unfortunately this means we need to call eval1() twice for the
|
|
|
|
@ -4605,7 +4627,7 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal)
|
|
|
|
|
// "#{abc}" is never a curly-braces expression.
|
|
|
|
|
if (*curly_expr != '}'
|
|
|
|
|
&& !literal
|
|
|
|
|
&& eval1(&curly_expr, &tv, 0) == OK
|
|
|
|
|
&& eval1(&curly_expr, &tv, NULL) == OK
|
|
|
|
|
&& *skipwhite(curly_expr) == '}') {
|
|
|
|
|
return NOTDONE;
|
|
|
|
|
}
|
|
|
|
@ -4622,7 +4644,7 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal)
|
|
|
|
|
while (**arg != '}' && **arg != NUL) {
|
|
|
|
|
if ((literal
|
|
|
|
|
? get_literal_key(arg, &tvkey)
|
|
|
|
|
: eval1(arg, &tvkey, flags)) == FAIL) { // recursive!
|
|
|
|
|
: eval1(arg, &tvkey, &evalarg)) == FAIL) { // recursive!
|
|
|
|
|
goto failret;
|
|
|
|
|
}
|
|
|
|
|
if (**arg != ':') {
|
|
|
|
@ -4640,7 +4662,7 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*arg = skipwhite(*arg + 1);
|
|
|
|
|
if (eval1(arg, &tv, flags) == FAIL) { // Recursive!
|
|
|
|
|
if (eval1(arg, &tv, &evalarg) == FAIL) { // Recursive!
|
|
|
|
|
if (evaluate) {
|
|
|
|
|
tv_clear(&tvkey);
|
|
|
|
|
}
|
|
|
|
@ -7389,6 +7411,8 @@ void ex_echo(exarg_T *eap)
|
|
|
|
|
const int did_emsg_before = did_emsg;
|
|
|
|
|
const int called_emsg_before = called_emsg;
|
|
|
|
|
|
|
|
|
|
evalarg_T evalarg = { .eval_flags = eap->skip ? 0 : EVAL_EVALUATE };
|
|
|
|
|
|
|
|
|
|
if (eap->skip) {
|
|
|
|
|
emsg_skip++;
|
|
|
|
|
}
|
|
|
|
@ -7399,7 +7423,7 @@ void ex_echo(exarg_T *eap)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
char *p = arg;
|
|
|
|
|
if (eval1(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE) == FAIL) {
|
|
|
|
|
if (eval1(&arg, &rettv, &evalarg) == FAIL) {
|
|
|
|
|
// Report the invalid expression unless the expression evaluation
|
|
|
|
|
// has been cancelled due to an aborting error, an interrupt, or an
|
|
|
|
|
// exception.
|
|
|
|
|