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