diff options
author | Bram Moolenaar <Bram@vim.org> | 2021-04-21 17:57:26 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-04-21 17:57:26 +0200 |
commit | 459fbdbf9216bc7b4721fc192e08b35039036caa (patch) | |
tree | d038aa9267a2efe1e1dae0cefea0c26a4e1ca098 | |
parent | a369c3d9c1217cd932bc3d1751a8cff1f5aef1e4 (diff) | |
download | vim-git-459fbdbf9216bc7b4721fc192e08b35039036caa.tar.gz |
patch 8.2.2799: Vim9: type casts don't fully work at the script levelv8.2.2799
Problem: Vim9: type casts don't fully work at the script level.
Solution: Implement the missing piece.
-rw-r--r-- | src/eval.c | 85 | ||||
-rw-r--r-- | src/testdir/test_vim9_expr.vim | 23 | ||||
-rw-r--r-- | src/version.c | 2 |
3 files changed, 101 insertions, 9 deletions
diff --git a/src/eval.c b/src/eval.c index 4dbbc4096..a9f5ae65b 100644 --- a/src/eval.c +++ b/src/eval.c @@ -51,6 +51,7 @@ static int eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg); static int eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg); static int eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg); static int eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); +static int eval7t(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); static int eval7(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); static int eval7_leader(typval_T *rettv, int numeric_only, char_u *start_leader, char_u **end_leaderp); @@ -3068,7 +3069,7 @@ eval6( /* * Get the first variable. */ - if (eval7(arg, rettv, evalarg, want_string) == FAIL) + if (eval7t(arg, rettv, evalarg, want_string) == FAIL) return FAIL; /* @@ -3141,7 +3142,7 @@ eval6( return FAIL; } *arg = skipwhite_and_linebreak(*arg + 1, evalarg); - if (eval7(arg, &var2, evalarg, FALSE) == FAIL) + if (eval7t(arg, &var2, evalarg, FALSE) == FAIL) return FAIL; if (evaluate) @@ -3231,6 +3232,86 @@ eval6( return OK; } +/* + * Handle a type cast before a base level expression. + * "arg" must point to the first non-white of the expression. + * "arg" is advanced to just after the recognized expression. + * Return OK or FAIL. + */ + static int +eval7t( + char_u **arg, + typval_T *rettv, + evalarg_T *evalarg, + int want_string) // after "." operator +{ + type_T *want_type = NULL; + garray_T type_list; // list of pointers to allocated types + int res; + int evaluate = evalarg == NULL ? 0 + : (evalarg->eval_flags & EVAL_EVALUATE); + + // Recognize <type> in Vim9 script only. + if (in_vim9script() && **arg == '<' && eval_isnamec1((*arg)[1])) + { + ++*arg; + ga_init2(&type_list, sizeof(type_T *), 10); + want_type = parse_type(arg, &type_list, TRUE); + if (want_type == NULL && (evaluate || **arg != '>')) + { + clear_type_list(&type_list); + return FAIL; + } + + if (**arg != '>') + { + if (*skipwhite(*arg) == '>') + semsg(_(e_no_white_space_allowed_before_str_str), ">", *arg); + else + emsg(_(e_missing_gt)); + clear_type_list(&type_list); + return FAIL; + } + ++*arg; + *arg = skipwhite_and_linebreak(*arg, evalarg); + } + + res = eval7(arg, rettv, evalarg, want_string); + + if (want_type != NULL && evaluate) + { + if (res == OK) + { + type_T *actual = typval2type(rettv, get_copyID(), &type_list, TRUE); + + if (!equal_type(want_type, actual)) + { + if (want_type == &t_bool && actual != &t_bool + && (actual->tt_flags & TTFLAG_BOOL_OK)) + { + int n = tv2bool(rettv); + + // can use "0" and "1" for boolean in some places + clear_tv(rettv); + rettv->v_type = VAR_BOOL; + rettv->vval.v_number = n ? VVAL_TRUE : VVAL_FALSE; + } + else + { + where_T where; + + where.wt_index = 0; + where.wt_variable = TRUE; + res = check_type(want_type, actual, TRUE, where); + } + } + } + clear_type_list(&type_list); + } + + return res; +} + int eval_leader(char_u **arg, int vim9) { diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 456b42612..fd9b406b2 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -1575,16 +1575,25 @@ let $TESTVAR = 'testvar' " type casts def Test_expr7t() - var ls: list<string> = ['a', <string>g:string_empty] - var ln: list<number> = [<number>g:anint, <number>g:thefour] - var nr = <number>234 - assert_equal(234, nr) + var lines =<< trim END + var ls: list<string> = ['a', <string>g:string_empty] + var ln: list<number> = [<number>g:anint, <number>g:thefour] + var nr = <number>234 + assert_equal(234, nr) + var text = + <string> + 'text' + if false + text = <number>'xxx' + endif + END + CheckDefAndScriptSuccess(lines) - CheckDefAndScriptFailure2(["var x = <nr>123"], 'E1010:', 'E15:', 1) + CheckDefAndScriptFailure(["var x = <nr>123"], 'E1010:', 1) CheckDefFailure(["var x = <number>"], 'E1097:', 3) CheckScriptFailure(['vim9script', "var x = <number>"], 'E15:', 2) - CheckDefAndScriptFailure2(["var x = <number >123"], 'E1068:', 'E15:', 1) - CheckDefAndScriptFailure2(["var x = <number 123"], 'E1104:', 'E15:', 1) + CheckDefAndScriptFailure(["var x = <number >123"], 'E1068:', 1) + CheckDefAndScriptFailure(["var x = <number 123"], 'E1104:', 1) enddef " test low level expression diff --git a/src/version.c b/src/version.c index 1420e7bda..1c33c9f34 100644 --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2799, +/**/ 2798, /**/ 2797, |