comparison 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
comparison
equal deleted inserted replaced
20396:89228c88b5c4 20397:c225be44692a
431 prepare_vimvar(VV_VAL, &save_val); 431 prepare_vimvar(VV_VAL, &save_val);
432 set_vim_var_string(VV_VAL, badword, -1); 432 set_vim_var_string(VV_VAL, badword, -1);
433 if (p_verbose == 0) 433 if (p_verbose == 0)
434 ++emsg_off; 434 ++emsg_off;
435 435
436 if (eval1(&p, &rettv, TRUE) == OK) 436 if (eval1(&p, &rettv, EVAL_EVALUATE) == OK)
437 { 437 {
438 if (rettv.v_type != VAR_LIST) 438 if (rettv.v_type != VAR_LIST)
439 clear_tv(&rettv); 439 clear_tv(&rettv);
440 else 440 else
441 list = rettv.vval.v_list; 441 list = rettv.vval.v_list;
699 { 699 {
700 ex_let_const(eap, FALSE); 700 ex_let_const(eap, FALSE);
701 } 701 }
702 702
703 /* 703 /*
704 * When "redefine" is TRUE the command will be executed again, redefining the 704 * When "discovery" is TRUE the ":let" or ":const" is encountered during the
705 * variable is OK then. 705 * discovery phase of vim9script:
706 */ 706 * - The command will be executed again, redefining the variable is OK then.
707 void 707 * - The expresion argument must be a constant.
708 ex_let_const(exarg_T *eap, int redefine) 708 * - If no constant expression a type must be specified.
709 */
710 void
711 ex_let_const(exarg_T *eap, int discovery)
709 { 712 {
710 char_u *arg = eap->arg; 713 char_u *arg = eap->arg;
711 char_u *expr = NULL; 714 char_u *expr = NULL;
712 typval_T rettv; 715 typval_T rettv;
713 int i; 716 int i;
715 int semicolon = 0; 718 int semicolon = 0;
716 char_u op[2]; 719 char_u op[2];
717 char_u *argend; 720 char_u *argend;
718 int first = TRUE; 721 int first = TRUE;
719 int concat; 722 int concat;
723 int has_assign;
720 int flags = eap->cmdidx == CMD_const ? LET_IS_CONST : 0; 724 int flags = eap->cmdidx == CMD_const ? LET_IS_CONST : 0;
721 725
722 // detect Vim9 assignment without ":let" or ":const" 726 // detect Vim9 assignment without ":let" or ":const"
723 if (eap->arg == eap->cmd) 727 if (eap->arg == eap->cmd)
724 flags |= LET_NO_COMMAND; 728 flags |= LET_NO_COMMAND;
725 if (redefine) 729 if (discovery)
726 flags |= LET_REDEFINE; 730 flags |= LET_DISCOVERY;
727 731
728 argend = skip_var_list(arg, TRUE, &var_count, &semicolon); 732 argend = skip_var_list(arg, TRUE, &var_count, &semicolon);
729 if (argend == NULL) 733 if (argend == NULL)
730 return; 734 return;
731 if (argend > arg && argend[-1] == '.') // for var.='str' 735 if (argend > arg && argend[-1] == '.') // for var.='str'
732 --argend; 736 --argend;
733 expr = skipwhite(argend); 737 expr = skipwhite(argend);
734 concat = expr[0] == '.' 738 concat = expr[0] == '.'
735 && ((expr[1] == '=' && current_sctx.sc_version < 2) 739 && ((expr[1] == '=' && current_sctx.sc_version < 2)
736 || (expr[1] == '.' && expr[2] == '=')); 740 || (expr[1] == '.' && expr[2] == '='));
737 if (*expr != '=' && !((vim_strchr((char_u *)"+-*/%", *expr) != NULL 741 has_assign = *expr == '=' || (vim_strchr((char_u *)"+-*/%", *expr) != NULL
738 && expr[1] == '=') || concat)) 742 && expr[1] == '=');
743 if (!has_assign && !concat && !discovery)
739 { 744 {
740 // ":let" without "=": list variables 745 // ":let" without "=": list variables
741 if (*arg == '[') 746 if (*arg == '[')
742 emsg(_(e_invarg)); 747 emsg(_(e_invarg));
743 else if (expr[0] == '.') 748 else if (expr[0] == '.')
777 clear_tv(&rettv); 782 clear_tv(&rettv);
778 } 783 }
779 } 784 }
780 else 785 else
781 { 786 {
782 op[0] = '='; 787 int eval_flags;
783 op[1] = NUL; 788 int save_called_emsg = called_emsg;
784 if (*expr != '=') 789
785 { 790 rettv.v_type = VAR_UNKNOWN;
786 if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) 791 i = FAIL;
792 if (has_assign || concat)
793 {
794 op[0] = '=';
795 op[1] = NUL;
796 if (*expr != '=')
787 { 797 {
788 op[0] = *expr; // +=, -=, *=, /=, %= or .= 798 if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL)
789 if (expr[0] == '.' && expr[1] == '.') // ..= 799 {
790 ++expr; 800 op[0] = *expr; // +=, -=, *=, /=, %= or .=
801 if (expr[0] == '.' && expr[1] == '.') // ..=
802 ++expr;
803 }
804 expr = skipwhite(expr + 2);
791 } 805 }
792 expr = skipwhite(expr + 2); 806 else
793 } 807 expr = skipwhite(expr + 1);
794 else 808
795 expr = skipwhite(expr + 1); 809 if (eap->skip)
796 810 ++emsg_skip;
797 if (eap->skip) 811 eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
798 ++emsg_skip; 812 if (discovery)
799 i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip); 813 eval_flags |= EVAL_CONSTANT;
814 i = eval0(expr, &rettv, &eap->nextcmd, eval_flags);
815 }
800 if (eap->skip) 816 if (eap->skip)
801 { 817 {
802 if (i != FAIL) 818 if (i != FAIL)
803 clear_tv(&rettv); 819 clear_tv(&rettv);
804 --emsg_skip; 820 --emsg_skip;
805 } 821 }
806 else if (i != FAIL) 822 else if (i != FAIL || (discovery && save_called_emsg == called_emsg))
807 { 823 {
824 // In Vim9 script discovery "let v: bool = Func()" fails but is
825 // still a valid declaration.
808 (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count, 826 (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
809 flags, op); 827 flags, op);
810 clear_tv(&rettv); 828 clear_tv(&rettv);
811 } 829 }
812 } 830 }
1110 error = TRUE; 1128 error = TRUE;
1111 else 1129 else
1112 { 1130 {
1113 // handle d.key, l[idx], f(expr) 1131 // handle d.key, l[idx], f(expr)
1114 arg_subsc = arg; 1132 arg_subsc = arg;
1115 if (handle_subscript(&arg, &tv, TRUE, TRUE, 1133 if (handle_subscript(&arg, &tv, EVAL_EVALUATE, TRUE,
1116 name, &name) == FAIL) 1134 name, &name) == FAIL)
1117 error = TRUE; 1135 error = TRUE;
1118 else 1136 else
1119 { 1137 {
1120 if (arg == arg_subsc && len == 2 && name[1] == ':') 1138 if (arg == arg_subsc && len == 2 && name[1] == ':')
1351 else if (eval_isnamec1(*arg) || *arg == '{') 1369 else if (eval_isnamec1(*arg) || *arg == '{')
1352 { 1370 {
1353 lval_T lv; 1371 lval_T lv;
1354 1372
1355 p = get_lval(arg, tv, &lv, FALSE, FALSE, 0, FNE_CHECK_START); 1373 p = get_lval(arg, tv, &lv, FALSE, FALSE, 0, FNE_CHECK_START);
1356 if (p != NULL && lv.ll_name != NULL) 1374 if ((flags & LET_DISCOVERY) && tv->v_type == VAR_UNKNOWN
1375 && lv.ll_type == NULL)
1376 {
1377 semsg(_("E1091: type missing for %s"), arg);
1378 }
1379 else if (p != NULL && lv.ll_name != NULL)
1357 { 1380 {
1358 if (endchars != NULL && vim_strchr(endchars, 1381 if (endchars != NULL && vim_strchr(endchars,
1359 *skipwhite(lv.ll_name_end)) == NULL) 1382 *skipwhite(lv.ll_name_end)) == NULL)
1360 emsg(_(e_letunexp)); 1383 emsg(_(e_letunexp));
1361 else 1384 else
2979 init_tv(tv); 3002 init_tv(tv);
2980 } 3003 }
2981 3004
2982 if (flags & LET_IS_CONST) 3005 if (flags & LET_IS_CONST)
2983 di->di_tv.v_lock |= VAR_LOCKED; 3006 di->di_tv.v_lock |= VAR_LOCKED;
2984 if (flags & LET_REDEFINE) 3007 if (flags & LET_DISCOVERY)
2985 di->di_flags |= DI_FLAGS_RELOAD; 3008 di->di_flags |= DI_FLAGS_RELOAD;
2986 } 3009 }
2987 3010
2988 /* 3011 /*
2989 * Return TRUE if di_flags "flags" indicates variable "name" is read-only. 3012 * Return TRUE if di_flags "flags" indicates variable "name" is read-only.
3286 name = tofree; 3309 name = tofree;
3287 n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK); 3310 n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK);
3288 if (n) 3311 if (n)
3289 { 3312 {
3290 // handle d.key, l[idx], f(expr) 3313 // handle d.key, l[idx], f(expr)
3291 n = (handle_subscript(&var, &tv, TRUE, FALSE, name, &name) == OK); 3314 n = (handle_subscript(&var, &tv, EVAL_EVALUATE,
3315 FALSE, name, &name) == OK);
3292 if (n) 3316 if (n)
3293 clear_tv(&tv); 3317 clear_tv(&tv);
3294 } 3318 }
3295 } 3319 }
3296 if (*var != NUL) 3320 if (*var != NUL)