# HG changeset patch # User Bram Moolenaar # Date 1592064903 -7200 # Node ID 0600ab7b9f095fd122708be31d501da001e9a7d3 # Parent 7c1e92b152ed4b6ba50bda1fc96d1f5ad1d8e290 patch 8.2.0972: Vim9 script variable declarations need a type Commit: https://github.com/vim/vim/commit/c82a5b5da5eab15bc35115545b639fb590272ad7 Author: Bram Moolenaar Date: Sat Jun 13 18:09:19 2020 +0200 patch 8.2.0972: Vim9 script variable declarations need a type Problem: Vim9 script variable declarations need a type. Solution: Make "let var: type" declare a script-local variable. diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -728,8 +728,18 @@ ex_let(exarg_T *eap) else if (expr[0] == '.') emsg(_("E985: .= is not supported with script version 2")); else if (!ends_excmd2(eap->cmd, arg)) - // ":let var1 var2" - arg = list_arg_vars(eap, arg, &first); + { + if (current_sctx.sc_version == SCRIPT_VERSION_VIM9) + { + // Vim9 declaration ":let var: type" + arg = vim9_declare_scriptvar(eap, arg); + } + else + { + // ":let var1 var2" - list values + arg = list_arg_vars(eap, arg, &first); + } + } else if (!eap->skip) { // ":let" diff --git a/src/globals.h b/src/globals.h --- a/src/globals.h +++ b/src/globals.h @@ -1785,6 +1785,8 @@ EXTERN char e_white_after[] INIT(= N_("E EXTERN char e_no_white_before[] INIT(= N_("E1068: No white space allowed before '%s'")); EXTERN char e_lock_unlock[] INIT(= N_("E940: Cannot lock or unlock variable %s")); +EXTERN char e_const_req_value[] INIT(= N_("E1021: const requires a value")); +EXTERN char e_type_req[] INIT(= N_("E1022: type or initialization required")); #endif #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) EXTERN char e_alloc_color[] INIT(= N_("E254: Cannot allocate color %s")); diff --git a/src/proto/vim9script.pro b/src/proto/vim9script.pro --- a/src/proto/vim9script.pro +++ b/src/proto/vim9script.pro @@ -6,4 +6,5 @@ void free_imports(int sid); void ex_import(exarg_T *eap); int find_exported(int sid, char_u **argp, int *name_len, ufunc_T **ufunc, type_T **type); char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx); +char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg); /* vim: set ft=c : */ diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1815,6 +1815,22 @@ def Test_let_missing_type() CheckScriptSuccess(lines) enddef +def Test_let_declaration() + let lines =<< trim END + vim9script + let var: string + g:var_uninit = var + var = 'text' + g:var_test = var + END + CheckScriptSuccess(lines) + assert_equal('', g:var_uninit) + assert_equal('text', g:var_test) + + unlet g:var_uninit + unlet g:var_test +enddef + def Test_forward_declaration() let lines =<< trim END vim9script diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 972, +/**/ 971, /**/ 970, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2255,7 +2255,8 @@ get_script_item_idx(int sid, char_u *nam } /* - * Find "name" in imported items of the current script/ + * Find "name" in imported items of the current script or in "cctx" if not + * NULL. */ imported_T * find_imported(char_u *name, size_t len, cctx_T *cctx) @@ -5012,12 +5013,12 @@ compile_assignment(char_u *arg, exarg_T } else if (cmdidx == CMD_const) { - emsg(_("E1021: const requires a value")); + emsg(_(e_const_req_value)); goto theend; } else if (!has_type || dest == dest_option) { - emsg(_("E1022: type or initialization required")); + emsg(_(e_type_req)); goto theend; } else diff --git a/src/vim9script.c b/src/vim9script.c --- a/src/vim9script.c +++ b/src/vim9script.c @@ -434,4 +434,59 @@ handle_import(char_u *arg_start, garray_ return cmd_end; } +/* + * Declare a script-local variable without init: "let var: type". + * "const" is an error since the value is missing. + * Returns a pointer to after the type. + */ + char_u * +vim9_declare_scriptvar(exarg_T *eap, char_u *arg) +{ + char_u *p; + char_u *name; + scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); + type_T *type; + int called_emsg_before = called_emsg; + typval_T init_tv; + + if (eap->cmdidx == CMD_const) + { + emsg(_(e_const_req_value)); + return arg + STRLEN(arg); + } + + // Check for valid starting character. + if (!eval_isnamec1(*arg)) + { + semsg(_(e_invarg2), arg); + return arg + STRLEN(arg); + } + + for (p = arg + 1; *p != NUL && *p != ':' && eval_isnamec(*p); + MB_PTR_ADV(p)) + ; + + if (*p != ':') + { + emsg(_(e_type_req)); + return arg + STRLEN(arg); + } + name = vim_strnsave(arg, p - arg); + + // parse type + p = skipwhite(p + 1); + type = parse_type(&p, &si->sn_type_list); + if (called_emsg != called_emsg_before) + return p; + + // Create the variable with 0/NULL value. + CLEAR_FIELD(init_tv); + init_tv.v_type = type->tt_type; + set_var_const(name, type, &init_tv, FALSE, 0); + + vim_free(name); + return p; +} + + #endif // FEAT_EVAL