To: vim_dev@googlegroups.com Subject: Patch 8.2.1408 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1408 Problem: Vim9: type casting not supported. Solution: Introduce type casting. Files: runtime/doc/vim9.txt, src/vim9compile.c, src/testdir/test_vim9_expr.vim, src/testdir/test_vim9_disassemble.vim *** ../vim-8.2.1407/runtime/doc/vim9.txt 2020-08-09 17:21:25.662269290 +0200 --- runtime/doc/vim9.txt 2020-08-09 18:43:51.565213946 +0200 *************** *** 640,645 **** --- 640,674 ---- {not implemented yet} + Variable types and type casting *variable-types* + + Variables declared in Vim9 script or in a `:def` function have a type, either + specified explicitly or inferred from the initialization. + + Global, buffer, window and tab page variables do not have a specific type, the + value can be changed at any time, possibly changing the type. Therefore, in + compiled code the "any" type is assumed. + + This can be a problem when the "any" type is undesired and the actual type is + expected to always be the same. For example, when declaring a list: > + let l: list = [1, g:two] + This will give an error, because "g:two" has type "any". To avoid this, use a + type cast: > + let l: list = [1, g:two] + < *type-casting* + The compiled code will then check that "g:two" is a number at runtime and give + an error if it isn't. This is called type casting. + + The syntax of a type cast is: "<" {type} ">". There cannot be white space + after the "<" or before the ">" (to avoid them being confused with + smaller-than and bigger-than operators). + + The semantics is that, if needed, a runtime type check is performed. The + value is not actually changed. If you need to change the type, e.g. to change + it to a string, use the |string()| function. Or use |str2nr()| to convert a + string to a number. + + Type inference *type-inference* In general: Whenever the type is clear it can be omitted. For example, when *** ../vim-8.2.1407/src/vim9compile.c 2020-08-09 17:21:25.662269290 +0200 --- src/vim9compile.c 2020-08-09 18:21:19.198159457 +0200 *************** *** 3402,3407 **** --- 3402,3457 ---- } /* + * expr7: runtime type check / conversion + */ + static int + compile_expr7t(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) + { + type_T *want_type = NULL; + + // Recognize + if (**arg == '<' && eval_isnamec1((*arg)[1])) + { + int called_emsg_before = called_emsg; + + ++*arg; + want_type = parse_type(arg, cctx->ctx_type_list); + if (called_emsg != called_emsg_before) + return FAIL; + + if (**arg != '>') + { + if (*skipwhite(*arg) == '>') + semsg(_(e_no_white_before), ">"); + else + emsg(_("E1104: Missing >")); + return FAIL; + } + ++*arg; + if (may_get_next_line_error(*arg - 1, arg, cctx) == FAIL) + return FAIL; + } + + if (compile_expr7(arg, cctx, ppconst) == FAIL) + return FAIL; + + if (want_type != NULL) + { + garray_T *stack = &cctx->ctx_type_stack; + type_T *actual = ((type_T **)stack->ga_data)[stack->ga_len - 1]; + + if (check_type(want_type, actual, FALSE) == FAIL) + { + generate_ppconst(cctx, ppconst); + if (need_type(actual, want_type, -1, cctx, FALSE) == FAIL) + return FAIL; + } + } + + return OK; + } + + /* * * number multiplication * / number division * % number modulo *************** *** 3414,3420 **** int ppconst_used = ppconst->pp_used; // get the first expression ! if (compile_expr7(arg, cctx, ppconst) == FAIL) return FAIL; /* --- 3464,3470 ---- int ppconst_used = ppconst->pp_used; // get the first expression ! if (compile_expr7t(arg, cctx, ppconst) == FAIL) return FAIL; /* *************** *** 3441,3447 **** return FAIL; // get the second expression ! if (compile_expr7(arg, cctx, ppconst) == FAIL) return FAIL; if (ppconst->pp_used == ppconst_used + 2 --- 3491,3497 ---- return FAIL; // get the second expression ! if (compile_expr7t(arg, cctx, ppconst) == FAIL) return FAIL; if (ppconst->pp_used == ppconst_used + 2 *** ../vim-8.2.1407/src/testdir/test_vim9_expr.vim 2020-08-09 17:21:25.662269290 +0200 --- src/testdir/test_vim9_expr.vim 2020-08-09 18:47:05.476495220 +0200 *************** *** 1247,1252 **** --- 1247,1258 ---- let $TESTVAR = 'testvar' + " type casts + def Test_expr7t() + let ls: list = ['a', g:string_empty] + let ln: list = [g:anint, g:alsoint] + enddef + " test low level expression def Test_expr7_number() # number constant *** ../vim-8.2.1407/src/testdir/test_vim9_disassemble.vim 2020-07-31 22:04:59.776336159 +0200 --- src/testdir/test_vim9_disassemble.vim 2020-08-09 18:56:51.390358687 +0200 *************** *** 817,822 **** --- 817,840 ---- let g:number = 42 + def TypeCast() + let l: list = [23, g:number] + enddef + + def Test_disassemble_typecast() + let instr = execute('disassemble TypeCast') + assert_match('TypeCast.*' .. + 'let l: list = \[23, g:number\].*' .. + '\d PUSHNR 23\_s*' .. + '\d LOADG g:number\_s*' .. + '\d CHECKTYPE number stack\[-1\]\_s*' .. + '\d NEWLIST size 2\_s*' .. + '\d STORE $0\_s*' .. + '\d PUSHNR 0\_s*' .. + '\d RETURN\_s*', + instr) + enddef + def Computing() let nr = 3 let nrres = nr + 7 *** ../vim-8.2.1407/src/version.c 2020-08-09 17:21:25.662269290 +0200 --- src/version.c 2020-08-09 18:40:17.790018360 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 1408, /**/ -- hundred-and-one symptoms of being an internet addict: 165. You have a web page burned into your glasses /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///