diff src/vim9script.c @ 26980:8796f1384750 v8.2.4019

patch 8.2.4019: Vim9: import mechanism is too complicated Commit: https://github.com/vim/vim/commit/d5f400c607182db6d4fbe2964471d796277f67e8 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Jan 6 21:10:28 2022 +0000 patch 8.2.4019: Vim9: import mechanism is too complicated Problem: Vim9: import mechanism is too complicated. Solution: Do not use the Javascript mechanism but a much simpler one.
author Bram Moolenaar <Bram@vim.org>
date Thu, 06 Jan 2022 22:15:04 +0100
parents 4e77f9961650
children bef1f0167251
line wrap: on
line diff
--- a/src/vim9script.c
+++ b/src/vim9script.c
@@ -363,121 +363,27 @@ handle_import(
 	void	    *cctx)
 {
     char_u	*arg = arg_start;
-    char_u	*cmd_end = NULL;
+    char_u	*nextarg;
+    int		getnext;
+    char_u	*expr_end;
     int		ret = FAIL;
+    char_u	*as_name = NULL;
     typval_T	tv;
     int		sid = -1;
     int		res;
-    int		mult = FALSE;
-    garray_T	names;
-    garray_T	as_names;
     long	start_lnum = SOURCING_LNUM;
 
-    tv.v_type = VAR_UNKNOWN;
-    ga_init2(&names, sizeof(char_u *), 10);
-    ga_init2(&as_names, sizeof(char_u *), 10);
-    if (*arg == '{')
-    {
-	// "import {item, item} from ..."
-	mult = TRUE;
-	arg = skipwhite_and_linebreak(arg + 1, evalarg);
-    }
-
-    for (;;)
-    {
-	char_u	    *p = arg;
-	int	    had_comma = FALSE;
-	char_u	    *as_name = NULL;
-
-	// accept "*" or "Name"
-	if (!mult && arg[0] == '*' && IS_WHITE_OR_NUL(arg[1]))
-	    ++arg;
-	else
-	    while (eval_isnamec(*arg))
-		++arg;
-	if (p == arg)
-	    break;
-	if (ga_grow(&names, 1) == FAIL || ga_grow(&as_names, 1) == FAIL)
-	    goto erret;
-	((char_u **)names.ga_data)[names.ga_len] = vim_strnsave(p, arg - p);
-	++names.ga_len;
-
-	arg = skipwhite_and_linebreak(arg, evalarg);
-	if (STRNCMP("as", arg, 2) == 0 && IS_WHITE_OR_NUL(arg[2]))
-	{
-	    // Skip over "as Name "; no line break allowed after "as".
-	    // Do not allow for ':' and '#'.
-	    arg = skipwhite(arg + 2);
-	    p = arg;
-	    if (eval_isnamec1(*arg))
-		while (ASCII_ISALNUM(*arg) || *arg == '_')
-		    ++arg;
-	    if (p == arg || !(IS_WHITE_OR_NUL(*arg)
-				  || (mult && (*arg == ',' || *arg == '}'))))
-	    {
-		semsg(_(e_syntax_error_in_import_str), p);
-		goto erret;
-	    }
-	    if (check_defined(p, arg - p, cctx, FALSE) == FAIL)
-		goto erret;
-	    as_name = vim_strnsave(p, arg - p);
-	    arg = skipwhite_and_linebreak(arg, evalarg);
-	}
-	else if (*arg_start == '*')
-	{
-	    emsg(_(e_missing_as_after_star));
-	    goto erret;
-	}
-	// without "as Name" the as_names entry is NULL
-	((char_u **)as_names.ga_data)[as_names.ga_len] = as_name;
-	++as_names.ga_len;
-
-	if (!mult)
-	    break;
-	if (*arg == ',')
-	{
-	    had_comma = TRUE;
-	    ++arg;
-	}
-	arg = skipwhite_and_linebreak(arg, evalarg);
-	if (*arg == '}')
-	{
-	    ++arg;
-	    break;
-	}
-	if (!had_comma)
-	{
-	    emsg(_(e_missing_comma_in_import));
-	    goto erret;
-	}
-    }
-    arg = skipwhite_and_linebreak(arg, evalarg);
-
-    if (names.ga_len == 0)
-    {
-	semsg(_(e_syntax_error_in_import_str), arg_start);
-	goto erret;
-    }
-
-    if (STRNCMP("from", arg, 4) != 0 || !IS_WHITE_OR_NUL(arg[4]))
-    {
-	emsg(_(e_missing_from));
-	goto erret;
-    }
-
     // The name of the file can be an expression, which must evaluate to a
     // string.
-    arg = skipwhite_and_linebreak(arg + 4, evalarg);
-    ret = eval0(arg, &tv, NULL, evalarg);
+    ret = eval0_retarg(arg, &tv, NULL, evalarg, &expr_end);
     if (ret == FAIL)
 	goto erret;
     if (tv.v_type != VAR_STRING
 		       || tv.vval.v_string == NULL || *tv.vval.v_string == NUL)
     {
-	emsg(_(e_invalid_string_after_from));
+	semsg(_(e_invalid_string_for_import_str), arg);
 	goto erret;
     }
-    cmd_end = arg;
 
     // Give error messages for the start of the line.
     SOURCING_LNUM = start_lnum;
@@ -532,12 +438,55 @@ handle_import(
 	goto erret;
     }
 
-    if (*arg_start == '*')
+    // Allow for the "as Name" to be in the next line.
+    nextarg = eval_next_non_blank(expr_end, evalarg, &getnext);
+    if (STRNCMP("as", nextarg, 2) == 0 && IS_WHITE_OR_NUL(nextarg[2]))
+    {
+	char_u *p;
+
+	if (getnext)
+	    arg = eval_next_line(evalarg);
+	else
+	    arg = nextarg;
+
+	// Skip over "as Name "; no line break allowed after "as".
+	// Do not allow for ':' and '#'.
+	arg = skipwhite(arg + 2);
+	p = arg;
+	if (eval_isnamec1(*arg))
+	    while (ASCII_ISALNUM(*arg) || *arg == '_')
+		++arg;
+	if (p == arg || !IS_WHITE_OR_NUL(*arg))
+	{
+	    semsg(_(e_syntax_error_in_import_str), p);
+	    goto erret;
+	}
+	as_name = vim_strnsave(p, arg - p);
+	arg = skipwhite(arg);
+    }
+    else
+    {
+	char_u *p = gettail(tv.vval.v_string);
+	char_u *end = (char_u *)strstr((char *)p, ".vim");
+
+	if (!ends_excmd2(arg_start, expr_end))
+	{
+	    semsg(_(e_trailing_characters_str), expr_end);
+	    goto erret;
+	}
+
+	if (end == NULL)
+	{
+	    semsg(_(e_imported_script_must_end_in_dot_vim_str), p);
+	    goto erret;
+	}
+	as_name = vim_strnsave(p, end - p);
+    }
+
+    if (as_name != NULL)
     {
 	imported_T  *imported;
-	char_u	    *as_name = ((char_u **)as_names.ga_data)[0];
 
-	// "import * as That"
 	imported = find_imported(as_name, STRLEN(as_name), cctx);
 	if (imported != NULL && imported->imp_sid == sid)
 	{
@@ -550,107 +499,27 @@ handle_import(
 		goto erret;
 	    }
 	}
+	else if (check_defined(as_name, STRLEN(as_name), cctx, FALSE) == FAIL)
+	    goto erret;
 
 	imported = new_imported(gap != NULL ? gap
 					: &SCRIPT_ITEM(import_sid)->sn_imports);
 	if (imported == NULL)
 	    goto erret;
 	imported->imp_name = as_name;
-	((char_u **)as_names.ga_data)[0] = NULL;
+	as_name = NULL;
 	imported->imp_sid = sid;
-	imported->imp_flags = IMP_FLAGS_STAR;
     }
-    else
-    {
-	int i;
-
-	arg = arg_start;
-	if (*arg == '{')
-	    arg = skipwhite(arg + 1);
-	for (i = 0; i < names.ga_len; ++i)
-	{
-	    char_u	*name = ((char_u **)names.ga_data)[i];
-	    char_u	*as_name = ((char_u **)as_names.ga_data)[i];
-	    size_t	len = STRLEN(name);
-	    int		idx;
-	    imported_T	*imported;
-	    ufunc_T	*ufunc = NULL;
-	    type_T	*type;
-
-	    idx = find_exported(sid, name, &ufunc, &type, cctx, TRUE);
-
-	    if (idx < 0 && ufunc == NULL)
-		goto erret;
 
-	    // If already imported with the same properties and the
-	    // IMP_FLAGS_RELOAD set then we keep that entry.  Otherwise create
-	    // a new one (and give an error for an existing import).
-	    imported = find_imported(name, len, cctx);
-	    if (imported != NULL
-		    && (imported->imp_flags & IMP_FLAGS_RELOAD)
-		    && imported->imp_sid == sid
-		    && (idx >= 0
-			? (equal_type(imported->imp_type, type, 0)
-			    && imported->imp_var_vals_idx == idx)
-			: (equal_type(imported->imp_type, ufunc->uf_func_type,
-							     ETYPE_ARG_UNKNOWN)
-			    && STRCMP(imported->imp_funcname,
-							ufunc->uf_name) == 0)))
-	    {
-		imported->imp_flags &= ~IMP_FLAGS_RELOAD;
-	    }
-	    else
-	    {
-		if (as_name == NULL
-			      && check_defined(name, len, cctx, FALSE) == FAIL)
-		    goto erret;
-
-		imported = new_imported(gap != NULL ? gap
-				       : &SCRIPT_ITEM(import_sid)->sn_imports);
-		if (imported == NULL)
-		    goto erret;
-
-		if (as_name == NULL)
-		{
-		    imported->imp_name = name;
-		    ((char_u **)names.ga_data)[i] = NULL;
-		}
-		else
-		{
-		    // "import This as That ..."
-		    imported->imp_name = as_name;
-		    ((char_u **)as_names.ga_data)[i] = NULL;
-		}
-		imported->imp_sid = sid;
-		if (idx >= 0)
-		{
-		    imported->imp_type = type;
-		    imported->imp_var_vals_idx = idx;
-		}
-		else
-		{
-		    imported->imp_type = ufunc->uf_func_type;
-		    imported->imp_funcname = ufunc->uf_name;
-		}
-	    }
-	}
-    }
 erret:
     clear_tv(&tv);
-    ga_clear_strings(&names);
-    ga_clear_strings(&as_names);
-    return cmd_end;
+    vim_free(as_name);
+    return arg;
 }
 
 /*
- * ":import Item from 'filename'"
- * ":import Item as Alias from 'filename'"
- * ":import {Item} from 'filename'".
- * ":import {Item as Alias} from 'filename'"
- * ":import {Item, Item} from 'filename'"
- * ":import {Item, Item as Alias} from 'filename'"
- *
- * ":import * as Name from 'filename'"
+ * ":import 'filename'"
+ * ":import 'filename' as Name"
  */
     void
 ex_import(exarg_T *eap)
