Mercurial > vim
diff src/evalvars.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 | 489cb75c76b6 |
line wrap: on
line diff
--- a/src/evalvars.c +++ b/src/evalvars.c @@ -433,7 +433,7 @@ eval_spell_expr(char_u *badword, char_u if (p_verbose == 0) ++emsg_off; - if (eval1(&p, &rettv, TRUE) == OK) + if (eval1(&p, &rettv, EVAL_EVALUATE) == OK) { if (rettv.v_type != VAR_LIST) clear_tv(&rettv); @@ -701,11 +701,14 @@ ex_const(exarg_T *eap) } /* - * When "redefine" is TRUE the command will be executed again, redefining the - * variable is OK then. + * When "discovery" is TRUE the ":let" or ":const" is encountered during the + * discovery phase of vim9script: + * - The command will be executed again, redefining the variable is OK then. + * - The expresion argument must be a constant. + * - If no constant expression a type must be specified. */ void -ex_let_const(exarg_T *eap, int redefine) +ex_let_const(exarg_T *eap, int discovery) { char_u *arg = eap->arg; char_u *expr = NULL; @@ -717,13 +720,14 @@ ex_let_const(exarg_T *eap, int redefine) char_u *argend; int first = TRUE; int concat; + int has_assign; int flags = eap->cmdidx == CMD_const ? LET_IS_CONST : 0; // detect Vim9 assignment without ":let" or ":const" if (eap->arg == eap->cmd) flags |= LET_NO_COMMAND; - if (redefine) - flags |= LET_REDEFINE; + if (discovery) + flags |= LET_DISCOVERY; argend = skip_var_list(arg, TRUE, &var_count, &semicolon); if (argend == NULL) @@ -734,8 +738,9 @@ ex_let_const(exarg_T *eap, int redefine) concat = expr[0] == '.' && ((expr[1] == '=' && current_sctx.sc_version < 2) || (expr[1] == '.' && expr[2] == '=')); - if (*expr != '=' && !((vim_strchr((char_u *)"+-*/%", *expr) != NULL - && expr[1] == '=') || concat)) + has_assign = *expr == '=' || (vim_strchr((char_u *)"+-*/%", *expr) != NULL + && expr[1] == '='); + if (!has_assign && !concat && !discovery) { // ":let" without "=": list variables if (*arg == '[') @@ -779,32 +784,45 @@ ex_let_const(exarg_T *eap, int redefine) } else { - op[0] = '='; - op[1] = NUL; - if (*expr != '=') + int eval_flags; + int save_called_emsg = called_emsg; + + rettv.v_type = VAR_UNKNOWN; + i = FAIL; + if (has_assign || concat) { - if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) + op[0] = '='; + op[1] = NUL; + if (*expr != '=') { - op[0] = *expr; // +=, -=, *=, /=, %= or .= - if (expr[0] == '.' && expr[1] == '.') // ..= - ++expr; + if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) + { + op[0] = *expr; // +=, -=, *=, /=, %= or .= + if (expr[0] == '.' && expr[1] == '.') // ..= + ++expr; + } + expr = skipwhite(expr + 2); } - expr = skipwhite(expr + 2); + else + expr = skipwhite(expr + 1); + + if (eap->skip) + ++emsg_skip; + eval_flags = eap->skip ? 0 : EVAL_EVALUATE; + if (discovery) + eval_flags |= EVAL_CONSTANT; + i = eval0(expr, &rettv, &eap->nextcmd, eval_flags); } - else - expr = skipwhite(expr + 1); - - if (eap->skip) - ++emsg_skip; - i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip); if (eap->skip) { if (i != FAIL) clear_tv(&rettv); --emsg_skip; } - else if (i != FAIL) + else if (i != FAIL || (discovery && save_called_emsg == called_emsg)) { + // In Vim9 script discovery "let v: bool = Func()" fails but is + // still a valid declaration. (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count, flags, op); clear_tv(&rettv); @@ -1112,7 +1130,7 @@ list_arg_vars(exarg_T *eap, char_u *arg, { // handle d.key, l[idx], f(expr) arg_subsc = arg; - if (handle_subscript(&arg, &tv, TRUE, TRUE, + if (handle_subscript(&arg, &tv, EVAL_EVALUATE, TRUE, name, &name) == FAIL) error = TRUE; else @@ -1353,7 +1371,12 @@ ex_let_one( lval_T lv; p = get_lval(arg, tv, &lv, FALSE, FALSE, 0, FNE_CHECK_START); - if (p != NULL && lv.ll_name != NULL) + if ((flags & LET_DISCOVERY) && tv->v_type == VAR_UNKNOWN + && lv.ll_type == NULL) + { + semsg(_("E1091: type missing for %s"), arg); + } + else if (p != NULL && lv.ll_name != NULL) { if (endchars != NULL && vim_strchr(endchars, *skipwhite(lv.ll_name_end)) == NULL) @@ -2981,7 +3004,7 @@ set_var_const( if (flags & LET_IS_CONST) di->di_tv.v_lock |= VAR_LOCKED; - if (flags & LET_REDEFINE) + if (flags & LET_DISCOVERY) di->di_flags |= DI_FLAGS_RELOAD; } @@ -3288,7 +3311,8 @@ var_exists(char_u *var) if (n) { // handle d.key, l[idx], f(expr) - n = (handle_subscript(&var, &tv, TRUE, FALSE, name, &name) == OK); + n = (handle_subscript(&var, &tv, EVAL_EVALUATE, + FALSE, name, &name) == OK); if (n) clear_tv(&tv); }