vim-patch:8.2.{0695,0725,0734,0753,0818,0819,0822} (#23075)

vim-patch:8.2.0695: Vim9: cannot define a function inside a function

Problem:    Vim9: cannot define a function inside a function.
Solution:   Initial support for :def inside :def.

04b1269783

vim-patch:8.2.0725: Vim9: cannot call a function declared later in Vim9 script

Problem:    Vim9: cannot call a function declared later in Vim9 script.
Solution:   Make two passes through the script file.

09689a0284

vim-patch:8.2.0734: Vim9: leaking memory when using :finish

Problem:    Vim9: leaking memory when using :finish.
Solution:   Do not check for next line in third pass.

04816717df

vim-patch:8.2.0753: Vim9: expressions are evaluated in the discovery phase

Problem:    Vim9: expressions are evaluated in the discovery phase.
Solution:   Bail out if an expression is not a constant.  Require a type for
            declared constants.

32e351179e

vim-patch:8.2.0818: Vim9: using a discovery phase doesn't work well

Problem:    Vim9: using a discovery phase doesn't work well.
Solution:   Remove the discovery phase, instead compile a function only when
            it is used.  Add :defcompile to compile def functions earlier.

822ba24743

vim-patch:8.2.0819: compiler warning for unused variable

Problem:    Compiler warning for unused variable.
Solution:   Remove the variable.

f40e51a880

vim-patch:8.2.0822: Vim9: code left over from discovery phase

Problem:    Vim9: code left over from discovery phase.
Solution:   Remove the dead code.

2eec37926d

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
zeertzjq
2023-04-14 07:11:59 +08:00
committed by GitHub
parent 0adb9f75c5
commit 8f69c5ed45
10 changed files with 112 additions and 95 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, true); ok = eval0(expr.data, &rettv, NULL, EVAL_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, true) == FAIL) { if (eval0(dict.data.string.data, &rettv, NULL, EVAL_EVALUATE) == FAIL) {
api_set_error(err, kErrorTypeException, api_set_error(err, kErrorTypeException,
"Failed to evaluate dict expression"); "Failed to evaluate dict expression");
} }

View File