@@ -673,7 +542,7 @@ ex_import(exarg_T *eap)
 }
 
 /*
- * Find an exported item in "sid" matching the name at "*argp".
+ * Find an exported item in "sid" matching "name".
  * When it is a variable return the index.
  * When it is a user function return "*ufunc".
  * When not found returns -1 and "*ufunc" is NULL.
@@ -807,7 +676,7 @@ vim9_declare_scriptvar(exarg_T *eap, cha
 	init_tv.v_type = VAR_NUMBER;
     else
 	init_tv.v_type = type->tt_type;
-    set_var_const(name, type, &init_tv, FALSE, 0, 0);
+    set_var_const(name, 0, type, &init_tv, FALSE, 0, 0);
 
     vim_free(name);
     return p;
@@ -902,7 +771,7 @@ update_vim9_script_var(
     }
     else
     {
-	sv = find_typval_in_script(&di->di_tv);
+	sv = find_typval_in_script(&di->di_tv, 0);
     }
     if (sv != NULL)
     {
@@ -991,12 +860,13 @@ hide_script_var(scriptitem_T *si, int id
 
 /*
  * Find the script-local variable that links to "dest".
+ * If "sid" is zero use the current script.
  * Returns NULL if not found and give an internal error.
  */
     svar_T *
-find_typval_in_script(typval_T *dest)
+find_typval_in_script(typval_T *dest, scid_T sid)
 {
-    scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
+    scriptitem_T    *si = SCRIPT_ITEM(sid == 0 ? current_sctx.sc_sid : sid);
     int		    idx;
 
     if (si->sn_version != SCRIPT_VERSION_VIM9)