Merge pull request #23078 from zeertzjq/vim-8.2.1047

vim-patch:8.2.{1047,1048,1049,1050,1052},9.0.1447
This commit is contained in:
zeertzjq
2023-04-14 10:58:29 +08:00
committed by GitHub
18 changed files with 207 additions and 136 deletions

View File

@@ -172,7 +172,7 @@ Object nvim_eval(String expr, Error *err)
int ok; int ok;
TRY_WRAP(err, { TRY_WRAP(err, {
ok = eval0(expr.data, &rettv, NULL, EVAL_EVALUATE); ok = eval0(expr.data, &rettv, NULL, &EVALARG_EVALUATE);
}); });
if (!ERROR_SET(err)) { if (!ERROR_SET(err)) {
@@ -290,7 +290,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err)
switch (dict.type) { switch (dict.type) {
case kObjectTypeString: case kObjectTypeString:
try_start(); try_start();
if (eval0(dict.data.string.data, &rettv, NULL, EVAL_EVALUATE) == FAIL) { if (eval0(dict.data.string.data, &rettv, NULL, &EVALARG_EVALUATE) == FAIL) {
api_set_error(err, kErrorTypeException, api_set_error(err, kErrorTypeException,
"Failed to evaluate dict expression"); "Failed to evaluate dict expression");
} }

View File

@@ -2203,7 +2203,7 @@ bool get_keymap_str(win_T *wp, char *fmt, char *buf, int len)
curwin = wp; curwin = wp;
STRCPY(buf, "b:keymap_name"); // must be writable STRCPY(buf, "b:keymap_name"); // must be writable
emsg_skip++; emsg_skip++;
s = p = eval_to_string(buf, NULL, false); s = p = eval_to_string(buf, false);
emsg_skip--; emsg_skip--;
curbuf = old_curbuf; curbuf = old_curbuf;
curwin = old_curwin; curwin = old_curwin;

View File

@@ -698,7 +698,7 @@ void eval_patch(const char *const origfile, const char *const difffile, const ch
/// @param skip only parse, don't execute /// @param skip only parse, don't execute
/// ///
/// @return true or false. /// @return true or false.
int eval_to_bool(char *arg, bool *error, char **nextcmd, int skip) int eval_to_bool(char *arg, bool *error, exarg_T *eap, int skip)
{ {
typval_T tv; typval_T tv;
bool retval = false; bool retval = false;
@@ -706,7 +706,7 @@ int eval_to_bool(char *arg, bool *error, char **nextcmd, int skip)
if (skip) { if (skip) {
emsg_skip++; emsg_skip++;
} }
if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL) { if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_EVALUATE) == FAIL) {
*error = true; *error = true;
} else { } else {
*error = false; *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 did_emsg_before = did_emsg;
const int called_emsg_before = called_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) { if (ret == FAIL) {
// Report the invalid expression unless the expression evaluation has // Report the invalid expression unless the expression evaluation has
// been cancelled due to an aborting error, an interrupt, or an // been cancelled due to an aborting error, an interrupt, or an
@@ -817,13 +817,12 @@ bool eval_expr_to_bool(const typval_T *expr, bool *error)
/// Top level evaluation function, returning a string /// Top level evaluation function, returning a string
/// ///
/// @param[in] arg String to evaluate. /// @param[in] arg String to evaluate.
/// @param nextcmd Pointer to the start of the next Ex command.
/// @param[in] skip If true, only do parsing to nextcmd without reporting /// @param[in] skip If true, only do parsing to nextcmd without reporting
/// errors or actually evaluating anything. /// errors or actually evaluating anything.
/// ///
/// @return [allocated] string result of evaluation or NULL in case of error or /// @return [allocated] string result of evaluation or NULL in case of error or
/// when skipping. /// when skipping.
char *eval_to_string_skip(const char *arg, const char **nextcmd, const bool skip) char *eval_to_string_skip(char *arg, exarg_T *eap, const bool skip)
FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT
{ {
typval_T tv; typval_T tv;
@@ -832,7 +831,7 @@ char *eval_to_string_skip(const char *arg, const char **nextcmd, const bool skip
if (skip) { if (skip) {
emsg_skip++; emsg_skip++;
} }
if (eval0((char *)arg, &tv, (char **)nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL || skip) { if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_EVALUATE) == FAIL || skip) {
retval = NULL; retval = NULL;
} else { } else {
retval = xstrdup(tv_get_string(&tv)); retval = xstrdup(tv_get_string(&tv));
@@ -853,7 +852,7 @@ int skip_expr(char **pp)
typval_T rettv; typval_T rettv;
*pp = skipwhite(*pp); *pp = skipwhite(*pp);
return eval1(pp, &rettv, 0); return eval1(pp, &rettv, NULL);
} }
/// Top level evaluation function, returning a string. /// Top level evaluation function, returning a string.
@@ -862,13 +861,13 @@ int skip_expr(char **pp)
/// a Float to a String. /// a Float to a String.
/// ///
/// @return pointer to allocated memory, or NULL for failure. /// @return pointer to allocated memory, or NULL for failure.
char *eval_to_string(char *arg, char **nextcmd, bool convert) char *eval_to_string(char *arg, bool convert)
{ {
typval_T tv; typval_T tv;
char *retval; char *retval;
garray_T ga; garray_T ga;
if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL) { if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) {
retval = NULL; retval = NULL;
} else { } else {
if (convert && tv.v_type == VAR_LIST) { if (convert && tv.v_type == VAR_LIST) {
@@ -898,7 +897,7 @@ char *eval_to_string(char *arg, char **nextcmd, bool convert)
/// textlock. /// textlock.
/// ///
/// @param use_sandbox when true, use the sandbox. /// @param use_sandbox when true, use the sandbox.
char *eval_to_string_safe(char *arg, char **nextcmd, int use_sandbox) char *eval_to_string_safe(char *arg, int use_sandbox)
{ {
char *retval; char *retval;
funccal_entry_T funccal_entry; funccal_entry_T funccal_entry;
@@ -908,7 +907,7 @@ char *eval_to_string_safe(char *arg, char **nextcmd, int use_sandbox)
sandbox++; sandbox++;
} }
textlock++; textlock++;
retval = eval_to_string(arg, nextcmd, false); retval = eval_to_string(arg, false);
if (use_sandbox) { if (use_sandbox) {
sandbox--; sandbox--;
} }
@@ -929,7 +928,7 @@ varnumber_T eval_to_number(char *expr)
emsg_off++; emsg_off++;
if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL) { if (eval1(&p, &rettv, &EVALARG_EVALUATE) == FAIL) {
retval = -1; retval = -1;
} else { } else {
retval = tv_get_number_chk(&rettv, NULL); retval = tv_get_number_chk(&rettv, NULL);
@@ -947,7 +946,7 @@ varnumber_T eval_to_number(char *expr)
typval_T *eval_expr(char *arg) typval_T *eval_expr(char *arg)
{ {
typval_T *tv = xmalloc(sizeof(*tv)); 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); XFREE_CLEAR(tv);
} }
return tv; return tv;
@@ -1024,7 +1023,7 @@ list_T *eval_spell_expr(char *badword, char *expr)
emsg_off++; emsg_off++;
} }
if (eval1(&p, &rettv, EVAL_EVALUATE) == OK) { if (eval1(&p, &rettv, &EVALARG_EVALUATE) == OK) {
if (rettv.v_type != VAR_LIST) { if (rettv.v_type != VAR_LIST) {
tv_clear(&rettv); tv_clear(&rettv);
} else { } else {
@@ -1171,7 +1170,7 @@ int eval_foldexpr(char *arg, int *cp)
} }
textlock++; textlock++;
*cp = NUL; *cp = NUL;
if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL) { if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) {
retval = 0; retval = 0;
} else { } else {
// If the result is a number, just return the number. // If the result is a number, just return the number.
@@ -1346,7 +1345,7 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const
empty1 = true; empty1 = true;
} else { } else {
empty1 = false; empty1 = false;
if (eval1(&p, &var1, EVAL_EVALUATE) == FAIL) { // Recursive! if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL) { // Recursive!
return NULL; return NULL;
} }
if (!tv_check_str(&var1)) { if (!tv_check_str(&var1)) {
@@ -1381,7 +1380,7 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const
} else { } else {
lp->ll_empty2 = false; lp->ll_empty2 = false;
// Recursive! // Recursive!
if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL) { if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL) {
tv_clear(&var1); tv_clear(&var1);
return NULL; return NULL;
} }
@@ -1777,13 +1776,14 @@ notify:
/// @param[out] *errp set to true for an error, false otherwise; /// @param[out] *errp set to true for an error, false otherwise;
/// ///
/// @return a pointer that holds the info. Null when there is an error. /// @return a pointer that holds the info. Null when there is an error.
void *eval_for_line(const char *arg, bool *errp, char **nextcmdp, int skip) void *eval_for_line(const char *arg, bool *errp, exarg_T *eap, int skip)
{ {
forinfo_T *fi = xcalloc(1, sizeof(forinfo_T)); forinfo_T *fi = xcalloc(1, sizeof(forinfo_T));
const char *expr; const char *expr;
typval_T tv; typval_T tv;
list_T *l; list_T *l;
evalarg_T evalarg = { .eval_flags = skip ? 0 : EVAL_EVALUATE };
*errp = true; // Default: there is an error. *errp = true; // Default: there is an error.
expr = skip_var_list(arg, &fi->fi_varcount, &fi->fi_semicolon); expr = skip_var_list(arg, &fi->fi_varcount, &fi->fi_semicolon);
@@ -1800,7 +1800,7 @@ void *eval_for_line(const char *arg, bool *errp, char **nextcmdp, int skip)
if (skip) { if (skip) {
emsg_skip++; emsg_skip++;
} }
if (eval0(skipwhite(expr + 2), &tv, nextcmdp, skip ? 0 : EVAL_EVALUATE) == OK) { if (eval0(skipwhite(expr + 2), &tv, eap, &evalarg) == OK) {
*errp = false; *errp = false;
if (!skip) { if (!skip) {
if (tv.v_type == VAR_LIST) { if (tv.v_type == VAR_LIST) {
@@ -2225,10 +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. /// Put the result in "rettv" when returning OK and "evaluate" is true.
/// Note: "rettv.v_lock" is not set. /// 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. /// @return OK or FAIL.
int eval0(char *arg, typval_T *rettv, char **nextcmd, const int flags) int eval0(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg)
{ {
int ret; int ret;
char *p; char *p;
@@ -2236,8 +2236,11 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, const int flags)
const int called_emsg_before = called_emsg; const int called_emsg_before = called_emsg;
bool end_error = false; bool end_error = false;
if (evalarg != NULL) {
evalarg->eval_tofree = NULL;
}
p = skipwhite(arg); p = skipwhite(arg);
ret = eval1(&p, rettv, flags); ret = eval1(&p, rettv, evalarg);
if (ret != FAIL) { if (ret != FAIL) {
end_error = !ends_excmd(*p); end_error = !ends_excmd(*p);
@@ -2261,8 +2264,24 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, const int flags)
} }
ret = FAIL; ret = FAIL;
} }
if (nextcmd != NULL) {
*nextcmd = check_nextcmd(p); if (eap != NULL) {
eap->nextcmd = check_nextcmd(p);
}
if (evalarg != NULL) {
if (eap != NULL) {
if (evalarg->eval_tofree != NULL) {
// We may need to keep the original command line, e.g. for
// ":let" it has the variable names. But we may also need the
// new one, "nextcmd" points into it. Keep both.
xfree(eap->cmdline_tofree);
eap->cmdline_tofree = *eap->cmdlinep;
*eap->cmdlinep = evalarg->eval_tofree;
}
} else {
xfree(evalarg->eval_tofree);
}
} }
return ret; return ret;
@@ -2277,20 +2296,20 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, const int flags)
/// Note: "rettv.v_lock" is not set. /// Note: "rettv.v_lock" is not set.
/// ///
/// @return OK or FAIL. /// @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. // Get the first variable.
if (eval2(arg, rettv, flags) == FAIL) { if (eval2(arg, rettv, evalarg) == FAIL) {
return FAIL; return FAIL;
} }
if ((*arg)[0] == '?') { 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; bool result = false;
if (flags & EVAL_EVALUATE) { if (evaluate) {
bool error = false; bool error = false;
if (tv_get_number_chk(rettv, &error) != 0) { if (tv_get_number_chk(rettv, &error) != 0) {
@@ -2304,7 +2323,8 @@ int eval1(char **arg, typval_T *rettv, const int flags)
// Get the second variable. Recursive! // Get the second variable. Recursive!
*arg = skipwhite(*arg + 1); *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; return FAIL;
} }
@@ -2319,7 +2339,9 @@ int eval1(char **arg, typval_T *rettv, const int flags)
// Get the third variable. Recursive! // Get the third variable. Recursive!
*arg = skipwhite(*arg + 1); *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) { if (evaluate && result) {
tv_clear(rettv); tv_clear(rettv);
} }
@@ -2340,13 +2362,13 @@ int eval1(char **arg, typval_T *rettv, const int flags)
/// "arg" is advanced to the next non-white after the recognized expression. /// "arg" is advanced to the next non-white after the recognized expression.
/// ///
/// @return OK or FAIL. /// @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; typval_T var2;
bool error = false; bool error = false;
// Get the first variable. // Get the first variable.
if (eval3(arg, rettv, flags) == FAIL) { if (eval3(arg, rettv, evalarg) == FAIL) {
return FAIL; return FAIL;
} }
@@ -2354,7 +2376,9 @@ static int eval2(char **arg, typval_T *rettv, const int flags)
bool first = true; bool first = true;
bool result = false; bool result = false;
while ((*arg)[0] == '|' && (*arg)[1] == '|') { 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 (evaluate && first) {
if (tv_get_number_chk(rettv, &error) != 0) { if (tv_get_number_chk(rettv, &error) != 0) {
@@ -2369,7 +2393,8 @@ static int eval2(char **arg, typval_T *rettv, const int flags)
// Get the second variable. // Get the second variable.
*arg = skipwhite(*arg + 2); *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; return FAIL;
} }
@@ -2399,13 +2424,13 @@ static int eval2(char **arg, typval_T *rettv, const int flags)
/// `arg` is advanced to the next non-white after the recognized expression. /// `arg` is advanced to the next non-white after the recognized expression.
/// ///
/// @return OK or FAIL. /// @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; typval_T var2;
bool error = false; bool error = false;
// Get the first variable. // Get the first variable.
if (eval4(arg, rettv, flags) == FAIL) { if (eval4(arg, rettv, evalarg) == FAIL) {
return FAIL; return FAIL;
} }
@@ -2413,7 +2438,9 @@ static int eval3(char **arg, typval_T *rettv, const int flags)
bool first = true; bool first = true;
bool result = true; bool result = true;
while ((*arg)[0] == '&' && (*arg)[1] == '&') { 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 (evaluate && first) {
if (tv_get_number_chk(rettv, &error) == 0) { if (tv_get_number_chk(rettv, &error) == 0) {
@@ -2428,7 +2455,8 @@ static int eval3(char **arg, typval_T *rettv, const int flags)
// Get the second variable. // Get the second variable.
*arg = skipwhite(*arg + 2); *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; return FAIL;
} }
@@ -2467,7 +2495,7 @@ static int eval3(char **arg, typval_T *rettv, const int flags)
/// "arg" is advanced to the next non-white after the recognized expression. /// "arg" is advanced to the next non-white after the recognized expression.
/// ///
/// @return OK or FAIL. /// @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; typval_T var2;
char *p; char *p;
@@ -2475,7 +2503,7 @@ static int eval4(char **arg, typval_T *rettv, const int flags)
int len = 2; int len = 2;
// Get the first variable. // Get the first variable.
if (eval5(arg, rettv, flags) == FAIL) { if (eval5(arg, rettv, evalarg) == FAIL) {
return FAIL; return FAIL;
} }
@@ -2539,11 +2567,11 @@ static int eval4(char **arg, typval_T *rettv, const int flags)
// Get the second variable. // Get the second variable.
*arg = skipwhite(p + len); *arg = skipwhite(p + len);
if (eval5(arg, &var2, flags) == FAIL) { if (eval5(arg, &var2, evalarg) == FAIL) {
tv_clear(rettv); tv_clear(rettv);
return FAIL; return FAIL;
} }
if (flags & EVAL_EVALUATE) { if (evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE)) {
const int ret = typval_compare(rettv, &var2, type, ic); const int ret = typval_compare(rettv, &var2, type, ic);
tv_clear(&var2); tv_clear(&var2);
@@ -2597,27 +2625,25 @@ static int eval_addlist(typval_T *tv1, typval_T *tv2)
/// `arg` is advanced to the next non-white after the recognized expression. /// `arg` is advanced to the next non-white after the recognized expression.
/// ///
/// @return OK or FAIL. /// @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; const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
varnumber_T n1, n2;
float_T f1 = 0, f2 = 0;
char *p;
// Get the first variable. // Get the first variable.
if (eval6(arg, rettv, flags, false) == FAIL) { if (eval6(arg, rettv, evalarg, false) == FAIL) {
return FAIL; return FAIL;
} }
// Repeat computing, until no '+', '-' or '.' is following. // Repeat computing, until no '+', '-' or '.' is following.
for (;;) { for (;;) {
int op = (uint8_t)(**arg); int op = (uint8_t)(**arg);
if (op != '+' && op != '-' && op != '.') { bool concat = op == '.';
if (op != '+' && op != '-' && !concat) {
break; break;
} }
if ((op != '+' || (rettv->v_type != VAR_LIST && rettv->v_type != VAR_BLOB)) 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 // For "list + ...", an illegal use of the first operand as
// a number cannot be determined before evaluating the 2nd // a number cannot be determined before evaluating the 2nd
// operand: if this is also a list, all is ok. // operand: if this is also a list, all is ok.
@@ -2636,12 +2662,13 @@ static int eval5(char **arg, typval_T *rettv, const int flags)
(*arg)++; (*arg)++;
} }
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
if (eval6(arg, &var2, flags, op == '.') == FAIL) { typval_T var2;
if (eval6(arg, &var2, evalarg, op == '.') == FAIL) {
tv_clear(rettv); tv_clear(rettv);
return FAIL; return FAIL;
} }
if (flags & EVAL_EVALUATE) { if (evaluate) {
// Compute the result. // Compute the result.
if (op == '.') { if (op == '.') {
char buf1[NUMBUFLEN]; char buf1[NUMBUFLEN];
@@ -2654,7 +2681,7 @@ static int eval5(char **arg, typval_T *rettv, const int flags)
tv_clear(&var2); tv_clear(&var2);
return FAIL; return FAIL;
} }
p = concat_str(s1, s2); char *p = concat_str(s1, s2);
tv_clear(rettv); tv_clear(rettv);
rettv->v_type = VAR_STRING; rettv->v_type = VAR_STRING;
rettv->vval.v_string = p; rettv->vval.v_string = p;
@@ -2666,6 +2693,8 @@ static int eval5(char **arg, typval_T *rettv, const int flags)
} }
} else { } else {
bool error = false; bool error = false;
varnumber_T n1, n2;
float_T f1 = 0, f2 = 0;
if (rettv->v_type == VAR_FLOAT) { if (rettv->v_type == VAR_FLOAT) {
f1 = rettv->vval.v_float; f1 = rettv->vval.v_float;
@@ -2738,7 +2767,7 @@ static int eval5(char **arg, typval_T *rettv, const int flags)
/// @param[in] want_string True if "." is string_concatenation, otherwise /// @param[in] want_string True if "." is string_concatenation, otherwise
/// float /// float
/// @return OK or FAIL. /// @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 FUNC_ATTR_NO_SANITIZE_UNDEFINED
{ {
typval_T var2; typval_T var2;
@@ -2749,18 +2778,19 @@ static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string)
bool error = false; bool error = false;
// Get the first variable. // Get the first variable.
if (eval7(arg, rettv, flags, want_string) == FAIL) { if (eval7(arg, rettv, evalarg, want_string) == FAIL) {
return FAIL; return FAIL;
} }
// Repeat computing, until no '*', '/' or '%' is following. // Repeat computing, until no '*', '/' or '%' is following.
for (;;) { for (;;) {
const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
op = (uint8_t)(**arg); op = (uint8_t)(**arg);
if (op != '*' && op != '/' && op != '%') { if (op != '*' && op != '/' && op != '%') {
break; break;
} }
if (flags & EVAL_EVALUATE) { if (evaluate) {
if (rettv->v_type == VAR_FLOAT) { if (rettv->v_type == VAR_FLOAT) {
f1 = rettv->vval.v_float; f1 = rettv->vval.v_float;
use_float = true; use_float = true;
@@ -2778,11 +2808,11 @@ static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string)
// Get the second variable. // Get the second variable.
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
if (eval7(arg, &var2, flags, false) == FAIL) { if (eval7(arg, &var2, evalarg, false) == FAIL) {
return FAIL; return FAIL;
} }
if (flags & EVAL_EVALUATE) { if (evaluate) {
if (var2.v_type == VAR_FLOAT) { if (var2.v_type == VAR_FLOAT) {
if (!use_float) { if (!use_float) {
f1 = (float_T)n1; f1 = (float_T)n1;
@@ -2869,9 +2899,10 @@ static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string)
/// @param want_string after "." operator /// @param want_string after "." operator
/// ///
/// @return OK or FAIL. /// @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; int ret = OK;
static int recurse = 0; static int recurse = 0;
@@ -2979,7 +3010,7 @@ static int eval7(char **arg, typval_T *rettv, const int flags, bool want_string)
// nested expression: (expression). // nested expression: (expression).
case '(': case '(':
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
ret = eval1(arg, rettv, flags); // recursive! ret = eval1(arg, rettv, evalarg); // recursive!
if (**arg == ')') { if (**arg == ')') {
(*arg)++; (*arg)++;
} else if (ret == OK) { } else if (ret == OK) {
@@ -3319,13 +3350,15 @@ static int eval_index(char **arg, typval_T *rettv, const int flags, bool verbose
} }
*arg = skipwhite(key + len); *arg = skipwhite(key + len);
} else { } else {
evalarg_T evalarg = { .eval_flags = flags };
// something[idx] // something[idx]
// //
// Get the (first) variable from inside the []. // Get the (first) variable from inside the [].
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
if (**arg == ':') { if (**arg == ':') {
empty1 = true; empty1 = true;
} else if (eval1(arg, &var1, flags) == FAIL) { // Recursive! } else if (eval1(arg, &var1, &evalarg) == FAIL) { // Recursive!
return FAIL; return FAIL;
} else if (evaluate && !tv_check_str(&var1)) { } else if (evaluate && !tv_check_str(&var1)) {
// Not a number or string. // Not a number or string.
@@ -3339,7 +3372,7 @@ static int eval_index(char **arg, typval_T *rettv, const int flags, bool verbose
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
if (**arg == ']') { if (**arg == ']') {
empty2 = true; empty2 = true;
} else if (eval1(arg, &var2, flags) == FAIL) { // Recursive! } else if (eval1(arg, &var2, &evalarg) == FAIL) { // Recursive!
if (!empty1) { if (!empty1) {
tv_clear(&var1); tv_clear(&var1);
} }
@@ -3947,6 +3980,8 @@ static int get_list_tv(char **arg, typval_T *rettv, const int flags)
const bool evaluate = flags & EVAL_EVALUATE; const bool evaluate = flags & EVAL_EVALUATE;
list_T *l = NULL; list_T *l = NULL;
evalarg_T evalarg = { .eval_flags = flags };
if (evaluate) { if (evaluate) {
l = tv_list_alloc(kListLenShouldKnow); l = tv_list_alloc(kListLenShouldKnow);
} }
@@ -3954,7 +3989,7 @@ static int get_list_tv(char **arg, typval_T *rettv, const int flags)
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
while (**arg != ']' && **arg != NUL) { while (**arg != ']' && **arg != NUL) {
typval_T tv; typval_T tv;
if (eval1(arg, &tv, flags) == FAIL) { // Recursive! if (eval1(arg, &tv, &evalarg) == FAIL) { // Recursive!
goto failret; goto failret;
} }
if (evaluate) { if (evaluate) {
@@ -4586,7 +4621,9 @@ static int get_literal_key(char **arg, typval_T *tv)
} }
/// Allocate a variable for a Dictionary and fill it from "*arg". /// 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}. /// @return OK or FAIL. Returns NOTDONE for {expr}.
static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal) static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal)
@@ -4597,6 +4634,8 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal)
char *curly_expr = skipwhite(*arg + 1); char *curly_expr = skipwhite(*arg + 1);
char buf[NUMBUFLEN]; char buf[NUMBUFLEN];
evalarg_T evalarg = { .eval_flags = flags };
// First check if it's not a curly-braces expression: {expr}. // First check if it's not a curly-braces expression: {expr}.
// Must do this without evaluating, otherwise a function may be called // Must do this without evaluating, otherwise a function may be called
// twice. Unfortunately this means we need to call eval1() twice for the // twice. Unfortunately this means we need to call eval1() twice for the
@@ -4605,7 +4644,7 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal)
// "#{abc}" is never a curly-braces expression. // "#{abc}" is never a curly-braces expression.
if (*curly_expr != '}' if (*curly_expr != '}'
&& !literal && !literal
&& eval1(&curly_expr, &tv, 0) == OK && eval1(&curly_expr, &tv, NULL) == OK
&& *skipwhite(curly_expr) == '}') { && *skipwhite(curly_expr) == '}') {
return NOTDONE; return NOTDONE;
} }
@@ -4622,7 +4661,7 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal)
while (**arg != '}' && **arg != NUL) { while (**arg != '}' && **arg != NUL) {
if ((literal if ((literal
? get_literal_key(arg, &tvkey) ? get_literal_key(arg, &tvkey)
: eval1(arg, &tvkey, flags)) == FAIL) { // recursive! : eval1(arg, &tvkey, &evalarg)) == FAIL) { // recursive!
goto failret; goto failret;
} }
if (**arg != ':') { if (**arg != ':') {
@@ -4640,7 +4679,7 @@ static int eval_dict(char **arg, typval_T *rettv, const int flags, bool literal)
} }
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
if (eval1(arg, &tv, flags) == FAIL) { // Recursive! if (eval1(arg, &tv, &evalarg) == FAIL) { // Recursive!
if (evaluate) { if (evaluate) {
tv_clear(&tvkey); tv_clear(&tvkey);
} }
@@ -6515,15 +6554,14 @@ static char *make_expanded_name(const char *in_start, char *expr_start, char *ex
} }
char *retval = NULL; char *retval = NULL;
char *nextcmd = NULL;
*expr_start = NUL; *expr_start = NUL;
*expr_end = NUL; *expr_end = NUL;
char c1 = *in_end; char c1 = *in_end;
*in_end = NUL; *in_end = NUL;
char *temp_result = eval_to_string(expr_start + 1, &nextcmd, false); char *temp_result = eval_to_string(expr_start + 1, false);
if (temp_result != NULL && nextcmd == NULL) { if (temp_result != NULL) {
retval = xmalloc(strlen(temp_result) + (size_t)(expr_start - in_start) retval = xmalloc(strlen(temp_result) + (size_t)(expr_start - in_start)
+ (size_t)(in_end - expr_end) + 1); + (size_t)(in_end - expr_end) + 1);
STRCPY(retval, in_start); STRCPY(retval, in_start);
@@ -7389,6 +7427,8 @@ void ex_echo(exarg_T *eap)
const int did_emsg_before = did_emsg; const int did_emsg_before = did_emsg;
const int called_emsg_before = called_emsg; const int called_emsg_before = called_emsg;
evalarg_T evalarg = { .eval_flags = eap->skip ? 0 : EVAL_EVALUATE };
if (eap->skip) { if (eap->skip) {
emsg_skip++; emsg_skip++;
} }
@@ -7399,7 +7439,7 @@ void ex_echo(exarg_T *eap)
{ {
char *p = arg; 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 // Report the invalid expression unless the expression evaluation
// has been cancelled due to an aborting error, an interrupt, or an // has been cancelled due to an aborting error, an interrupt, or an
// exception. // exception.

View File

@@ -266,11 +266,26 @@ typedef int (*ex_unletlock_callback)(lval_T *, char *, exarg_T *, int);
// Used for checking if local variables or arguments used in a lambda. // Used for checking if local variables or arguments used in a lambda.
extern bool *eval_lavars_used; extern bool *eval_lavars_used;
/// Struct passed through eval() functions.
/// See EVALARG_EVALUATE for a fixed value with eval_flags set to EVAL_EVALUATE.
typedef struct {
int eval_flags; ///< EVAL_ flag values below
/// copied from exarg_T when "getline" is "getsourceline". Can be NULL.
void *eval_cookie; // argument for getline()
/// pointer to the line obtained with getsourceline()
char *eval_tofree;
} evalarg_T;
/// Flag for expression evaluation. /// Flag for expression evaluation.
enum { enum {
EVAL_EVALUATE = 1, ///< when missing don't actually evaluate EVAL_EVALUATE = 1, ///< when missing don't actually evaluate
}; };
/// Passed to an eval() function to enable evaluation.
EXTERN evalarg_T EVALARG_EVALUATE INIT(= { EVAL_EVALUATE, NULL, NULL });
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval.h.generated.h" # include "eval.h.generated.h"
#endif #endif

View File

@@ -1550,7 +1550,7 @@ static void f_eval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
} }
const char *const expr_start = s; const char *const expr_start = s;
if (s == NULL || eval1((char **)&s, rettv, EVAL_EVALUATE) == FAIL) { if (s == NULL || eval1((char **)&s, rettv, &EVALARG_EVALUATE) == FAIL) {
if (expr_start != NULL && !aborting()) { if (expr_start != NULL && !aborting()) {
semsg(_(e_invexpr2), expr_start); semsg(_(e_invexpr2), expr_start);
} }

View File

@@ -152,7 +152,7 @@ static int get_function_args(char **argp, char endchar, garray_T *newargs, int *
p = skipwhite(p) + 1; p = skipwhite(p) + 1;
p = skipwhite(p); p = skipwhite(p);
char *expr = p; char *expr = p;
if (eval1(&p, &rettv, 0) != FAIL) { if (eval1(&p, &rettv, NULL) != FAIL) {
ga_grow(default_args, 1); ga_grow(default_args, 1);
// trim trailing whitespace // trim trailing whitespace
@@ -455,6 +455,8 @@ int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, funcexe_
typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments
int argcount = 0; // number of arguments found int argcount = 0; // number of arguments found
evalarg_T evalarg = { .eval_flags = funcexe->fe_evaluate ? EVAL_EVALUATE : 0 };
// Get the arguments. // Get the arguments.
argp = *arg; argp = *arg;
while (argcount < MAX_FUNC_ARGS while (argcount < MAX_FUNC_ARGS
@@ -463,8 +465,7 @@ int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, funcexe_
if (*argp == ')' || *argp == ',' || *argp == NUL) { if (*argp == ')' || *argp == ',' || *argp == NUL) {
break; break;
} }
if (eval1(&argp, &argvars[argcount], if (eval1(&argp, &argvars[argcount], &evalarg) == FAIL) {
funcexe->fe_evaluate ? EVAL_EVALUATE : 0) == FAIL) {
ret = FAIL; ret = FAIL;
break; break;
} }
@@ -973,7 +974,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)) default_expr = ((char **)(fp->uf_def_args.ga_data))
[ai + fp->uf_def_args.ga_len]; [ai + fp->uf_def_args.ga_len];
if (eval1(&default_expr, &def_rettv, EVAL_EVALUATE) == FAIL) { if (eval1(&default_expr, &def_rettv, &EVALARG_EVALUATE) == FAIL) {
default_arg_err = true; default_arg_err = true;
break; break;
} }
@@ -1110,7 +1111,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 // A Lambda always has the command "return {expr}". It is much faster
// to evaluate {expr} directly. // to evaluate {expr} directly.
ex_nesting_level++; ex_nesting_level++;
(void)eval1(&p, rettv, EVAL_EVALUATE); (void)eval1(&p, rettv, &EVALARG_EVALUATE);
ex_nesting_level--; ex_nesting_level--;
} else { } else {
// call do_cmdline() to execute the lines // call do_cmdline() to execute the lines
@@ -2948,13 +2949,15 @@ void ex_return(exarg_T *eap)
return; return;
} }
evalarg_T evalarg = { .eval_flags = eap->skip ? 0 : EVAL_EVALUATE };
if (eap->skip) { if (eap->skip) {
emsg_skip++; emsg_skip++;
} }
eap->nextcmd = NULL; eap->nextcmd = NULL;
if ((*arg != NUL && *arg != '|' && *arg != '\n') if ((*arg != NUL && *arg != '|' && *arg != '\n')
&& eval0(arg, &rettv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) != FAIL) { && eval0(arg, &rettv, eap, &evalarg) != FAIL) {
if (!eap->skip) { if (!eap->skip) {
returning = do_return(eap, false, true, &rettv); returning = do_return(eap, false, true, &rettv);
} else { } else {
@@ -3005,7 +3008,7 @@ void ex_call(exarg_T *eap)
// instead to skip to any following command, e.g. for: // instead to skip to any following command, e.g. for:
// :if 0 | call dict.foo().bar() | endif. // :if 0 | call dict.foo().bar() | endif.
emsg_skip++; emsg_skip++;
if (eval0(eap->arg, &rettv, &eap->nextcmd, 0) != FAIL) { if (eval0(eap->arg, &rettv, eap, NULL) != FAIL) {
tv_clear(&rettv); tv_clear(&rettv);
} }
emsg_skip--; emsg_skip--;

View File

@@ -185,7 +185,6 @@ void ex_let(exarg_T *eap)
char *arg = eap->arg; char *arg = eap->arg;
char *expr = NULL; char *expr = NULL;
typval_T rettv; typval_T rettv;
int i;
int var_count = 0; int var_count = 0;
int semicolon = 0; int semicolon = 0;
char op[2]; char op[2];
@@ -221,7 +220,10 @@ void ex_let(exarg_T *eap)
list_vim_vars(&first); list_vim_vars(&first);
} }
eap->nextcmd = check_nextcmd(arg); eap->nextcmd = check_nextcmd(arg);
} else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') { return;
}
if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') {
// HERE document // HERE document
list_T *l = heredoc_get(eap, expr + 3); list_T *l = heredoc_get(eap, expr + 3);
if (l != NULL) { if (l != NULL) {
@@ -233,39 +235,44 @@ void ex_let(exarg_T *eap)
} }
tv_clear(&rettv); tv_clear(&rettv);
} }
return;
}
rettv.v_type = VAR_UNKNOWN;
op[0] = '=';
op[1] = NUL;
if (*expr != '=') {
if (vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL) {
op[0] = *expr; // +=, -=, *=, /=, %= or .=
if (expr[0] == '.' && expr[1] == '.') { // ..=
expr++;
}
}
expr += 2;
} else { } else {
rettv.v_type = VAR_UNKNOWN; expr += 1;
}
op[0] = '='; expr = skipwhite(expr);
op[1] = NUL;
if (*expr != '=') {
if (vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL) {
op[0] = *expr; // +=, -=, *=, /=, %= or .=
if (expr[0] == '.' && expr[1] == '.') { // ..=
expr++;
}
}
expr += 2;
} else {
expr += 1;
}
expr = skipwhite(expr); if (eap->skip) {
emsg_skip++;
}
evalarg_T evalarg = {
.eval_flags = eap->skip ? 0 : EVAL_EVALUATE,
.eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL,
};
int eval_res = eval0(expr, &rettv, eap, &evalarg);
if (eap->skip) {
emsg_skip--;
}
if (eap->skip) { if (!eap->skip && eval_res != FAIL) {
emsg_skip++; (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
} }
int eval_flags = eap->skip ? 0 : EVAL_EVALUATE; if (eval_res != FAIL) {
i = eval0(expr, &rettv, &eap->nextcmd, eval_flags); tv_clear(&rettv);
if (eap->skip) {
if (i != FAIL) {
tv_clear(&rettv);
}
emsg_skip--;
} else if (i != FAIL) {
(void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
tv_clear(&rettv);
}
} }
} }

View File

@@ -185,6 +185,7 @@ struct exarg {
char *nextcmd; ///< next command (NULL if none) char *nextcmd; ///< next command (NULL if none)
char *cmd; ///< the name of the command (except for :make) char *cmd; ///< the name of the command (except for :make)
char **cmdlinep; ///< pointer to pointer of allocated cmdline char **cmdlinep; ///< pointer to pointer of allocated cmdline
char *cmdline_tofree; ///< free later
cmdidx_T cmdidx; ///< the index for the command cmdidx_T cmdidx; ///< the index for the command
uint32_t argt; ///< flags for the command uint32_t argt; ///< flags for the command
int skip; ///< don't execute the command, only parse it int skip; ///< don't execute the command, only parse it

View File

@@ -2328,6 +2328,7 @@ doend:
} }
ex_nesting_level--; ex_nesting_level--;
xfree(ea.cmdline_tofree);
return ea.nextcmd; return ea.nextcmd;
} }
@@ -4432,7 +4433,7 @@ static void ex_colorscheme(exarg_T *eap)
char *expr = xstrdup("g:colors_name"); char *expr = xstrdup("g:colors_name");
emsg_off++; emsg_off++;
char *p = eval_to_string(expr, NULL, false); char *p = eval_to_string(expr, false);
emsg_off--; emsg_off--;
xfree(expr); xfree(expr);

View File

@@ -792,8 +792,11 @@ void report_discard_pending(int pending, void *value)
void ex_eval(exarg_T *eap) void ex_eval(exarg_T *eap)
{ {
typval_T tv; typval_T tv;
evalarg_T evalarg = {
if (eval0(eap->arg, &tv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) == OK) { .eval_flags = eap->skip ? 0 : EVAL_EVALUATE,
.eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL,
};
if (eval0(eap->arg, &tv, eap, &evalarg) == OK) {
tv_clear(&tv); tv_clear(&tv);
} }
} }
@@ -812,7 +815,7 @@ void ex_if(exarg_T *eap)
int skip = CHECK_SKIP; int skip = CHECK_SKIP;
bool error; bool error;
int result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); int result = eval_to_bool(eap->arg, &error, eap, skip);
if (!skip && !error) { if (!skip && !error) {
if (result) { if (result) {
@@ -907,7 +910,7 @@ void ex_else(exarg_T *eap)
if (skip && *eap->arg != '"' && ends_excmd(*eap->arg)) { if (skip && *eap->arg != '"' && ends_excmd(*eap->arg)) {
semsg(_(e_invexpr2), eap->arg); semsg(_(e_invexpr2), eap->arg);
} else { } else {
result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); result = eval_to_bool(eap->arg, &error, eap, skip);
} }
// When throwing error exceptions, we want to throw always the first // When throwing error exceptions, we want to throw always the first
@@ -954,7 +957,7 @@ void ex_while(exarg_T *eap)
int skip = CHECK_SKIP; int skip = CHECK_SKIP;
if (eap->cmdidx == CMD_while) { if (eap->cmdidx == CMD_while) {
// ":while bool-expr" // ":while bool-expr"
result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); result = eval_to_bool(eap->arg, &error, eap, skip);
} else { } else {
void *fi; void *fi;
@@ -966,7 +969,7 @@ void ex_while(exarg_T *eap)
error = false; error = false;
} else { } else {
// Evaluate the argument and get the info in a structure. // Evaluate the argument and get the info in a structure.
fi = eval_for_line(eap->arg, &error, &eap->nextcmd, skip); fi = eval_for_line(eap->arg, &error, eap, skip);
cstack->cs_forinfo[cstack->cs_idx] = fi; cstack->cs_forinfo[cstack->cs_idx] = fi;
} }
@@ -1125,12 +1128,11 @@ void ex_endwhile(exarg_T *eap)
/// Handle ":throw expr" /// Handle ":throw expr"
void ex_throw(exarg_T *eap) void ex_throw(exarg_T *eap)
{ {
const char *arg = eap->arg; char *arg = eap->arg;
char *value; char *value;
if (*arg != NUL && *arg != '|' && *arg != '\n') { if (*arg != NUL && *arg != '|' && *arg != '\n') {
value = eval_to_string_skip(arg, (const char **)&eap->nextcmd, value = eval_to_string_skip(arg, eap, eap->skip);
(bool)eap->skip);
} else { } else {
emsg(_(e_argreq)); emsg(_(e_argreq));
value = NULL; value = NULL;

View File

@@ -1749,7 +1749,8 @@ char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo
curbuf = wp->w_buffer; curbuf = wp->w_buffer;
emsg_silent++; // handle exceptions, but don't display errors emsg_silent++; // handle exceptions, but don't display errors
text = eval_to_string_safe(wp->w_p_fdt, NULL, was_set_insecurely(wp, "foldtext", OPT_LOCAL)); text = eval_to_string_safe(wp->w_p_fdt,
was_set_insecurely(wp, "foldtext", OPT_LOCAL));
emsg_silent--; emsg_silent--;
if (text == NULL || did_emsg) { if (text == NULL || did_emsg) {

View File

@@ -1632,7 +1632,7 @@ char *eval_map_expr(mapblock_T *mp, int c)
api_clear_error(&err); api_clear_error(&err);
} }
} else { } else {
p = eval_to_string(expr, NULL, false); p = eval_to_string(expr, false);
xfree(expr); xfree(expr);
} }
expr_map_lock--; expr_map_lock--;

View File

@@ -763,7 +763,7 @@ char *get_expr_line(void)
} }
nested++; nested++;
rv = eval_to_string(expr_copy, NULL, true); rv = eval_to_string(expr_copy, true);
nested--; nested--;
xfree(expr_copy); xfree(expr_copy);
return rv; return rv;

View File

@@ -1371,7 +1371,7 @@ static int expand_backtick(garray_T *gap, char *pat, int flags)
char *cmd = xstrnsave(pat + 1, strlen(pat) - 2); char *cmd = xstrnsave(pat + 1, strlen(pat) - 2);
if (*cmd == '=') { // `={expr}`: Expand expression if (*cmd == '=') { // `={expr}`: Expand expression
buffer = eval_to_string(cmd + 1, &p, true); buffer = eval_to_string(cmd + 1, true);
} else { } else {
buffer = get_cmd_output(cmd, NULL, (flags & EW_SILENT) ? kShellOptSilent : 0, NULL); buffer = get_cmd_output(cmd, NULL, (flags & EW_SILENT) ? kShellOptSilent : 0, NULL);
} }
@@ -1662,7 +1662,7 @@ void simplify_filename(char *filename)
static char *eval_includeexpr(const char *const ptr, const size_t len) static char *eval_includeexpr(const char *const ptr, const size_t len)
{ {
set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len); set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len);
char *res = eval_to_string_safe(curbuf->b_p_inex, NULL, char *res = eval_to_string_safe(curbuf->b_p_inex,
was_set_insecurely(curwin, "includeexpr", OPT_LOCAL)); was_set_insecurely(curwin, "includeexpr", OPT_LOCAL));
set_vim_var_string(VV_FNAME, NULL, 0); set_vim_var_string(VV_FNAME, NULL, 0);
return res; return res;

View File

@@ -6958,7 +6958,7 @@ void ex_cexpr(exarg_T *eap)
// Evaluate the expression. When the result is a string or a list we can // Evaluate the expression. When the result is a string or a list we can
// use it to fill the errorlist. // use it to fill the errorlist.
typval_T tv; typval_T tv;
if (eval0(eap->arg, &tv, &eap->nextcmd, EVAL_EVALUATE) == FAIL) { if (eval0(eap->arg, &tv, eap, &EVALARG_EVALUATE) == FAIL) {
return; return;
} }

View File

@@ -1812,7 +1812,7 @@ static int vim_regsub_both(char *source, typval_T *expr, char *dest, int destlen
} }
tv_clear(&rettv); tv_clear(&rettv);
} else { } else {
eval_result[nested] = eval_to_string(source + 2, NULL, true); eval_result[nested] = eval_to_string(source + 2, true);
} }
nesting--; nesting--;

View File

@@ -985,7 +985,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n
}; };
set_var(S_LEN("g:statusline_winid"), &tv, false); set_var(S_LEN("g:statusline_winid"), &tv, false);
usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox); usefmt = eval_to_string_safe(fmt + 2, use_sandbox);
if (usefmt == NULL) { if (usefmt == NULL) {
usefmt = fmt; usefmt = fmt;
} }
@@ -1457,7 +1457,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n
} }
// Note: The result stored in `t` is unused. // Note: The result stored in `t` is unused.
str = eval_to_string_safe(out_p, &t, use_sandbox); str = eval_to_string_safe(out_p, use_sandbox);
curwin = save_curwin; curwin = save_curwin;
curbuf = save_curbuf; curbuf = save_curbuf;

View File

@@ -512,7 +512,8 @@ end
local function eval0(expr) local function eval0(expr)
local tv = ffi.gc(ffi.new('typval_T', {v_type=eval.VAR_UNKNOWN}), local tv = ffi.gc(ffi.new('typval_T', {v_type=eval.VAR_UNKNOWN}),
eval.tv_clear) eval.tv_clear)
if eval.eval0(to_cstr(expr), tv, nil, eval.EVAL_EVALUATE) == 0 then local evalarg = ffi.new('evalarg_T', {eval_flags = eval.EVAL_EVALUATE})
if eval.eval0(to_cstr(expr), tv, nil, evalarg) == 0 then
return nil return nil
else else
return tv return tv