changeset 24112:0346a59ed5bf v8.2.2597

patch 8.2.2597: Vim9: "import * as" does not work at script level Commit: https://github.com/vim/vim/commit/cb4e80fab9b1ee67249bde4f784526f900cda70c Author: Bram Moolenaar <Bram@vim.org> Date: Sat Mar 13 20:57:19 2021 +0100 patch 8.2.2597: Vim9: "import * as" does not work at script level Problem: Vim9: "import * as" does not work at script level. Solution: Implement using an imported namespace.
author Bram Moolenaar <Bram@vim.org>
date Sat, 13 Mar 2021 21:00:03 +0100
parents 33c1e030ceae
children bc9303ef0b87
files src/errors.h src/eval.c src/evalvars.c src/proto/evalvars.pro src/proto/vim9script.pro src/testdir/test_vim9_script.vim src/version.c src/vim.h src/vim9execute.c src/vim9script.c
diffstat 10 files changed, 129 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/src/errors.h
+++ b/src/errors.h
@@ -373,3 +373,5 @@ EXTERN char e_argument_name_shadows_exis
 	INIT(= N_("E1167: Argument name shadows existing variable: %s"));
 EXTERN char e_argument_already_declared_in_script_str[]
 	INIT(= N_("E1168: Argument already declared in the script: %s"));
