Mercurial > vim
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) |