@@ -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) == FAIL) { if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_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); const int ret = eval1(arg, rettv, evaluate ? EVAL_EVALUATE : 0);
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
@@ -832,7 +832,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) == FAIL || skip) { if (eval0((char *)arg, &tv, (char **)nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL || skip) {
retval = NULL; retval = NULL;
} else { } else {
retval = xstrdup(tv_get_string(&tv)); retval = xstrdup(tv_get_string(&tv));
@@ -853,7 +853,7 @@ int skip_expr(char **pp)
typval_T rettv; typval_T rettv;
*pp = skipwhite(*pp); *pp = skipwhite(*pp);
return eval1(pp, &rettv, false); return eval1(pp, &rettv, 0);
} }
/// Top level evaluation function, returning a string. /// Top level evaluation function, returning a string.
@@ -868,7 +868,7 @@ char *eval_to_string(char *arg, char **nextcmd, bool convert)
char *retval; char *retval;
garray_T ga; garray_T ga;
if (eval0(arg, &tv, nextcmd, true) == FAIL) { if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL) {
retval = NULL; retval = NULL;
} else { } else {
if (convert && tv.v_type == VAR_LIST) { if (convert && tv.v_type == VAR_LIST) {
@@ -929,7 +929,7 @@ varnumber_T eval_to_number(char *expr)
emsg_off++; emsg_off++;
if (eval1(&p, &rettv, true) == FAIL) { if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL) {
retval = -1; retval = -1;
} else { } else {
retval = tv_get_number_chk(&rettv, NULL); 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 *eval_expr(char *arg)
{ {
typval_T *tv = xmalloc(sizeof(*tv)); typval_T *tv = xmalloc(sizeof(*tv));
if (eval0(arg, tv, NULL, true) == FAIL) { if (eval0(arg, tv, NULL, EVAL_EVALUATE) == FAIL) {
XFREE_CLEAR(tv); XFREE_CLEAR(tv);
} }
return tv; return tv;
@@ -1024,7 +1024,7 @@ list_T *eval_spell_expr(char *badword, char *expr)
emsg_off++; emsg_off++;
} }
if (eval1(&p, &rettv, true) == OK) { if (eval1(&p, &rettv, EVAL_EVALUATE) == OK) {
if (rettv.v_type != VAR_LIST) { if (rettv.v_type != VAR_LIST) {
tv_clear(&rettv); tv_clear(&rettv);
} else { } else {
@@ -1171,7 +1171,7 @@ int eval_foldexpr(char *arg, int *cp)
} }
textlock++; textlock++;
*cp = NUL; *cp = NUL;
if (eval0(arg, &tv, NULL, true) == FAIL) { if (eval0(arg, &tv, NULL, EVAL_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 +1346,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, true) == FAIL) { // Recursive! if (eval1(&p, &var1, EVAL_EVALUATE) == FAIL) { // Recursive!
return NULL; return NULL;
} }
if (!tv_check_str(&var1)) { 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; lp->ll_empty2 = true;
} else { } else {
lp->ll_empty2 = false; lp->ll_empty2 = false;
if (eval1(&p, &var2, true) == FAIL) { // Recursive! // Recursive!
if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL) {
tv_clear(&var1); tv_clear(&var1);
return NULL; return NULL;
} }
@@ -1799,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) == OK) { if (eval0(skipwhite(expr + 2), &tv, nextcmdp, skip ? 0 : EVAL_EVALUATE) == OK) {
*errp = false; *errp = false;
if (!skip) { if (!skip) {
if (tv.v_type == VAR_LIST) { 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. /// @return OK or FAIL.
static int eval_func(char **const arg, char *const name, const int name_len, typval_T *const rettv, 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) FUNC_ATTR_NONNULL_ARG(1, 2, 4)
{ {
const bool evaluate = flags & EVAL_EVALUATE;
char *s = name; char *s = name;
int len = name_len; 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. /// 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.
///
/// @return OK or FAIL. /// @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; int ret;
char *p; char *p;
@@ -2233,7 +2237,7 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, int evaluate)
bool end_error = false; bool end_error = false;
p = skipwhite(arg); p = skipwhite(arg);
ret = eval1(&p, rettv, evaluate); ret = eval1(&p, rettv, flags);
if (ret != FAIL) { if (ret != FAIL) {
end_error = !ends_excmd(*p); 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 // been cancelled due to an aborting error, an interrupt, or an
// exception, or we already gave a more specific error. // exception, or we already gave a more specific error.
// Also check called_emsg for when using assert_fails(). // 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) { && called_emsg == called_emsg_before) {
if (end_error) { if (end_error) {
semsg(_(e_trailing_arg), p); 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. /// Note: "rettv.v_lock" is not set.
/// ///
/// @return OK or FAIL. /// @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; typval_T var2;
// Get the first variable. // Get the first variable.
if (eval2(arg, rettv, evaluate) == FAIL) { if (eval2(arg, rettv, flags) == FAIL) {
return FAIL; return FAIL;
} }
if ((*arg)[0] == '?') { if ((*arg)[0] == '?') {
const bool evaluate = flags & EVAL_EVALUATE;
bool result = false; bool result = false;
if (evaluate) { if (flags & EVAL_EVALUATE) {
bool error = false; bool error = false;
if (tv_get_number_chk(rettv, &error) != 0) { 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); *arg = skipwhite(*arg + 1);
if (eval1(arg, rettv, evaluate && result) == FAIL) { // recursive! if (eval1(arg, rettv, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) {
return FAIL; return FAIL;
} }
@@ -2310,9 +2317,9 @@ int eval1(char **arg, typval_T *rettv, int evaluate)
return FAIL; return FAIL;
} }
// Get the third variable. // Get the third variable. Recursive!
*arg = skipwhite(*arg + 1); *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) { if (evaluate && result) {
tv_clear(rettv); 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. /// "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, int evaluate) static int eval2(char **arg, typval_T *rettv, const int flags)
{ {
typval_T var2; typval_T var2;
bool error = false; bool error = false;
// Get the first variable. // Get the first variable.
if (eval3(arg, rettv, evaluate) == FAIL) { if (eval3(arg, rettv, flags) == FAIL) {
return FAIL; return FAIL;
} }
@@ -2347,6 +2354,8 @@ static int eval2(char **arg, typval_T *rettv, int evaluate)
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;
if (evaluate && first) { if (evaluate && first) {
if (tv_get_number_chk(rettv, &error) != 0) { if (tv_get_number_chk(rettv, &error) != 0) {
result = true; result = true;
@@ -2360,7 +2369,7 @@ static int eval2(char **arg, typval_T *rettv, int evaluate)
// Get the second variable. // Get the second variable.
*arg = skipwhite(*arg + 2); *arg = skipwhite(*arg + 2);
if (eval3(arg, &var2, evaluate && !result) == FAIL) { if (eval3(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) {
return 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. /// `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, int evaluate) static int eval3(char **arg, typval_T *rettv, const int flags)
{ {
typval_T var2; typval_T var2;
bool error = false; bool error = false;
// Get the first variable. // Get the first variable.
if (eval4(arg, rettv, evaluate) == FAIL) { if (eval4(arg, rettv, flags) == FAIL) {
return FAIL; return FAIL;
} }
@@ -2404,6 +2413,8 @@ static int eval3(char **arg, typval_T *rettv, int evaluate)
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;
if (evaluate && first) { if (evaluate && first) {
if (tv_get_number_chk(rettv, &error) == 0) { if (tv_get_number_chk(rettv, &error) == 0) {
result = false; result = false;
@@ -2417,7 +2428,7 @@ static int eval3(char **arg, typval_T *rettv, int evaluate)
// Get the second variable. // Get the second variable.
*arg = skipwhite(*arg + 2); *arg = skipwhite(*arg + 2);
if (eval4(arg, &var2, evaluate && result) == FAIL) { if (eval4(arg, &var2, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) {
return 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. /// "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, int evaluate) static int eval4(char **arg, typval_T *rettv, const int flags)
{ {
typval_T var2; typval_T var2;
char *p; char *p;
@@ -2464,7 +2475,7 @@ static int eval4(char **arg, typval_T *rettv, int evaluate)
int len = 2; int len = 2;
// Get the first variable. // Get the first variable.
if (eval5(arg, rettv, evaluate) == FAIL) { if (eval5(arg, rettv, flags) == FAIL) {
return FAIL; return FAIL;
} }
@@ -2528,11 +2539,11 @@ static int eval4(char **arg, typval_T *rettv, int evaluate)
// Get the second variable. // Get the second variable.
*arg = skipwhite(p + len); *arg = skipwhite(p + len);
if (eval5(arg, &var2, evaluate) == FAIL) { if (eval5(arg, &var2, flags) == FAIL) {
tv_clear(rettv); tv_clear(rettv);
return FAIL; return FAIL;
} }
if (evaluate) { if (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);
@@ -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. /// `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, int evaluate) static int eval5(char **arg, typval_T *rettv, const int flags)
{ {
typval_T var2; typval_T var2;
varnumber_T n1, n2; varnumber_T n1, n2;
@@ -2594,7 +2605,7 @@ static int eval5(char **arg, typval_T *rettv, int evaluate)
char *p; char *p;
// Get the first variable. // Get the first variable.
if (eval6(arg, rettv, evaluate, false) == FAIL) { if (eval6(arg, rettv, flags, false) == FAIL) {
return 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)) 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 // 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.
@@ -2625,12 +2636,12 @@ static int eval5(char **arg, typval_T *rettv, int evaluate)
(*arg)++; (*arg)++;
} }
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
if (eval6(arg, &var2, evaluate, op == '.') == FAIL) { if (eval6(arg, &var2, flags, op == '.') == FAIL) {
tv_clear(rettv); tv_clear(rettv);
return FAIL; return FAIL;
} }
if (evaluate) { if (flags & EVAL_EVALUATE) {
// Compute the result. // Compute the result.
if (op == '.') { if (op == '.') {
char buf1[NUMBUFLEN]; 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 /// expression. Is advanced to the next non-whitespace
/// character after the recognized expression. /// character after the recognized expression.
/// @param[out] rettv Location where result is saved. /// @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 /// @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, int evaluate, int want_string) static int eval6(char **arg, typval_T *rettv, const int flags, bool want_string)
FUNC_ATTR_NO_SANITIZE_UNDEFINED FUNC_ATTR_NO_SANITIZE_UNDEFINED
{ {
typval_T var2; typval_T var2;
@@ -2739,7 +2749,7 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string)
bool error = false; bool error = false;
// Get the first variable. // Get the first variable.
if (eval7(arg, rettv, evaluate, want_string) == FAIL) { if (eval7(arg, rettv, flags, want_string) == FAIL) {
return FAIL; return FAIL;
} }
@@ -2750,7 +2760,7 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string)
break; break;
} }
if (evaluate) { if (flags & EVAL_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;
@@ -2768,11 +2778,11 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string)
// Get the second variable. // Get the second variable.
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
if (eval7(arg, &var2, evaluate, false) == FAIL) { if (eval7(arg, &var2, flags, false) == FAIL) {
return FAIL; return FAIL;
} }
if (evaluate) { if (flags & EVAL_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;
@@ -2859,8 +2869,9 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int 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, 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; int ret = OK;
static int recurse = 0; static int recurse = 0;
@@ -2922,14 +2933,14 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
// List: [expr, expr] // List: [expr, expr]
case '[': case '[':
ret = get_list_tv(arg, rettv, evaluate); ret = get_list_tv(arg, rettv, flags);
break; break;
// Dictionary: #{key: val, key: val} // Dictionary: #{key: val, key: val}
case '#': case '#':
if ((*arg)[1] == '{') { if ((*arg)[1] == '{') {
(*arg)++; (*arg)++;
ret = eval_dict(arg, rettv, evaluate, true); ret = eval_dict(arg, rettv, flags, true);
} else { } else {
ret = NOTDONE; ret = NOTDONE;
} }
@@ -2940,7 +2951,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
case '{': case '{':
ret = get_lambda_tv(arg, rettv, evaluate); ret = get_lambda_tv(arg, rettv, evaluate);
if (ret == NOTDONE) { if (ret == NOTDONE) {
ret = eval_dict(arg, rettv, evaluate, false); ret = eval_dict(arg, rettv, flags, false);
} }
break; break;
@@ -2968,7 +2979,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
// nested expression: (expression). // nested expression: (expression).
case '(': case '(':
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
ret = eval1(arg, rettv, evaluate); // recursive! ret = eval1(arg, rettv, flags); // recursive!
if (**arg == ')') { if (**arg == ')') {
(*arg)++; (*arg)++;
} else if (ret == OK) { } else if (ret == OK) {
@@ -2997,7 +3008,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
ret = FAIL; ret = FAIL;
} else { } else {
if (**arg == '(') { // recursive! if (**arg == '(') { // recursive!
ret = eval_func(arg, s, len, rettv, evaluate, NULL); ret = eval_func(arg, s, len, rettv, flags, NULL);
} else if (evaluate) { } else if (evaluate) {
ret = get_var_tv(s, len, rettv, NULL, true, false); ret = get_var_tv(s, len, rettv, NULL, true, false);
} else { } 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, // Handle following '[', '(' and '.' for expr[expr], expr.name,
// expr(expr), expr->name(expr) // expr(expr), expr->name(expr)
if (ret == OK) { 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 '+'. // 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); ret = call_func_rettv(arg, rettv, evaluate, NULL, &base, lua_funcname);
} else { } 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 /// @param verbose give error messages
/// ///
/// @returns FAIL or OK. "*arg" is advanced to after the ']'. /// @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 empty1 = false;
bool empty2 = false; bool empty2 = false;
ptrdiff_t len = -1; 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); *arg = skipwhite(*arg + 1);
if (**arg == ':') { if (**arg == ':') {
empty1 = true; empty1 = true;
} else if (eval1(arg, &var1, evaluate) == FAIL) { // Recursive! } else if (eval1(arg, &var1, flags) == 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.
@@ -3327,7 +3339,7 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose)
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
if (**arg == ']') { if (**arg == ']') {
empty2 = true; empty2 = true;
} else if (eval1(arg, &var2, evaluate) == FAIL) { // Recursive! } else if (eval1(arg, &var2, flags) == FAIL) { // Recursive!
if (!empty1) { if (!empty1) {
tv_clear(&var1); tv_clear(&var1);
} }
@@ -3930,8 +3942,9 @@ void partial_unref(partial_T *pt)
/// Allocate a variable for a List and fill it from "*arg". /// Allocate a variable for a List and fill it from "*arg".
/// ///
/// @return OK or FAIL. /// @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; list_T *l = NULL;
if (evaluate) { if (evaluate) {
@@ -3941,7 +3954,7 @@ static int get_list_tv(char **arg, typval_T *rettv, int evaluate)
*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, evaluate) == FAIL) { // Recursive! if (eval1(arg, &tv, flags) == FAIL) { // Recursive!
goto failret; goto failret;
} }
if (evaluate) { if (evaluate) {
@@ -4576,8 +4589,9 @@ static int get_literal_key(char **arg, typval_T *tv)
/// "literal" is true for #{key: val} /// "literal" is true for #{key: val}
/// ///
/// @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, 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; typval_T tv;
char *key = NULL; char *key = NULL;
char *curly_expr = skipwhite(*arg + 1); 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. // "#{abc}" is never a curly-braces expression.
if (*curly_expr != '}' if (*curly_expr != '}'
&& !literal && !literal
&& eval1(&curly_expr, &tv, false) == OK && eval1(&curly_expr, &tv, 0) == OK
&& *skipwhite(curly_expr) == '}') { && *skipwhite(curly_expr) == '}') {
return NOTDONE; return NOTDONE;
} }
@@ -4608,7 +4622,7 @@ static int eval_dict(char **arg, typval_T *rettv, int evaluate, 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, evaluate)) == FAIL) { // recursive! : eval1(arg, &tvkey, flags)) == FAIL) { // recursive!
goto failret; goto failret;
} }
if (**arg != ':') { if (**arg != ':') {
@@ -4626,7 +4640,7 @@ static int eval_dict(char **arg, typval_T *rettv, int evaluate, bool literal)
} }
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
if (eval1(arg, &tv, evaluate) == FAIL) { // Recursive! if (eval1(arg, &tv, flags) == FAIL) { // Recursive!
if (evaluate) { if (evaluate) {
tv_clear(&tvkey); 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() /// 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 verbose give error messages
/// @param start_leader start of '!' and '-' prefixes /// @param start_leader start of '!' and '-' prefixes
/// @param end_leaderp end 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; int ret = OK;
dict_T *selfdict = NULL; dict_T *selfdict = NULL;
const char *lua_funcname = NULL; const char *lua_funcname = NULL;
@@ -7002,7 +7016,7 @@ int handle_subscript(const char **const arg, typval_T *rettv, int evaluate, int
} else { } else {
selfdict = NULL; selfdict = NULL;
} }
if (eval_index((char **)arg, rettv, evaluate, verbose) == FAIL) { if (eval_index((char **)arg, rettv, flags, verbose) == FAIL) {
tv_clear(rettv); tv_clear(rettv);
ret = FAIL; ret = FAIL;
} }
@@ -7385,7 +7399,7 @@ void ex_echo(exarg_T *eap)
{ {
char *p = arg; 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 // 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,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. // Used for checking if local variables or arguments used in a lambda.
extern bool *eval_lavars_used; extern bool *eval_lavars_used;
/// Flag for expression evaluation.
enum {
EVAL_EVALUATE = 1, ///< when missing don't actually evaluate
};
#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, true) == FAIL) { if (s == NULL || eval1((char **)&s, rettv, EVAL_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, false) != FAIL) { if (eval1(&p, &rettv, 0) != FAIL) {
ga_grow(default_args, 1); ga_grow(default_args, 1);
// trim trailing whitespace // 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) { if (*argp == ')' || *argp == ',' || *argp == NUL) {
break; break;
} }
if (eval1(&argp, &argvars[argcount], funcexe->fe_evaluate) == FAIL) { if (eval1(&argp, &argvars[argcount],
funcexe->fe_evaluate ? EVAL_EVALUATE : 0) == FAIL) {
ret = FAIL; ret = FAIL;
break; 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)) 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, true) == FAIL) { if (eval1(&default_expr, &def_rettv, EVAL_EVALUATE) == FAIL) {
default_arg_err = true; default_arg_err = true;
break; 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 // 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, true); (void)eval1(&p, rettv, EVAL_EVALUATE);
ex_nesting_level--; ex_nesting_level--;
} else { } else {
// call do_cmdline() to execute the lines // call do_cmdline() to execute the lines
@@ -2953,7 +2954,7 @@ void ex_return(exarg_T *eap)
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) != FAIL) { && eval0(arg, &rettv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) != FAIL) {
if (!eap->skip) { if (!eap->skip) {
returning = do_return(eap, false, true, &rettv); returning = do_return(eap, false, true, &rettv);
} else { } else {
@@ -3004,7 +3005,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, false) != FAIL) { if (eval0(eap->arg, &rettv, &eap->nextcmd, 0) != FAIL) {
tv_clear(&rettv); tv_clear(&rettv);
} }
emsg_skip--; emsg_skip--;
@@ -3071,7 +3072,7 @@ void ex_call(exarg_T *eap)
} }
// Handle a function returning a Funcref, Dictionary or List. // 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) { == FAIL) {
failed = true; failed = true;
break; break;

View File

@@ -175,21 +175,13 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
/// ":let var ..= expr" assignment command. /// ":let var ..= expr" assignment command.
/// ":let [var1, var2] = expr" unpack list. /// ":let [var1, var2] = expr" unpack list.
/// ":let [name, ..., ; lastname] = 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] var = expr1" define constant
/// ":cons[t] [name1, name2, ...] = expr1" define constants unpacking list /// ":cons[t] [name1, name2, ...] = expr1" define constants unpacking list
/// ":cons[t] [name, ..., ; lastname] = expr" define constants unpacking list /// ":cons[t] [name, ..., ; lastname] = expr" define constants unpacking list
void ex_const(exarg_T *eap) void ex_let(exarg_T *eap)
{
ex_let_const(eap, true);
}
static void ex_let_const(exarg_T *eap, const bool is_const)
{ {
const bool is_const = eap->cmdidx == CMD_const;
char *arg = eap->arg; char *arg = eap->arg;
char *expr = NULL; char *expr = NULL;
typval_T rettv; typval_T rettv;
@@ -208,8 +200,10 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
argend--; argend--;
} }
expr = skipwhite(argend); expr = skipwhite(argend);
if (*expr != '=' && !((vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL bool concat = strncmp(expr, "..=", 3) == 0;
&& expr[1] == '=') || strncmp(expr, "..=", 3) == 0)) { bool has_assign = *expr == '=' || (vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL
&& expr[1] == '=');
if (!has_assign && !concat) {
// ":let" without "=": list variables // ":let" without "=": list variables
if (*arg == '[') { if (*arg == '[') {
emsg(_(e_invarg)); emsg(_(e_invarg));
@@ -240,6 +234,8 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
tv_clear(&rettv); tv_clear(&rettv);
} }
} else { } else {
rettv.v_type = VAR_UNKNOWN;
op[0] = '='; op[0] = '=';
op[1] = NUL; op[1] = NUL;
if (*expr != '=') { if (*expr != '=') {
@@ -259,7 +255,8 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
if (eap->skip) { if (eap->skip) {
emsg_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 (eap->skip) {
if (i != FAIL) { if (i != FAIL) {
tv_clear(&rettv); tv_clear(&rettv);
@@ -506,7 +503,7 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
} else { } else {
// handle d.key, l[idx], f(expr) // handle d.key, l[idx], f(expr)
const char *const arg_subsc = arg; 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; error = true;
} else { } else {
if (arg == arg_subsc && len == 2 && name[1] == ':') { 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; n = get_var_tv(name, len, &tv, NULL, false, true) == OK;
if (n) { if (n) {
// Handle d.key, l[idx], f(expr). // 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) { if (n) {
tv_clear(&tv); tv_clear(&tv);
} }

View File

@@ -634,7 +634,7 @@ module.cmds = {
command='const', command='const',
flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN, LOCK_OK), flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN, LOCK_OK),
addr_type='ADDR_NONE', addr_type='ADDR_NONE',
func='ex_const', func='ex_let',
}, },
{ {
command='copen', command='copen',

View File

@@ -793,7 +793,7 @@ void ex_eval(exarg_T *eap)
{ {
typval_T tv; 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); tv_clear(&tv);
} }
} }

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, true) == FAIL) { if (eval0(eap->arg, &tv, &eap->nextcmd, EVAL_EVALUATE) == FAIL) {
return; return;
} }

View File

@@ -512,7 +512,7 @@ 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, true) == 0 then if eval.eval0(to_cstr(expr), tv, nil, eval.EVAL_EVALUATE) == 0 then
return nil return nil
else else
return tv return tv