summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-04-21 17:57:26 +0200
committerBram Moolenaar <Bram@vim.org>2021-04-21 17:57:26 +0200
commit459fbdbf9216bc7b4721fc192e08b35039036caa (patch)
treed038aa9267a2efe1e1dae0cefea0c26a4e1ca098
parenta369c3d9c1217cd932bc3d1751a8cff1f5aef1e4 (diff)
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.c85
-rw-r--r--src/testdir/test_vim9_expr.vim23
-rw-r--r--src/version.c2
3 files changed, 101 insertions, 9 deletions
diff --git a/src/eval.c b/src/eval.c
index 4dbbc40961..a9f5ae65be 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 456b42612e..fd9b406b24 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 1420e7bdae..1c33c9f348 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,