Mercurial > vim
diff src/eval.c @ 20397:c225be44692a v8.2.0753
patch 8.2.0753: Vim9: expressions are evaluated in the discovery phase
Commit: https://github.com/vim/vim/commit/32e351179eacfc84f64cd5029e221582d400bb38
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu May 14 22:41:15 2020 +0200
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.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 14 May 2020 22:45:04 +0200 |
parents | 4c317d8c1051 |
children | 918b9a05cf35 |
line wrap: on
line diff
--- a/src/eval.c +++ b/src/eval.c @@ -48,12 +48,12 @@ typedef struct } forinfo_T; static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op); -static int eval2(char_u **arg, typval_T *rettv, int evaluate); -static int eval3(char_u **arg, typval_T *rettv, int evaluate); -static int eval4(char_u **arg, typval_T *rettv, int evaluate); -static int eval5(char_u **arg, typval_T *rettv, int evaluate); -static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string); -static int eval7(char_u **arg, typval_T *rettv, int evaluate, int want_string); +static int eval2(char_u **arg, typval_T *rettv, int flags); +static int eval3(char_u **arg, typval_T *rettv, int flags); +static int eval4(char_u **arg, typval_T *rettv, int flags); +static int eval5(char_u **arg, typval_T *rettv, int flags); +static int eval6(char_u **arg, typval_T *rettv, int flags, int want_string); +static int eval7(char_u **arg, typval_T *rettv, int flags, int want_string); static int eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp); static int free_unref_items(int copyID); @@ -173,7 +173,7 @@ eval_to_bool( if (skip) ++emsg_skip; - if (eval0(arg, &tv, nextcmd, !skip) == FAIL) + if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL) *error = TRUE; else { @@ -201,7 +201,7 @@ eval1_emsg(char_u **arg, typval_T *rettv int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; - ret = eval1(arg, rettv, evaluate); + ret = eval1(arg, rettv, evaluate ? EVAL_EVALUATE : 0); if (ret == FAIL) { // Report the invalid expression unless the expression evaluation has @@ -315,7 +315,7 @@ eval_to_string_skip( if (skip) ++emsg_skip; - if (eval0(arg, &tv, nextcmd, !skip) == FAIL || skip) + if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL || skip) retval = NULL; else { @@ -338,7 +338,7 @@ skip_expr(char_u **pp) typval_T rettv; *pp = skipwhite(*pp); - return eval1(pp, &rettv, FALSE); + return eval1(pp, &rettv, 0); } /* @@ -360,7 +360,7 @@ eval_to_string( char_u numbuf[NUMBUFLEN]; #endif - if (eval0(arg, &tv, nextcmd, TRUE) == FAIL) + if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL) retval = NULL; else { @@ -430,7 +430,7 @@ eval_to_number(char_u *expr) ++emsg_off; - if (eval1(&p, &rettv, TRUE) == FAIL) + if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL) retval = -1; else { @@ -453,7 +453,7 @@ eval_expr(char_u *arg, char_u **nextcmd) typval_T *tv; tv = ALLOC_ONE(typval_T); - if (tv != NULL && eval0(arg, tv, nextcmd, TRUE) == FAIL) + if (tv != NULL && eval0(arg, tv, nextcmd, EVAL_EVALUATE) == FAIL) VIM_CLEAR(tv); return tv; @@ -578,7 +578,7 @@ eval_foldexpr(char_u *arg, int *cp) ++sandbox; ++textwinlock; *cp = NUL; - if (eval0(arg, &tv, NULL, TRUE) == FAIL) + if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL) retval = 0; else { @@ -766,7 +766,7 @@ get_lval( else { empty1 = FALSE; - if (eval1(&p, &var1, TRUE) == FAIL) // recursive! + if (eval1(&p, &var1, EVAL_EVALUATE) == FAIL) // recursive! return NULL; if (tv_get_string_chk(&var1) == NULL) { @@ -803,7 +803,8 @@ get_lval( else { lp->ll_empty2 = FALSE; - if (eval1(&p, &var2, TRUE) == FAIL) // recursive! + // recursive! + if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL) { clear_tv(&var1); return NULL; @@ -1433,7 +1434,8 @@ eval_for_line( 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) @@ -1694,9 +1696,10 @@ eval_func( char_u *name, int name_len, typval_T *rettv, - int evaluate, + int flags, typval_T *basetv) // "expr" for "expr->name(arg)" { + int evaluate = flags & EVAL_EVALUATE; char_u *s = name; int len = name_len; partial_T *partial; @@ -1712,7 +1715,7 @@ eval_func( // Need to make a copy, in case evaluating the arguments makes // the name invalid. s = vim_strsave(s); - if (s == NULL) + if (s == NULL || (flags & EVAL_CONSTANT)) ret = FAIL; else { @@ -1761,6 +1764,7 @@ eval_func( * This calls eval1() and handles error message and nextcmd. * Put the result in "rettv" when returning OK and "evaluate" is TRUE. * Note: "rettv.v_lock" is not set. + * "flags" has EVAL_EVALUATE and similar flags. * Return OK or FAIL. */ int @@ -1768,7 +1772,7 @@ eval0( char_u *arg, typval_T *rettv, char_u **nextcmd, - int evaluate) + int flags) { int ret; char_u *p; @@ -1776,7 +1780,7 @@ eval0( int called_emsg_before = called_emsg; p = skipwhite(arg); - ret = eval1(&p, rettv, evaluate); + ret = eval1(&p, rettv, flags); if (ret == FAIL || !ends_excmd2(arg, p)) { if (ret != FAIL) @@ -1787,8 +1791,10 @@ eval0( * 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 - && called_emsg == called_emsg_before) + if (!aborting() + && did_emsg == did_emsg_before + && called_emsg == called_emsg_before + && (flags & EVAL_CONSTANT) == 0) semsg(_(e_invexpr2), arg); ret = FAIL; } @@ -1810,7 +1816,7 @@ eval0( * Return OK or FAIL. */ int -eval1(char_u **arg, typval_T *rettv, int evaluate) +eval1(char_u **arg, typval_T *rettv, int flags) { int result; typval_T var2; @@ -1818,13 +1824,15 @@ eval1(char_u **arg, typval_T *rettv, int /* * Get the first variable. */ - if (eval2(arg, rettv, evaluate) == FAIL) + if (eval2(arg, rettv, flags) == FAIL) return FAIL; if ((*arg)[0] == '?') { + int evaluate = flags & EVAL_EVALUATE; + result = FALSE; - if (evaluate) + if (flags & EVAL_EVALUATE) { int error = FALSE; @@ -1836,10 +1844,10 @@ eval1(char_u **arg, typval_T *rettv, int } /* - * 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; /* @@ -1854,10 +1862,10 @@ eval1(char_u **arg, typval_T *rettv, int } /* - * 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) clear_tv(rettv); @@ -1880,7 +1888,7 @@ eval1(char_u **arg, typval_T *rettv, int * Return OK or FAIL. */ static int -eval2(char_u **arg, typval_T *rettv, int evaluate) +eval2(char_u **arg, typval_T *rettv, int flags) { typval_T var2; long result; @@ -1890,7 +1898,7 @@ eval2(char_u **arg, typval_T *rettv, int /* * Get the first variable. */ - if (eval3(arg, rettv, evaluate) == FAIL) + if (eval3(arg, rettv, flags) == FAIL) return FAIL; /* @@ -1900,6 +1908,8 @@ eval2(char_u **arg, typval_T *rettv, int result = FALSE; while ((*arg)[0] == '|' && (*arg)[1] == '|') { + int evaluate = flags & EVAL_EVALUATE; + if (evaluate && first) { if (tv_get_number_chk(rettv, &error) != 0) @@ -1914,7 +1924,8 @@ eval2(char_u **arg, typval_T *rettv, int * 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; /* @@ -1948,7 +1959,7 @@ eval2(char_u **arg, typval_T *rettv, int * Return OK or FAIL. */ static int -eval3(char_u **arg, typval_T *rettv, int evaluate) +eval3(char_u **arg, typval_T *rettv, int flags) { typval_T var2; long result; @@ -1958,7 +1969,7 @@ eval3(char_u **arg, typval_T *rettv, int /* * Get the first variable. */ - if (eval4(arg, rettv, evaluate) == FAIL) + if (eval4(arg, rettv, flags) == FAIL) return FAIL; /* @@ -1968,6 +1979,8 @@ eval3(char_u **arg, typval_T *rettv, int result = TRUE; while ((*arg)[0] == '&' && (*arg)[1] == '&') { + int evaluate = flags & EVAL_EVALUATE; + if (evaluate && first) { if (tv_get_number_chk(rettv, &error) == 0) @@ -1982,7 +1995,7 @@ eval3(char_u **arg, typval_T *rettv, int * 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; /* @@ -2025,7 +2038,7 @@ eval3(char_u **arg, typval_T *rettv, int * Return OK or FAIL. */ static int -eval4(char_u **arg, typval_T *rettv, int evaluate) +eval4(char_u **arg, typval_T *rettv, int flags) { typval_T var2; char_u *p; @@ -2037,7 +2050,7 @@ eval4(char_u **arg, typval_T *rettv, int /* * Get the first variable. */ - if (eval5(arg, rettv, evaluate) == FAIL) + if (eval5(arg, rettv, flags) == FAIL) return FAIL; p = *arg; @@ -2105,12 +2118,12 @@ eval4(char_u **arg, typval_T *rettv, int * Get the second variable. */ *arg = skipwhite(p + len); - if (eval5(arg, &var2, evaluate) == FAIL) + if (eval5(arg, &var2, flags) == FAIL) { clear_tv(rettv); return FAIL; } - if (evaluate) + if (flags & EVAL_EVALUATE) { int ret = typval_compare(rettv, &var2, type, ic); @@ -2172,7 +2185,7 @@ eval_addlist(typval_T *tv1, typval_T *tv * Return OK or FAIL. */ static int -eval5(char_u **arg, typval_T *rettv, int evaluate) +eval5(char_u **arg, typval_T *rettv, int flags) { typval_T var2; int op; @@ -2188,7 +2201,7 @@ eval5(char_u **arg, typval_T *rettv, int /* * Get the first variable. */ - if (eval6(arg, rettv, evaluate, FALSE) == FAIL) + if (eval6(arg, rettv, flags, FALSE) == FAIL) return FAIL; /* @@ -2217,7 +2230,7 @@ eval5(char_u **arg, typval_T *rettv, int // we know that the first operand needs to be a string or number // without evaluating the 2nd operand. So check before to avoid // side effects after an error. - if (evaluate && tv_get_string_chk(rettv) == NULL) + if ((flags & EVAL_EVALUATE) && tv_get_string_chk(rettv) == NULL) { clear_tv(rettv); return FAIL; @@ -2230,13 +2243,13 @@ eval5(char_u **arg, typval_T *rettv, int if (op == '.' && *(*arg + 1) == '.') // .. string concatenation ++*arg; *arg = skipwhite(*arg + 1); - if (eval6(arg, &var2, evaluate, op == '.') == FAIL) + if (eval6(arg, &var2, flags, op == '.') == FAIL) { clear_tv(rettv); return FAIL; } - if (evaluate) + if (flags & EVAL_EVALUATE) { /* * Compute the result. @@ -2358,7 +2371,7 @@ eval5(char_u **arg, typval_T *rettv, int eval6( char_u **arg, typval_T *rettv, - int evaluate, + int flags, int want_string) // after "." operator { typval_T var2; @@ -2373,7 +2386,7 @@ eval6( /* * Get the first variable. */ - if (eval7(arg, rettv, evaluate, want_string) == FAIL) + if (eval7(arg, rettv, flags, want_string) == FAIL) return FAIL; /* @@ -2385,7 +2398,7 @@ eval6( if (op != '*' && op != '/' && op != '%') break; - if (evaluate) + if (flags & EVAL_EVALUATE) { #ifdef FEAT_FLOAT if (rettv->v_type == VAR_FLOAT) @@ -2408,10 +2421,10 @@ eval6( * 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) { #ifdef FEAT_FLOAT if (var2.v_type == VAR_FLOAT) @@ -2528,9 +2541,10 @@ eval6( eval7( char_u **arg, typval_T *rettv, - int evaluate, + int flags, int want_string) // after "." operator { + int evaluate = flags & EVAL_EVALUATE; int len; char_u *s; char_u *start_leader, *end_leader; @@ -2595,7 +2609,7 @@ eval7( /* * List: [expr, expr] */ - case '[': ret = get_list_tv(arg, rettv, evaluate, TRUE); + case '[': ret = get_list_tv(arg, rettv, flags, TRUE); break; /* @@ -2604,7 +2618,7 @@ eval7( case '#': if ((*arg)[1] == '{') { ++*arg; - ret = eval_dict(arg, rettv, evaluate, TRUE); + ret = eval_dict(arg, rettv, flags, TRUE); } else ret = NOTDONE; @@ -2616,7 +2630,7 @@ eval7( */ 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; /* @@ -2649,7 +2663,7 @@ eval7( * 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) @@ -2680,7 +2694,7 @@ eval7( 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 @@ -2697,7 +2711,7 @@ eval7( // Handle following '[', '(' and '.' for expr[expr], expr.name, // expr(expr), expr->name(expr) if (ret == OK) - ret = handle_subscript(arg, rettv, evaluate, TRUE, + ret = handle_subscript(arg, rettv, flags, TRUE, start_leader, &end_leader); /* @@ -2919,7 +2933,8 @@ eval_method( ret = FAIL; } else - ret = eval_func(arg, name, len, rettv, evaluate, &base); + ret = eval_func(arg, name, len, rettv, + evaluate ? EVAL_EVALUATE : 0, &base); } // Clear the funcref afterwards, so that deleting it while @@ -2939,9 +2954,10 @@ eval_method( eval_index( char_u **arg, typval_T *rettv, - int evaluate, + int flags, int verbose) // give error messages { + int evaluate = flags & EVAL_EVALUATE; int empty1 = FALSE, empty2 = FALSE; typval_T var1, var2; long i; @@ -3010,7 +3026,7 @@ eval_index( *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_get_string_chk(&var1) == NULL) { @@ -3028,7 +3044,7 @@ eval_index( *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) clear_tv(&var1); @@ -5310,11 +5326,12 @@ eval_isnamec1(int c) handle_subscript( char_u **arg, typval_T *rettv, - int evaluate, // do more than finding the end + int flags, // do more than finding the end int verbose, // give error messages char_u *start_leader, // start of '!' and '-' prefixes char_u **end_leaderp) // end of '!' and '-' prefixes { + int evaluate = flags & EVAL_EVALUATE; int ret = OK; dict_T *selfdict = NULL; @@ -5374,7 +5391,7 @@ handle_subscript( } else selfdict = NULL; - if (eval_index(arg, rettv, evaluate, verbose) == FAIL) + if (eval_index(arg, rettv, flags, verbose) == FAIL) { clear_tv(rettv); ret = FAIL; @@ -6108,7 +6125,7 @@ ex_echo(exarg_T *eap) need_clr_eos = needclr; 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