changeset 20840:0600ab7b9f09 v8.2.0972

patch 8.2.0972: Vim9 script variable declarations need a type Commit: https://github.com/vim/vim/commit/c82a5b5da5eab15bc35115545b639fb590272ad7 Author: Bram Moolenaar <Bram@vim.org> 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.
author Bram Moolenaar <Bram@vim.org>
date Sat, 13 Jun 2020 18:15:03 +0200
parents 7c1e92b152ed
children f0411e161f00
files src/evalvars.c src/globals.h src/proto/vim9script.pro src/testdir/test_vim9_script.vim src/version.c src/vim9compile.c src/vim9script.c
diffstat 7 files changed, 92 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- 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"
--- 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"));
--- 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 : */
--- 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
--- 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,
--- 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
--- 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