+EXTERN char e_import_as_name_not_supported_here[]
+	INIT(= N_("E1169: 'import * as {name}' not supported here"));
--- a/src/eval.c
+++ b/src/eval.c
@@ -1370,7 +1370,7 @@ set_var_lval(
 	    // handle +=, -=, *=, /=, %= and .=
 	    di = NULL;
 	    if (eval_variable(lp->ll_name, (int)STRLEN(lp->ll_name),
-					     &tv, &di, TRUE, FALSE) == OK)
+					     &tv, &di, EVAL_VAR_VERBOSE) == OK)
 	    {
 		if ((di == NULL
 			 || (!var_check_ro(di->di_flags, lp->ll_name, FALSE)
@@ -3500,7 +3500,8 @@ eval7(
 		    ret = OK;
 		}
 		else
-		    ret = eval_variable(s, len, rettv, NULL, TRUE, FALSE);
+		    ret = eval_variable(s, len, rettv, NULL,
+					   EVAL_VAR_VERBOSE + EVAL_VAR_IMPORT);
 	    }
 	    else
 	    {
@@ -5760,6 +5761,63 @@ handle_subscript(
 	    check_white = FALSE;
 	}
 
+	if (rettv->v_type == VAR_ANY)
+	{
+	    char_u	*exp_name;
+	    int		cc;
+	    int		idx;
+	    ufunc_T	*ufunc;
+	    type_T	*type;
+
+	    // Found script from "import * as {name}", script item name must
+	    // follow.
+	    if (**arg != '.')
+	    {
+		if (verbose)
+		    semsg(_(e_expected_str_but_got_str), "'.'", *arg);
+		ret = FAIL;
+		break;
+	    }
+	    ++*arg;
+	    if (IS_WHITE_OR_NUL(**arg))
+	    {
+		if (verbose)
+		    emsg(_(e_no_white_space_allowed_after_dot));
+		ret = FAIL;
+		break;
+	    }
+
+	    // isolate the name
+	    exp_name = *arg;
+	    while (eval_isnamec(**arg))
+		++*arg;
+	    cc = **arg;
+	    **arg = NUL;
+
+	    idx = find_exported(rettv->vval.v_number, exp_name, &ufunc, &type,
+						  evalarg->eval_cctx, verbose);
+	    **arg = cc;
+	    *arg = skipwhite(*arg);
+
+	    if (idx < 0 && ufunc == NULL)
+	    {
+		ret = FAIL;
+		break;
+	    }
+	    if (idx >= 0)
+	    {
+		scriptitem_T    *si = SCRIPT_ITEM(rettv->vval.v_number);
+		svar_T		*sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
+
+		copy_tv(sv->sv_tv, rettv);
+	    }
+	    else
+	    {
+		rettv->v_type = VAR_FUNC;
+		rettv->vval.v_string = vim_strsave(ufunc->uf_name);
+	    }
+	}
+
 	if ((**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC
 			    || rettv->v_type == VAR_PARTIAL))
 		    && (!check_white || !VIM_ISWHITE(*(*arg - 1))))
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -1219,7 +1219,8 @@ list_arg_vars(exarg_T *eap, char_u *arg,
 		arg = skipwhite(arg);
 		if (tofree != NULL)
 		    name = tofree;
-		if (eval_variable(name, len, &tv, NULL, TRUE, FALSE) == FAIL)
+		if (eval_variable(name, len, &tv, NULL,
+						     EVAL_VAR_VERBOSE) == FAIL)
 		    error = TRUE;
 		else
 		{
@@ -2539,6 +2540,8 @@ set_cmdarg(exarg_T *eap, char_u *oldarg)
 
 /*
  * Get the value of internal variable "name".
+ * If "flags" has EVAL_VAR_IMPORT may return a VAR_ANY with v_number set to the
+ * imported script ID.
  * Return OK or FAIL.  If OK is returned "rettv" must be cleared.
  */
     int
@@ -2547,12 +2550,11 @@ eval_variable(
     int		len,		// length of "name"
     typval_T	*rettv,		// NULL when only checking existence
     dictitem_T	**dip,		// non-NULL when typval's dict item is needed
-    int		verbose,	// may give error message
-    int		no_autoload)	// do not use script autoloading
+    int		flags)		// EVAL_VAR_ flags
 {
     int		ret = OK;
     typval_T	*tv = NULL;
-    int		foundFunc = FALSE;
+    int		found = FALSE;
     dictitem_T	*v;
     int		cc;
 
@@ -2561,7 +2563,7 @@ eval_variable(
     name[len] = NUL;
 
     // Check for user-defined variables.
-    v = find_var(name, NULL, no_autoload);
+    v = find_var(name, NULL, flags & EVAL_VAR_NOAUTOLOAD);
     if (v != NULL)
     {
 	tv = &v->di_tv;
@@ -2581,7 +2583,7 @@ eval_variable(
 	{
 	    if (import->imp_funcname != NULL)
 	    {
-		foundFunc = TRUE;
+		found = TRUE;
 		if (rettv != NULL)
 		{
 		    rettv->v_type = VAR_FUNC;
@@ -2590,8 +2592,21 @@ eval_variable(
 	    }
 	    else if (import->imp_flags & IMP_FLAGS_STAR)
 	    {
-		emsg("Sorry, 'import * as X' not implemented yet");
-		ret = FAIL;
+		if ((flags & EVAL_VAR_IMPORT) == 0)
+		{
+		    if (flags & EVAL_VAR_VERBOSE)
+			emsg(_(e_import_as_name_not_supported_here));
+		    ret = FAIL;
+		}
+		else
+		{
+		    if (rettv != NULL)
+		    {
+			rettv->v_type = VAR_ANY;
+			rettv->vval.v_number = import->imp_sid;
+		    }
+		    found = TRUE;
+		}
 	    }
 	    else
 	    {
@@ -2607,7 +2622,7 @@ eval_variable(
 
 	    if (ufunc != NULL)
 	    {
-		foundFunc = TRUE;
+		found = TRUE;
 		if (rettv != NULL)
 		{
 		    rettv->v_type = VAR_FUNC;
@@ -2617,11 +2632,11 @@ eval_variable(
 	}
     }
 
-    if (!foundFunc)
+    if (!found)
     {
 	if (tv == NULL)
 	{
-	    if (rettv != NULL && verbose)
+	    if (rettv != NULL && (flags & EVAL_VAR_VERBOSE))
 		semsg(_(e_undefined_variable_str), name);
 	    ret = FAIL;
 	}
@@ -3695,7 +3710,8 @@ var_exists(char_u *var)
     {
 	if (tofree != NULL)
 	    name = tofree;
-	n = (eval_variable(name, len, &tv, NULL, FALSE, TRUE) == OK);
+	n = (eval_variable(name, len, &tv, NULL,
+				 EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT) == OK);
 	if (n)
 	{
 	    // handle d.key, l[idx], f(expr)
--- a/src/proto/evalvars.pro
+++ b/src/proto/evalvars.pro
@@ -56,7 +56,7 @@ void set_reg_var(int c);
 char_u *v_exception(char_u *oldval);
 char_u *v_throwpoint(char_u *oldval);
 char_u *set_cmdarg(exarg_T *eap, char_u *oldarg);
-int eval_variable(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int verbose, int no_autoload);
+int eval_variable(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int flags);
 void check_vars(char_u *name, int len);
 dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
 dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
--- a/src/proto/vim9script.pro
+++ b/src/proto/vim9script.pro
@@ -7,7 +7,7 @@ void ex_export(exarg_T *eap);
 void free_imports_and_script_vars(int sid);
 void mark_imports_for_reload(int sid);
 void ex_import(exarg_T *eap);
-int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx);
+int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx, int verbose);
 char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, evalarg_T *evalarg, void *cctx);
 char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg);
 void update_vim9_script_var(int create, dictitem_T *di, int flags, typval_T *tv, type_T **type);
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -1031,13 +1031,17 @@ def Test_vim9_import_export()
     vim9script
     import * as Export from './Xexport.vim'
     def UseExport()
-      g:imported = Export.exported
+      g:imported_def = Export.exported
     enddef
+    g:imported_script = Export.exported
+    assert_equal(1, exists('Export.exported'))
+    assert_equal(0, exists('Export.notexported'))
     UseExport()
   END
   writefile(import_star_as_lines, 'Ximport.vim')
   source Ximport.vim
-  assert_equal(9883, g:imported)
+  assert_equal(9883, g:imported_def)
+  assert_equal(9883, g:imported_script)
 
   var import_star_as_lines_no_dot =<< trim END
     vim9script
@@ -1072,6 +1076,22 @@ def Test_vim9_import_export()
   writefile(import_star_as_duplicated, 'Ximport.vim')
   assert_fails('source Ximport.vim', 'E1073:', '', 4, 'Ximport.vim')
 
+  var import_star_as_lines_script_no_dot =<< trim END
+    vim9script
+    import * as Export from './Xexport.vim'
+    g:imported_script = Export exported
+  END
+  writefile(import_star_as_lines_script_no_dot, 'Ximport.vim')
+  assert_fails('source Ximport.vim', 'E1029:')
+
+  var import_star_as_lines_script_space_after_dot =<< trim END
+    vim9script
+    import * as Export from './Xexport.vim'
+    g:imported_script = Export. exported
+  END
+  writefile(import_star_as_lines_script_space_after_dot, 'Ximport.vim')
+  assert_fails('source Ximport.vim', 'E1074:')
+
   var import_star_as_lines_missing_name =<< trim END
     vim9script
     import * as Export from './Xexport.vim'
--- 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 */
 /**/
+    2597,
+/**/
     2596,
 /**/
     2595,
--- a/src/vim.h
+++ b/src/vim.h
@@ -2702,4 +2702,9 @@ long elapsed(DWORD start_tick);
 #define MCH_DELAY_IGNOREINPUT	1
 #define MCH_DELAY_SETTMODE	2
 
+// Flags for eval_variable().
+#define EVAL_VAR_VERBOSE	1   // may give error message
+#define EVAL_VAR_NOAUTOLOAD	2   // do not use script autoloading
+#define EVAL_VAR_IMPORT		4   // may return special variable for import
+
 #endif // VIM__H
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -1765,7 +1765,7 @@ call_def_function(
 			goto failed;
 		    SOURCING_LNUM = iptr->isn_lnum;
 		    if (eval_variable(name, (int)STRLEN(name),
-				  STACK_TV_BOT(0), NULL, TRUE, FALSE) == FAIL)
+			      STACK_TV_BOT(0), NULL, EVAL_VAR_VERBOSE) == FAIL)
 			goto on_error;
 		    ++ectx.ec_stack.ga_len;
 		}
--- a/src/vim9script.c
+++ b/src/vim9script.c
@@ -257,7 +257,8 @@ find_exported(
 	char_u	    *name,
 	ufunc_T	    **ufunc,
 	type_T	    **type,
-	cctx_T	    *cctx)
+	cctx_T	    *cctx,
+	int	    verbose)
 {
     int		idx = -1;
     svar_T	*sv;
@@ -271,7 +272,8 @@ find_exported(
 	sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
 	if (!sv->sv_export)
 	{
-	    semsg(_(e_item_not_exported_in_script_str), name);
+	    if (verbose)
+		semsg(_(e_item_not_exported_in_script_str), name);
 	    return -1;
 	}
 	*type = sv->sv_type;
@@ -301,7 +303,8 @@ find_exported(
 
 	if (*ufunc == NULL)
 	{
-	    semsg(_(e_item_not_found_in_script_str), name);
+	    if (verbose)
+		semsg(_(e_item_not_found_in_script_str), name);
 	    return -1;
 	}
     }
@@ -532,7 +535,7 @@ handle_import(
 	    ufunc_T	*ufunc = NULL;
 	    type_T	*type;
 
-	    idx = find_exported(sid, name, &ufunc, &type, cctx);
+	    idx = find_exported(sid, name, &ufunc, &type, cctx, TRUE);
 
 	    if (idx < 0 && ufunc == NULL)
 		goto erret;