0
0
mirror of https://github.com/vim/vim.git synced 2025-08-31 20:53:42 -04:00

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.
This commit is contained in:
Bram Moolenaar 2022-01-06 21:10:28 +00:00
parent 18f4740f04
commit d5f400c607
16 changed files with 479 additions and 674 deletions

View File

@ -1432,24 +1432,27 @@ be exported. {not implemented yet: class, interface}
Import ~ Import ~
*:import* *:imp* *E1094* *:import* *:imp* *E1094*
The exported items can be imported individually in another Vim9 script: > The exported items can be imported in another Vim9 script: >
import EXPORTED_CONST from "thatscript.vim" import "myscript.vim"
import MyClass from "myclass.vim"
To import multiple items at the same time: > This makes each item available as "myscript.item".
import {someValue, MyClass} from "thatscript.vim"
In case the name is ambiguous, another name can be specified: > In case the name is long or ambiguous, another name can be specified: >
import MyClass as ThatClass from "myclass.vim" import "thatscript.vim" as That
import {someValue, MyClass as ThatClass} from "myclass.vim"
To import all exported items under a specific identifier: >
import * as That from 'thatscript.vim'
Then you can use "That.EXPORTED_CONST", "That.someValue", etc. You are free Then you can use "That.EXPORTED_CONST", "That.someValue", etc. You are free
to choose the name "That", but it is highly recommended to use the name of the to choose the name "That". Use something that will be recognized as referring
script file to avoid confusion. Also avoid command names, because the name to the imported script. Avoid command names, because the name will shadow
will shadow them. them.
In case the dot in the name is unwanted, a local reference can be made: >
var ThatFunc = That.LongFuncName
This also works for constants: >
cost MAXLEN = That.MAX_LEN_OF_NAME
This does not work for variables, you could use a setter function and make a
local reference for it.
`:import` can also be used in legacy Vim script. The imported items still `:import` can also be used in legacy Vim script. The imported items still
become script-local, even when the "s:" prefix is not given. become script-local, even when the "s:" prefix is not given.
@ -1470,6 +1473,9 @@ The script name after `import` can be:
Once a vim9 script file has been imported, the result is cached and used the Once a vim9 script file has been imported, the result is cached and used the
next time the same script is imported. It will not be read again. next time the same script is imported. It will not be read again.
It is not allowed to import the same script twice, also when using two
different "as" names.
*:import-cycle* *:import-cycle*
The `import` commands are executed when encountered. If that script (directly The `import` commands are executed when encountered. If that script (directly
or indirectly) imports the current script, then items defined after the or indirectly) imports the current script, then items defined after the
@ -1491,9 +1497,9 @@ actually needed. A recommended mechanism:
2. In the autoload script do the actual work. You can import items from 2. In the autoload script do the actual work. You can import items from
other files to split up functionality in appropriate pieces. > other files to split up functionality in appropriate pieces. >
vim9script vim9script
import FilterFunc from "../import/someother.vim" import "../import/someother.vim" as other
def searchfor#Stuff(arg: string) def searchfor#Stuff(arg: string)
var filtered = FilterFunc(arg) var filtered = other.FilterFunc(arg)
... ...
< This goes in .../autoload/searchfor.vim. "searchfor" in the file name < This goes in .../autoload/searchfor.vim. "searchfor" in the file name
must be exactly the same as the prefix for the function name, that is how must be exactly the same as the prefix for the function name, that is how

View File

@ -2500,8 +2500,8 @@ EXTERN char e_white_space_required_after_str_str[]
INIT(= N_("E1069: White space required after '%s': %s")); INIT(= N_("E1069: White space required after '%s': %s"));
EXTERN char e_missing_from[] EXTERN char e_missing_from[]
INIT(= N_("E1070: Missing \"from\"")); INIT(= N_("E1070: Missing \"from\""));
EXTERN char e_invalid_string_after_from[] EXTERN char e_invalid_string_for_import_str[]
INIT(= N_("E1071: Invalid string after \"from\"")); INIT(= N_("E1071: Invalid string for :import: %s"));
EXTERN char e_cannot_compare_str_with_str[] EXTERN char e_cannot_compare_str_with_str[]
INIT(= N_("E1072: Cannot compare %s with %s")); INIT(= N_("E1072: Cannot compare %s with %s"));
EXTERN char e_name_already_defined_str[] EXTERN char e_name_already_defined_str[]
@ -2839,8 +2839,8 @@ EXTERN char e_legacy_must_be_followed_by_command[]
INIT(= N_("E1234: legacy must be followed by a command")); INIT(= N_("E1234: legacy must be followed by a command"));
EXTERN char e_function_reference_is_not_set[] EXTERN char e_function_reference_is_not_set[]
INIT(= N_("E1235: Function reference is not set")); INIT(= N_("E1235: Function reference is not set"));
EXTERN char e_cannot_use_str_itself_it_is_imported_with_star[] EXTERN char e_cannot_use_str_itself_it_is_imported[]
INIT(= N_("E1236: Cannot use %s itself, it is imported with '*'")); INIT(= N_("E1236: Cannot use %s itself, it is imported"));
EXTERN char e_no_such_user_defined_command_in_current_buffer_str[] EXTERN char e_no_such_user_defined_command_in_current_buffer_str[]
INIT(= N_("E1237: No such user-defined command in current buffer: %s")); INIT(= N_("E1237: No such user-defined command in current buffer: %s"));
EXTERN char e_blob_required_for_argument_nr[] EXTERN char e_blob_required_for_argument_nr[]
@ -2881,3 +2881,11 @@ EXTERN char e_cmd_mapping_must_end_with_cr[]
INIT(= N_("E1255: <Cmd> mapping must end with <CR>")); INIT(= N_("E1255: <Cmd> mapping must end with <CR>"));
EXTERN char e_string_or_function_required_for_argument_nr[] EXTERN char e_string_or_function_required_for_argument_nr[]
INIT(= N_("E1256: String or function required for argument %d")); INIT(= N_("E1256: String or function required for argument %d"));
EXTERN char e_imported_script_must_end_in_dot_vim_str[]
INIT(= N_("E1257: Imported script must end in .vim: %s"));
EXTERN char e_no_dot_after_imported_name_str[]
INIT(= N_("E1258: No '.' after imported name: %s"));
EXTERN char e_missing_name_after_imported_name_str[]
INIT(= N_("E1259: Missing name after imported name: %s"));
EXTERN char e_cannot_unlet_imported_item_str[]
INIT(= N_("E1260: Cannot unlet an imported item: %s"));

View File

@ -56,7 +56,6 @@ static int eval7_leader(typval_T *rettv, int numeric_only, char_u *start_leader,
static int free_unref_items(int copyID); static int free_unref_items(int copyID);
static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end); static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end);
static char_u *eval_next_line(evalarg_T *evalarg);
/* /*
* Return "n1" divided by "n2", taking care of dividing by zero. * Return "n1" divided by "n2", taking care of dividing by zero.
@ -922,9 +921,37 @@ get_lval(
} }
} }
} }
if (lp->ll_name == NULL)
return p;
if (*p == '.' && in_vim9script())
{
imported_T *import = find_imported(lp->ll_name, p - lp->ll_name, NULL);
if (import != NULL)
{
ufunc_T *ufunc;
type_T *type;
lp->ll_sid = import->imp_sid;
lp->ll_name = skipwhite(p + 1);
p = find_name_end(lp->ll_name, NULL, NULL, fne_flags);
lp->ll_name_end = p;
// check the item is exported
cc = *p;
*p = NUL;
if (find_exported(import->imp_sid, lp->ll_name, &ufunc, &type,
NULL, TRUE) == -1)
{
*p = cc;
return FAIL;
}
*p = cc;
}
}
// Without [idx] or .key we are done. // Without [idx] or .key we are done.
if ((*p != '[' && *p != '.') || lp->ll_name == NULL) if ((*p != '[' && *p != '.'))
return p; return p;
if (in_vim9script() && lval_root != NULL) if (in_vim9script() && lval_root != NULL)
@ -997,7 +1024,7 @@ get_lval(
&& lp->ll_tv == &v->di_tv && lp->ll_tv == &v->di_tv
&& ht != NULL && ht == get_script_local_ht()) && ht != NULL && ht == get_script_local_ht())
{ {
svar_T *sv = find_typval_in_script(lp->ll_tv); svar_T *sv = find_typval_in_script(lp->ll_tv, 0);
// Vim9 script local variable: get the type // Vim9 script local variable: get the type
if (sv != NULL) if (sv != NULL)
@ -1359,13 +1386,13 @@ set_var_lval(
// handle +=, -=, *=, /=, %= and .= // handle +=, -=, *=, /=, %= and .=
di = NULL; di = NULL;
if (eval_variable(lp->ll_name, (int)STRLEN(lp->ll_name), if (eval_variable(lp->ll_name, (int)STRLEN(lp->ll_name),
&tv, &di, EVAL_VAR_VERBOSE) == OK) lp->ll_sid, &tv, &di, EVAL_VAR_VERBOSE) == OK)
{ {
if ((di == NULL if ((di == NULL
|| (!var_check_ro(di->di_flags, lp->ll_name, FALSE) || (!var_check_ro(di->di_flags, lp->ll_name, FALSE)
&& !tv_check_lock(&di->di_tv, lp->ll_name, FALSE))) && !tv_check_lock(&di->di_tv, lp->ll_name, FALSE)))
&& tv_op(&tv, rettv, op) == OK) && tv_op(&tv, rettv, op) == OK)
set_var_const(lp->ll_name, NULL, &tv, FALSE, set_var_const(lp->ll_name, lp->ll_sid, NULL, &tv, FALSE,
ASSIGN_NO_DECL, 0); ASSIGN_NO_DECL, 0);
clear_tv(&tv); clear_tv(&tv);
} }
@ -1375,7 +1402,7 @@ set_var_lval(
if (lp->ll_type != NULL && check_typval_arg_type(lp->ll_type, rettv, if (lp->ll_type != NULL && check_typval_arg_type(lp->ll_type, rettv,
NULL, 0) == FAIL) NULL, 0) == FAIL)
return; return;
set_var_const(lp->ll_name, lp->ll_type, rettv, copy, set_var_const(lp->ll_name, lp->ll_sid, lp->ll_type, rettv, copy,
flags, var_idx); flags, var_idx);
} }
*endp = cc; *endp = cc;
@ -1389,7 +1416,7 @@ set_var_lval(
if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
&& (flags & ASSIGN_FOR_LOOP) == 0) && (flags & ASSIGN_FOR_LOOP) == 0)
{ {
emsg(_("E996: Cannot lock a range")); emsg(_(e_cannot_lock_range));
return; return;
} }
@ -1404,7 +1431,7 @@ set_var_lval(
if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
&& (flags & ASSIGN_FOR_LOOP) == 0) && (flags & ASSIGN_FOR_LOOP) == 0)
{ {
emsg(_("E996: Cannot lock a list or dict")); emsg(_(e_cannot_lock_list_or_dict));
return; return;
} }
@ -2089,7 +2116,7 @@ getline_peek_skip_comments(evalarg_T *evalarg)
* FALSE. * FALSE.
* "arg" must point somewhere inside a line, not at the start. * "arg" must point somewhere inside a line, not at the start.
*/ */
static char_u * char_u *
eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext) eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext)
{ {
char_u *p = skipwhite(arg); char_u *p = skipwhite(arg);
@ -2120,7 +2147,7 @@ eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext)
* To be called after eval_next_non_blank() sets "getnext" to TRUE. * To be called after eval_next_non_blank() sets "getnext" to TRUE.
* Only called for Vim9 script. * Only called for Vim9 script.
*/ */
static char_u * char_u *
eval_next_line(evalarg_T *evalarg) eval_next_line(evalarg_T *evalarg)
{ {
garray_T *gap = &evalarg->eval_ga; garray_T *gap = &evalarg->eval_ga;
@ -2235,6 +2262,21 @@ eval0(
typval_T *rettv, typval_T *rettv,
exarg_T *eap, exarg_T *eap,
evalarg_T *evalarg) evalarg_T *evalarg)
{
return eval0_retarg(arg, rettv, eap, evalarg, NULL);
}
/*
* Like eval0() but when "retarg" is not NULL store the pointer to after the
* expression and don't check what comes after the expression.
*/
int
eval0_retarg(
char_u *arg,
typval_T *rettv,
exarg_T *eap,
evalarg_T *evalarg,
char_u **retarg)
{ {
int ret; int ret;
char_u *p; char_u *p;
@ -2242,7 +2284,7 @@ eval0(
int did_emsg_before = did_emsg; int did_emsg_before = did_emsg;
int called_emsg_before = called_emsg; int called_emsg_before = called_emsg;
int flags = evalarg == NULL ? 0 : evalarg->eval_flags; int flags = evalarg == NULL ? 0 : evalarg->eval_flags;
int check_for_end = TRUE; int check_for_end = retarg == NULL;
int end_error = FALSE; int end_error = FALSE;
p = skipwhite(arg); p = skipwhite(arg);
@ -2253,7 +2295,7 @@ eval0(
// In Vim9 script a command block is not split at NL characters for // In Vim9 script a command block is not split at NL characters for
// commands using an expression argument. Skip over a '#' comment to check // commands using an expression argument. Skip over a '#' comment to check
// for a following NL. Require white space before the '#'. // for a following NL. Require white space before the '#'.
if (in_vim9script() && p > expr_end) if (in_vim9script() && p > expr_end && retarg == NULL)
while (*p == '#') while (*p == '#')
{ {
char_u *nl = vim_strchr(p, NL); char_u *nl = vim_strchr(p, NL);
@ -2298,7 +2340,9 @@ eval0(
return FAIL; return FAIL;
} }
if (check_for_end && eap != NULL) if (retarg != NULL)
*retarg = p;
else if (check_for_end && eap != NULL)
set_nextcmd(eap, p); set_nextcmd(eap, p);
return ret; return ret;
@ -3669,7 +3713,7 @@ eval7(
ret = OK; ret = OK;
} }
else else
ret = eval_variable(s, len, rettv, NULL, ret = eval_variable(s, len, 0, rettv, NULL,
EVAL_VAR_VERBOSE + EVAL_VAR_IMPORT); EVAL_VAR_VERBOSE + EVAL_VAR_IMPORT);
} }
else else
@ -5887,7 +5931,7 @@ handle_subscript(
ufunc_T *ufunc; ufunc_T *ufunc;
type_T *type; type_T *type;
// Found script from "import * as {name}", script item name must // Found script from "import {name} as name", script item name must
// follow. // follow.
if (**arg != '.') if (**arg != '.')
{ {
@ -5934,6 +5978,7 @@ handle_subscript(
rettv->v_type = VAR_FUNC; rettv->v_type = VAR_FUNC;
rettv->vval.v_string = vim_strsave(ufunc->uf_name); rettv->vval.v_string = vim_strsave(ufunc->uf_name);
} }
continue;
} }
if ((**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC if ((**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC

View File

@ -1232,7 +1232,7 @@ list_arg_vars(exarg_T *eap, char_u *arg, int *first)
arg = skipwhite(arg); arg = skipwhite(arg);
if (tofree != NULL) if (tofree != NULL)
name = tofree; name = tofree;
if (eval_variable(name, len, &tv, NULL, if (eval_variable(name, len, 0, &tv, NULL,
EVAL_VAR_VERBOSE) == FAIL) EVAL_VAR_VERBOSE) == FAIL)
error = TRUE; error = TRUE;
else else
@ -2645,6 +2645,7 @@ set_cmdarg(exarg_T *eap, char_u *oldarg)
eval_variable( eval_variable(
char_u *name, char_u *name,
int len, // length of "name" int len, // length of "name"
scid_T sid, // script ID for imported item or zero
typval_T *rettv, // NULL when only checking existence typval_T *rettv, // NULL when only checking existence
dictitem_T **dip, // non-NULL when typval's dict item is needed dictitem_T **dip, // non-NULL when typval's dict item is needed
int flags) // EVAL_VAR_ flags int flags) // EVAL_VAR_ flags
@ -2678,48 +2679,50 @@ eval_variable(
if (tv == NULL && (in_vim9script() || STRNCMP(name, "s:", 2) == 0)) if (tv == NULL && (in_vim9script() || STRNCMP(name, "s:", 2) == 0))
{ {
imported_T *import; imported_T *import = NULL;
char_u *p = STRNCMP(name, "s:", 2) == 0 ? name + 2 : name; char_u *p = STRNCMP(name, "s:", 2) == 0 ? name + 2 : name;
import = find_imported(p, 0, NULL); if (sid == 0)
import = find_imported(p, 0, NULL);
// imported variable from another script // imported variable from another script
if (import != NULL) if (import != NULL || sid != 0)
{ {
if (import->imp_funcname != NULL) if ((flags & EVAL_VAR_IMPORT) == 0)
{ {
found = TRUE; if (sid != 0 && SCRIPT_ID_VALID(sid))
if (rettv != NULL)
{ {
rettv->v_type = VAR_FUNC; ht = &SCRIPT_VARS(sid);
rettv->vval.v_string = vim_strsave(import->imp_funcname); if (ht != NULL)
{
dictitem_T *v = find_var_in_ht(ht, 0, name,
flags & EVAL_VAR_NOAUTOLOAD);
if (v != NULL)
{
tv = &v->di_tv;
if (dip != NULL)
*dip = v;
}
else
ht = NULL;
}
} }
} else
else if (import->imp_flags & IMP_FLAGS_STAR)
{
if ((flags & EVAL_VAR_IMPORT) == 0)
{ {
if (flags & EVAL_VAR_VERBOSE) if (flags & EVAL_VAR_VERBOSE)
emsg(_(e_import_as_name_not_supported_here)); emsg(_(e_import_as_name_not_supported_here));
ret = FAIL; ret = FAIL;
} }
else
{
if (rettv != NULL)
{
rettv->v_type = VAR_ANY;
rettv->vval.v_number = import->imp_sid;
}
found = TRUE;
}
} }
else else
{ {
scriptitem_T *si = SCRIPT_ITEM(import->imp_sid); if (rettv != NULL)
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) {
+ import->imp_var_vals_idx; rettv->v_type = VAR_ANY;
tv = sv->sv_tv; rettv->vval.v_number = sid != 0 ? sid : import->imp_sid;
type = sv->sv_type; }
found = TRUE;
} }
} }
else if (in_vim9script() && (flags & EVAL_VAR_NO_FUNC) == 0) else if (in_vim9script() && (flags & EVAL_VAR_NO_FUNC) == 0)
@ -2760,7 +2763,7 @@ eval_variable(
if (ht != NULL && ht == get_script_local_ht() if (ht != NULL && ht == get_script_local_ht()
&& tv != &SCRIPT_SV(current_sctx.sc_sid)->sv_var.di_tv) && tv != &SCRIPT_SV(current_sctx.sc_sid)->sv_var.di_tv)
{ {
svar_T *sv = find_typval_in_script(tv); svar_T *sv = find_typval_in_script(tv, 0);
if (sv != NULL) if (sv != NULL)
type = sv->sv_type; type = sv->sv_type;
@ -3278,17 +3281,19 @@ set_var(
typval_T *tv, typval_T *tv,
int copy) // make copy of value in "tv" int copy) // make copy of value in "tv"
{ {
set_var_const(name, NULL, tv, copy, ASSIGN_DECL, 0); set_var_const(name, 0, NULL, tv, copy, ASSIGN_DECL, 0);
} }
/* /*
* Set variable "name" to value in "tv". * Set variable "name" to value in "tv".
* When "sid" is non-zero "name" is in the script with this ID.
* If the variable already exists and "is_const" is FALSE the value is updated. * If the variable already exists and "is_const" is FALSE the value is updated.
* Otherwise the variable is created. * Otherwise the variable is created.
*/ */
void void
set_var_const( set_var_const(
char_u *name, char_u *name,
scid_T sid,
type_T *type_arg, type_T *type_arg,
typval_T *tv_arg, typval_T *tv_arg,
int copy, // make copy of value in "tv" int copy, // make copy of value in "tv"
@ -3301,20 +3306,27 @@ set_var_const(
dictitem_T *di; dictitem_T *di;
typval_T *dest_tv = NULL; typval_T *dest_tv = NULL;
char_u *varname; char_u *varname;
hashtab_T *ht; hashtab_T *ht = NULL;
int is_script_local; int is_script_local;
int vim9script = in_vim9script(); int vim9script = in_vim9script();
int var_in_vim9script; int var_in_vim9script;
int flags = flags_arg; int flags = flags_arg;
int free_tv_arg = !copy; // free tv_arg if not used int free_tv_arg = !copy; // free tv_arg if not used
ht = find_var_ht(name, &varname); if (sid != 0)
{
if (SCRIPT_ID_VALID(sid))
ht = &SCRIPT_VARS(sid);
varname = name;
}
else
ht = find_var_ht(name, &varname);
if (ht == NULL || *varname == NUL) if (ht == NULL || *varname == NUL)
{ {
semsg(_(e_illegal_variable_name_str), name); semsg(_(e_illegal_variable_name_str), name);
goto failed; goto failed;
} }
is_script_local = ht == get_script_local_ht(); is_script_local = ht == get_script_local_ht() || sid != 0;
if (vim9script if (vim9script
&& !is_script_local && !is_script_local
@ -3347,33 +3359,14 @@ set_var_const(
if (import != NULL) if (import != NULL)
{ {
scriptitem_T *si = SCRIPT_ITEM(import->imp_sid); // imported name space cannot be used
svar_T *sv;
where_T where = WHERE_INIT;
// imported variable from another script
if ((flags & ASSIGN_NO_DECL) == 0) if ((flags & ASSIGN_NO_DECL) == 0)
{ {
semsg(_(e_redefining_imported_item_str), name); semsg(_(e_redefining_imported_item_str), name);
goto failed; goto failed;
} }
if (import->imp_flags & IMP_FLAGS_STAR) semsg(_(e_cannot_use_str_itself_it_is_imported), name);
{ goto failed;
semsg(_(e_cannot_use_str_itself_it_is_imported_with_star),
name);
goto failed;
}
sv = ((svar_T *)si->sn_var_vals.ga_data) + import->imp_var_vals_idx;
where.wt_variable = TRUE;
if (check_typval_type(sv->sv_type, tv, where) == FAIL
|| value_check_lock(sv->sv_tv->v_lock, name, FALSE))
{
goto failed;
}
dest_tv = sv->sv_tv;
clear_tv(dest_tv);
} }
} }
@ -3419,7 +3412,7 @@ set_var_const(
if (var_in_vim9script && (flags & ASSIGN_FOR_LOOP) == 0) if (var_in_vim9script && (flags & ASSIGN_FOR_LOOP) == 0)
{ {
where_T where = WHERE_INIT; where_T where = WHERE_INIT;
svar_T *sv = find_typval_in_script(&di->di_tv); svar_T *sv = find_typval_in_script(&di->di_tv, sid);
if (sv != NULL) if (sv != NULL)
{ {
@ -3956,7 +3949,7 @@ var_exists(char_u *var)
{ {
if (tofree != NULL) if (tofree != NULL)
name = tofree; name = tofree;
n = (eval_variable(name, len, &tv, NULL, n = (eval_variable(name, len, 0, &tv, NULL,
EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT) == OK); EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT) == OK);
if (n) if (n)
{ {

View File

@ -33,10 +33,13 @@ int next_for_item(void *fi_void, char_u *arg);
void free_for_info(void *fi_void); void free_for_info(void *fi_void);
void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx); void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx);
int pattern_match(char_u *pat, char_u *text, int ic); int pattern_match(char_u *pat, char_u *text, int ic);
char_u *eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext);
char_u *eval_next_line(evalarg_T *evalarg);
char_u *skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg); char_u *skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg);
void init_evalarg(evalarg_T *evalarg); void init_evalarg(evalarg_T *evalarg);
void clear_evalarg(evalarg_T *evalarg, exarg_T *eap); void clear_evalarg(evalarg_T *evalarg, exarg_T *eap);
int eval0(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T *evalarg); int eval0(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T *evalarg);
int eval0_retarg(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T *evalarg, char_u **retarg);
int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg); int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
void eval_addblob(typval_T *tv1, typval_T *tv2); void eval_addblob(typval_T *tv1, typval_T *tv2);
int eval_addlist(typval_T *tv1, typval_T *tv2); int eval_addlist(typval_T *tv1, typval_T *tv2);

View File

@ -57,7 +57,7 @@ void set_reg_var(int c);
char_u *v_exception(char_u *oldval); char_u *v_exception(char_u *oldval);
char_u *v_throwpoint(char_u *oldval); char_u *v_throwpoint(char_u *oldval);
char_u *set_cmdarg(exarg_T *eap, char_u *oldarg); 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 flags); int eval_variable(char_u *name, int len, scid_T sid, typval_T *rettv, dictitem_T **dip, int flags);
void check_vars(char_u *name, int len); 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(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); dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
@ -72,7 +72,7 @@ void vars_clear(hashtab_T *ht);
void vars_clear_ext(hashtab_T *ht, int free_val); void vars_clear_ext(hashtab_T *ht, int free_val);
void delete_var(hashtab_T *ht, hashitem_T *hi); void delete_var(hashtab_T *ht, hashitem_T *hi);
void set_var(char_u *name, typval_T *tv, int copy); void set_var(char_u *name, typval_T *tv, int copy);
void set_var_const(char_u *name, type_T *type_arg, typval_T *tv_arg, int copy, int flags_arg, int var_idx); void set_var_const(char_u *name, scid_T sid, type_T *type_arg, typval_T *tv_arg, int copy, int flags_arg, int var_idx);
int var_check_permission(dictitem_T *di, char_u *name); int var_check_permission(dictitem_T *di, char_u *name);
int var_check_ro(int flags, char_u *name, int use_gettext); int var_check_ro(int flags, char_u *name, int use_gettext);
int var_check_lock(int flags, char_u *name, int use_gettext); int var_check_lock(int flags, char_u *name, int use_gettext);

View File

@ -15,7 +15,7 @@ int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T
char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg); 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, int do_member); void update_vim9_script_var(int create, dictitem_T *di, int flags, typval_T *tv, type_T **type, int do_member);
void hide_script_var(scriptitem_T *si, int idx, int func_defined); void hide_script_var(scriptitem_T *si, int idx, int func_defined);
svar_T *find_typval_in_script(typval_T *dest); svar_T *find_typval_in_script(typval_T *dest, scid_T sid);
int check_script_var_type(svar_T *sv, typval_T *value, char_u *name, where_T where); int check_script_var_type(svar_T *sv, typval_T *value, char_u *name, where_T where);
int check_reserved_name(char_u *name); int check_reserved_name(char_u *name);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@ -1822,19 +1822,10 @@ struct svar_S {
typedef struct { typedef struct {
char_u *imp_name; // name imported as (allocated) char_u *imp_name; // name imported as (allocated)
int imp_sid; // script ID of "from" scid_T imp_sid; // script ID of "from"
int imp_flags; // IMP_FLAGS_ values int imp_flags; // IMP_FLAGS_ values
// for a variable
type_T *imp_type;
int imp_var_vals_idx; // index in sn_var_vals of "from"
// for a function
char_u *imp_funcname; // user func name (NOT allocated)
} imported_T; } imported_T;
#define IMP_FLAGS_STAR 1 // using "import * as Name"
#define IMP_FLAGS_RELOAD 2 // script reloaded, OK to redefine #define IMP_FLAGS_RELOAD 2 // script reloaded, OK to redefine
/* /*
@ -4264,6 +4255,10 @@ typedef struct lval_S
char_u *ll_name_end; // end of variable name (can be NULL) char_u *ll_name_end; // end of variable name (can be NULL)
type_T *ll_type; // type of variable (can be NULL) type_T *ll_type; // type of variable (can be NULL)
char_u *ll_exp_name; // NULL or expanded name in allocated memory. char_u *ll_exp_name; // NULL or expanded name in allocated memory.
scid_T ll_sid; // for an imported item: the script ID it was
// imported from; zero otherwise
typval_T *ll_tv; // Typeval of item being used. If "newkey" typval_T *ll_tv; // Typeval of item being used. If "newkey"
// isn't NULL it's the Dict to which to add // isn't NULL it's the Dict to which to add
// the item. // the item.

View File

@ -2109,13 +2109,13 @@ def Test_unlet()
writefile(['vim9script', 'export var svar = 1234'], 'XunletExport.vim') writefile(['vim9script', 'export var svar = 1234'], 'XunletExport.vim')
var lines =<< trim END var lines =<< trim END
vim9script vim9script
import svar from './XunletExport.vim' import './XunletExport.vim' as exp
def UnletSvar() def UnletSvar()
unlet svar unlet exp.svar
enddef enddef
defcompile defcompile
END END
CheckScriptFailure(lines, 'E1081:', 1) CheckScriptFailure(lines, 'E1260:', 1)
delete('XunletExport.vim') delete('XunletExport.vim')
$ENVVAR = 'foobar' $ENVVAR = 'foobar'

View File

@ -1172,47 +1172,43 @@ def Undo_export_script_lines()
enddef enddef
def Test_vim9_import_export() def Test_vim9_import_export()
writefile(s:export_script_lines, 'Xexport.vim')
var import_script_lines =<< trim END var import_script_lines =<< trim END
vim9script vim9script
import {exported, Exported, ExportedValue} from './Xexport.vim' var dir = './'
g:exported1 = exported var ext = ".vim"
exported += 3 import dir .. 'Xexport' .. ext as expo
g:exported2 = exported
g:exported3 = ExportedValue()
import ExportedInc from './Xexport.vim' g:exported1 = expo.exported
ExportedInc() expo.exported += 3
g:exported_i1 = exported g:exported2 = expo.exported
g:exported_i2 = ExportedValue() g:exported3 = expo.ExportedValue()
exported = 11 expo.ExportedInc()
g:exported_s1 = exported g:exported_i1 = expo.exported
g:exported_s2 = ExportedValue() g:exported_i2 = expo.ExportedValue()
g:imported_func = Exported() expo.exported = 11
g:exported_s1 = expo.exported
g:exported_s2 = expo.ExportedValue()
g:imported_func = expo.Exported()
def GetExported(): string def GetExported(): string
var local_dict = {ref: Exported} var local_dict = {ref: expo.Exported}
return local_dict.ref() return local_dict.ref()
enddef enddef
g:funcref_result = GetExported() g:funcref_result = GetExported()
var dir = './' g:imported_name = expo.exp_name
var ext = ".vim" expo.exp_name ..= ' Doe'
import {exp_name} from dir .. 'Xexport' .. ext g:imported_name_appended = expo.exp_name
g:imported_name = exp_name g:exported_later = expo.exported
exp_name ..= ' Doe'
g:imported_name_appended = exp_name
g:exported_later = exported
import theList from './Xexport.vim' expo.theList->add(2)
theList->add(2) assert_equal([1, 2], expo.theList)
assert_equal([1, 2], theList)
END END
writefile(import_script_lines, 'Ximport.vim') writefile(import_script_lines, 'Ximport.vim')
writefile(s:export_script_lines, 'Xexport.vim')
source Ximport.vim source Ximport.vim
assert_equal('bobbie', g:result) assert_equal('bobbie', g:result)
@ -1248,16 +1244,12 @@ def Test_vim9_import_export()
# similar, with line breaks # similar, with line breaks
var import_line_break_script_lines =<< trim END var import_line_break_script_lines =<< trim END
vim9script vim9script
import { import './Xexport.vim'
exported, as expo
Exported, g:exported = expo.exported
} expo.exported += 7
from g:exported_added = expo.exported
'./Xexport.vim' g:imported_func = expo.Exported()
g:exported = exported
exported += 7
g:exported_added = exported
g:imported_func = Exported()
END END
writefile(import_line_break_script_lines, 'Ximport_lbr.vim') writefile(import_line_break_script_lines, 'Ximport_lbr.vim')
source Ximport_lbr.vim source Ximport_lbr.vim
@ -1275,7 +1267,7 @@ def Test_vim9_import_export()
var import_star_as_lines =<< trim END var import_star_as_lines =<< trim END
vim9script vim9script
import * as Export from './Xexport.vim' import './Xexport.vim' as Export
def UseExport() def UseExport()
g:exported_def = Export.exported g:exported_def = Export.exported
enddef enddef
@ -1294,7 +1286,7 @@ def Test_vim9_import_export()
var import_star_as_lines_no_dot =<< trim END var import_star_as_lines_no_dot =<< trim END
vim9script vim9script
import * as Export from './Xexport.vim' import './Xexport.vim' as Export
def Func() def Func()
var dummy = 1 var dummy = 1
var imported = Export + dummy var imported = Export + dummy
@ -1306,7 +1298,7 @@ def Test_vim9_import_export()
var import_star_as_lines_dot_space =<< trim END var import_star_as_lines_dot_space =<< trim END
vim9script vim9script
import * as Export from './Xexport.vim' import './Xexport.vim' as Export
def Func() def Func()
var imported = Export . exported var imported = Export . exported
enddef enddef
@ -1317,8 +1309,8 @@ def Test_vim9_import_export()
var import_func_duplicated =<< trim END var import_func_duplicated =<< trim END
vim9script vim9script
import ExportedInc from './Xexport.vim' import './Xexport.vim' as expo
import ExportedInc from './Xexport.vim' import './Xexport.vim' as expo
ExportedInc() ExportedInc()
END END
@ -1327,9 +1319,9 @@ def Test_vim9_import_export()
var import_star_as_duplicated =<< trim END var import_star_as_duplicated =<< trim END
vim9script vim9script
import * as Export from './Xexport.vim' import './Xexport.vim' as Export
var some = 'other' var some = 'other'
import * as Export from './Xexport.vim' import './Xexport.vim' as Export
defcompile defcompile
END END
writefile(import_star_as_duplicated, 'Ximport.vim') writefile(import_star_as_duplicated, 'Ximport.vim')
@ -1337,7 +1329,7 @@ def Test_vim9_import_export()
var import_star_as_lines_script_no_dot =<< trim END var import_star_as_lines_script_no_dot =<< trim END
vim9script vim9script
import * as Export from './Xexport.vim' import './Xexport.vim' as Export
g:imported_script = Export exported g:imported_script = Export exported
END END
writefile(import_star_as_lines_script_no_dot, 'Ximport.vim') writefile(import_star_as_lines_script_no_dot, 'Ximport.vim')
@ -1345,7 +1337,7 @@ def Test_vim9_import_export()
var import_star_as_lines_script_space_after_dot =<< trim END var import_star_as_lines_script_space_after_dot =<< trim END
vim9script vim9script
import * as Export from './Xexport.vim' import './Xexport.vim' as Export
g:imported_script = Export. exported g:imported_script = Export. exported
END END
writefile(import_star_as_lines_script_space_after_dot, 'Ximport.vim') writefile(import_star_as_lines_script_space_after_dot, 'Ximport.vim')
@ -1353,7 +1345,7 @@ def Test_vim9_import_export()
var import_star_as_lines_missing_name =<< trim END var import_star_as_lines_missing_name =<< trim END
vim9script vim9script
import * as Export from './Xexport.vim' import './Xexport.vim' as Export
def Func() def Func()
var imported = Export. var imported = Export.
enddef enddef
@ -1364,10 +1356,8 @@ def Test_vim9_import_export()
var import_star_as_lbr_lines =<< trim END var import_star_as_lbr_lines =<< trim END
vim9script vim9script
import * import './Xexport.vim'
as Export as Export
from
'./Xexport.vim'
def UseExport() def UseExport()
g:exported = Export.exported g:exported = Export.exported
enddef enddef
@ -1378,44 +1368,20 @@ def Test_vim9_import_export()
assert_equal(18, g:exported) assert_equal(18, g:exported)
unlet g:exported unlet g:exported
var import_star_lines =<< trim END # try to use something that exists but is not exported
vim9script
import * from './Xexport.vim'
END
writefile(import_star_lines, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1045:', '', 2, 'Ximport.vim')
# try to import something that exists but is not exported
var import_not_exported_lines =<< trim END var import_not_exported_lines =<< trim END
vim9script vim9script
import name from './Xexport.vim' import './Xexport.vim' as expo
echo expo.name
END END
writefile(import_not_exported_lines, 'Ximport.vim') writefile(import_not_exported_lines, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1049:', '', 2, 'Ximport.vim') assert_fails('source Ximport.vim', 'E1049:', '', 3, 'Ximport.vim')
# try to import something that is already defined # try to import something that is already defined
var import_already_defined =<< trim END var import_already_defined =<< trim END
vim9script vim9script
var exported = 'something' var exported = 'something'
import exported from './Xexport.vim' import './Xexport.vim' as exported
END
writefile(import_already_defined, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1054:', '', 3, 'Ximport.vim')
# try to import something that is already defined
import_already_defined =<< trim END
vim9script
var exported = 'something'
import * as exported from './Xexport.vim'
END
writefile(import_already_defined, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1054:', '', 3, 'Ximport.vim')
# try to import something that is already defined
import_already_defined =<< trim END
vim9script
var exported = 'something'
import {exported} from './Xexport.vim'
END END
writefile(import_already_defined, 'Ximport.vim') writefile(import_already_defined, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1054:', '', 3, 'Ximport.vim') assert_fails('source Ximport.vim', 'E1054:', '', 3, 'Ximport.vim')
@ -1423,9 +1389,9 @@ def Test_vim9_import_export()
# try changing an imported const # try changing an imported const
var import_assign_to_const =<< trim END var import_assign_to_const =<< trim END
vim9script vim9script
import CONST from './Xexport.vim' import './Xexport.vim' as expo
def Assign() def Assign()
CONST = 987 expo.CONST = 987
enddef enddef
defcompile defcompile
END END
@ -1435,54 +1401,39 @@ def Test_vim9_import_export()
# try changing an imported final # try changing an imported final
var import_assign_to_final =<< trim END var import_assign_to_final =<< trim END
vim9script vim9script
import theList from './Xexport.vim' import './Xexport.vim' as expo
def Assign() def Assign()
theList = [2] expo.theList = [2]
enddef enddef
defcompile defcompile
END END
writefile(import_assign_to_final, 'Ximport.vim') writefile(import_assign_to_final, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E46:', '', 1, '_Assign') assert_fails('source Ximport.vim', 'E46:', '', 1, '_Assign')
# import a very long name, requires making a copy var import_no_as_lines =<< trim END
var import_long_name_lines =<< trim END
vim9script vim9script
import name012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 from './Xexport.vim' import './Xexport.vim' name
END END
writefile(import_long_name_lines, 'Ximport.vim') writefile(import_no_as_lines, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1048:', '', 2, 'Ximport.vim') assert_fails('source Ximport.vim', 'E488:', '', 2, 'Ximport.vim')
var import_no_from_lines =<< trim END
vim9script
import name './Xexport.vim'
END
writefile(import_no_from_lines, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1070:', '', 2, 'Ximport.vim')
var import_invalid_string_lines =<< trim END var import_invalid_string_lines =<< trim END
vim9script vim9script
import name from Xexport.vim import Xexport.vim
END END
writefile(import_invalid_string_lines, 'Ximport.vim') writefile(import_invalid_string_lines, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E121:', '', 2, 'Ximport.vim') assert_fails('source Ximport.vim', 'E121:', '', 2, 'Ximport.vim')
var import_wrong_name_lines =<< trim END var import_wrong_name_lines =<< trim END
vim9script vim9script
import name from './XnoExport.vim' import './XnoExport.vim'
END END
writefile(import_wrong_name_lines, 'Ximport.vim') writefile(import_wrong_name_lines, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1053:', '', 2, 'Ximport.vim') assert_fails('source Ximport.vim', 'E1053:', '', 2, 'Ximport.vim')
var import_missing_comma_lines =<< trim END
vim9script
import {exported name} from './Xexport.vim'
END
writefile(import_missing_comma_lines, 'Ximport3.vim')
assert_fails('source Ximport3.vim', 'E1046:', '', 2, 'Ximport3.vim')
var import_redefining_lines =<< trim END var import_redefining_lines =<< trim END
vim9script vim9script
import exported from './Xexport.vim' import './Xexport.vim' as exported
var exported = 5 var exported = 5
END END
writefile(import_redefining_lines, 'Ximport.vim') writefile(import_redefining_lines, 'Ximport.vim')
@ -1490,19 +1441,19 @@ def Test_vim9_import_export()
var import_assign_wrong_type_lines =<< trim END var import_assign_wrong_type_lines =<< trim END
vim9script vim9script
import exported from './Xexport.vim' import './Xexport.vim' as expo
exported = 'xxx' expo.exported = 'xxx'
END END
writefile(import_assign_wrong_type_lines, 'Ximport.vim') writefile(import_assign_wrong_type_lines, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1012: Type mismatch; expected number but got string', '', 3) assert_fails('source Ximport.vim', 'E1012: Type mismatch; expected number but got string', '', 3)
var import_assign_const_lines =<< trim END var import_assign_const_lines =<< trim END
vim9script vim9script
import CONST from './Xexport.vim' import './Xexport.vim' as expo
CONST = 4321 expo.CONST = 4321
END END
writefile(import_assign_const_lines, 'Ximport.vim') writefile(import_assign_const_lines, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E741: Value is locked: CONST', '', 3) assert_fails('source Ximport.vim', 'E46: Cannot change read-only variable "CONST"', '', 3)
delete('Ximport.vim') delete('Ximport.vim')
delete('Ximport3.vim') delete('Ximport3.vim')
@ -1541,12 +1492,12 @@ def Test_import_funcref()
lines =<< trim END lines =<< trim END
vim9script vim9script
import {G} from './Xlib.vim' import './Xlib.vim' as lib
const Foo = G() const Foo = lib.G()
assert_equal(42, Foo) assert_equal(42, Foo)
def DoTest() def DoTest()
const Goo = G() const Goo = lib.G()
assert_equal(42, Goo) assert_equal(42, Goo)
enddef enddef
DoTest() DoTest()
@ -1559,30 +1510,30 @@ enddef
def Test_import_star_fails() def Test_import_star_fails()
writefile([], 'Xfoo.vim') writefile([], 'Xfoo.vim')
var lines =<< trim END var lines =<< trim END
import * as foo from './Xfoo.vim' import './Xfoo.vim' as foo
foo = 'bar' foo = 'bar'
END END
CheckDefAndScriptFailure(lines, ['E1094:', 'E1236: Cannot use foo itself']) CheckDefAndScriptFailure(lines, ['E1094:', 'E1236: Cannot use foo itself'])
lines =<< trim END lines =<< trim END
vim9script vim9script
import * as foo from './Xfoo.vim' import './Xfoo.vim' as foo
var that = foo var that = foo
END END
CheckScriptFailure(lines, 'E1029: Expected ''.''') CheckScriptFailure(lines, 'E1029: Expected ''.''')
lines =<< trim END lines =<< trim END
vim9script vim9script
import * as 9foo from './Xfoo.vim' import './Xfoo.vim' as 9foo
END END
CheckScriptFailure(lines, 'E1047:') CheckScriptFailure(lines, 'E1047:')
lines =<< trim END lines =<< trim END
vim9script vim9script
import * as the#foo from './Xfoo.vim' import './Xfoo.vim' as the#foo
END END
CheckScriptFailure(lines, 'E1047:') CheckScriptFailure(lines, 'E1047:')
lines =<< trim END lines =<< trim END
vim9script vim9script
import * as g:foo from './Xfoo.vim' import './Xfoo.vim' as g:foo
END END
CheckScriptFailure(lines, 'E1047:') CheckScriptFailure(lines, 'E1047:')
@ -1597,53 +1548,13 @@ def Test_import_star_fails()
END END
writefile([], 'Xthat.vim') writefile([], 'Xthat.vim')
lines =<< trim END lines =<< trim END
import * as That from './Xthat.vim' import './Xthat.vim' as That
That() That()
END END
CheckDefAndScriptFailure(lines, ['E1094:', 'E1236: Cannot use That itself']) CheckDefAndScriptFailure(lines, ['E1094:', 'E1236: Cannot use That itself'])
delete('Xthat.vim') delete('Xthat.vim')
enddef enddef
def Test_import_as()
var export_lines =<< trim END
vim9script
export var one = 1
export var yes = 'yes'
export var slist: list<string>
END
writefile(export_lines, 'XexportAs')
var import_lines =<< trim END
vim9script
var one = 'notused'
var yes = 777
import one as thatOne from './XexportAs'
assert_equal(1, thatOne)
import yes as yesYes from './XexportAs'
assert_equal('yes', yesYes)
END
CheckScriptSuccess(import_lines)
import_lines =<< trim END
vim9script
import {one as thatOne, yes as yesYes} from './XexportAs'
assert_equal(1, thatOne)
assert_equal('yes', yesYes)
assert_fails('echo one', 'E121:')
assert_fails('echo yes', 'E121:')
END
CheckScriptSuccess(import_lines)
import_lines =<< trim END
vim9script
import {slist as impSlist} from './XexportAs'
impSlist->add(123)
END
CheckScriptFailure(import_lines, 'E1012: Type mismatch; expected string but got number')
delete('XexportAs')
enddef
func g:Trigger() func g:Trigger()
source Ximport.vim source Ximport.vim
return "echo 'yes'\<CR>" return "echo 'yes'\<CR>"
@ -1661,8 +1572,8 @@ def Test_import_export_expr_map()
var import_lines =<< trim END var import_lines =<< trim END
vim9script vim9script
import That from './Xexport_that.vim' import './Xexport_that.vim' as that
assert_equal('yes', That()) assert_equal('yes', that.That())
END END
writefile(import_lines, 'Ximport.vim') writefile(import_lines, 'Ximport.vim')
@ -1685,8 +1596,8 @@ def Test_import_in_filetype()
var import_lines =<< trim END var import_lines =<< trim END
vim9script vim9script
import That from './Xexport_ft.vim' import './Xexport_ft.vim' as ft
assert_equal('yes', That) assert_equal('yes', ft.That)
g:did_load_mytpe = 1 g:did_load_mytpe = 1
END END
writefile(import_lines, 'ftplugin/qf.vim') writefile(import_lines, 'ftplugin/qf.vim')
@ -1704,30 +1615,32 @@ def Test_import_in_filetype()
&rtp = save_rtp &rtp = save_rtp
enddef enddef
def Test_use_import_in_mapping() " FIXME
var lines =<< trim END "def Test_use_import_in_mapping()
vim9script " var lines =<< trim END
export def Funcx() " vim9script
g:result = 42 " export def Funcx()
enddef " g:result = 42
END " enddef
writefile(lines, 'XsomeExport.vim') " END
lines =<< trim END " writefile(lines, 'XsomeExport.vim')
vim9script " lines =<< trim END
import Funcx from './XsomeExport.vim' " vim9script
nnoremap <F3> :call <sid>Funcx()<cr> " import './XsomeExport.vim' as some
END " var Funcy = some.Funcx
writefile(lines, 'Xmapscript.vim') " nnoremap <F3> :call <sid>Funcy()<cr>
" END
source Xmapscript.vim " writefile(lines, 'Xmapscript.vim')
feedkeys("\<F3>", "xt") "
assert_equal(42, g:result) " source Xmapscript.vim
" feedkeys("\<F3>", "xt")
unlet g:result " assert_equal(42, g:result)
delete('XsomeExport.vim') "
delete('Xmapscript.vim') " unlet g:result
nunmap <F3> " delete('XsomeExport.vim')
enddef " delete('Xmapscript.vim')
" nunmap <F3>
"enddef
def Test_vim9script_mix() def Test_vim9script_mix()
var lines =<< trim END var lines =<< trim END
@ -1754,7 +1667,6 @@ def Test_vim9script_fails()
CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:') CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:')
CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:') CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:')
CheckScriptFailure(['export var some = 123'], 'E1042:') CheckScriptFailure(['export var some = 123'], 'E1042:')
CheckScriptFailure(['import some from "./Xexport.vim"'], 'E1048:')
CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:') CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:')
CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:') CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:')
@ -1802,14 +1714,13 @@ def Test_vim9script_reload_noclear()
vim9script noclear vim9script noclear
g:loadCount += 1 g:loadCount += 1
var s:reloaded = 'init' var s:reloaded = 'init'
import exported from './XExportReload' import './XExportReload' as exp
def Again(): string def Again(): string
return 'again' return 'again'
enddef enddef
import TheFunc from './XExportReload' exp.TheFunc()
TheFunc()
if exists('s:loaded') | finish | endif if exists('s:loaded') | finish | endif
var s:loaded = true var s:loaded = true
@ -1817,7 +1728,7 @@ def Test_vim9script_reload_noclear()
var s:notReloaded = 'yes' var s:notReloaded = 'yes'
s:reloaded = 'first' s:reloaded = 'first'
def g:Values(): list<string> def g:Values(): list<string>
return [s:reloaded, s:notReloaded, Again(), Once(), exported] return [s:reloaded, s:notReloaded, Again(), Once(), exp.exported]
enddef enddef
def Once(): string def Once(): string
@ -2022,14 +1933,14 @@ def Test_vim9script_funcref()
var lines =<< trim END var lines =<< trim END
vim9script vim9script
import FastSort from './Xsort.vim' import './Xsort.vim'
def Test() def Test()
g:result = FastSort() g:result = Xsort.FastSort()
enddef enddef
Test() Test()
# using a function imported with "as" # using a function imported with "as"
import * as anAlias from './Xsort.vim' import './Xsort.vim' as anAlias
assert_equal('yes', anAlias.GetString('yes')) assert_equal('yes', anAlias.GetString('yes'))
# using the function from a compiled function # using the function from a compiled function
@ -2075,13 +1986,13 @@ def Test_vim9script_funcref_other_script()
var lines =<< trim END var lines =<< trim END
vim9script vim9script
import {FilterFunc, FastFilter, FastFilterDirect} from './Xfilter.vim' import './Xfilter.vim' as filter
def Test() def Test()
var x: list<number> = FastFilter() var x: list<number> = filter.FastFilter()
enddef enddef
Test() Test()
def TestDirect() def TestDirect()
var x: list<number> = FastFilterDirect() var x: list<number> = filter.FastFilterDirect()
enddef enddef
TestDirect() TestDirect()
END END
@ -2155,11 +2066,11 @@ enddef
def Test_import_absolute() def Test_import_absolute()
var import_lines = [ var import_lines = [
'vim9script', 'vim9script',
'import exported from "' .. escape(getcwd(), '\') .. '/Xexport_abs.vim"', 'import "' .. escape(getcwd(), '\') .. '/Xexport_abs.vim" as abs',
'def UseExported()', 'def UseExported()',
' g:imported_abs = exported', ' g:imported_abs = abs.exported',
' exported = 8888', ' abs.exported = 8888',
' g:imported_after = exported', ' g:imported_after = abs.exported',
'enddef', 'enddef',
'UseExported()', 'UseExported()',
'g:import_disassembled = execute("disass UseExported")', 'g:import_disassembled = execute("disass UseExported")',
@ -2172,13 +2083,13 @@ def Test_import_absolute()
assert_equal(9876, g:imported_abs) assert_equal(9876, g:imported_abs)
assert_equal(8888, g:imported_after) assert_equal(8888, g:imported_after)
assert_match('<SNR>\d\+_UseExported\_s*' .. assert_match('<SNR>\d\+_UseExported\_s*' ..
'g:imported_abs = exported\_s*' .. 'g:imported_abs = abs.exported\_s*' ..
'0 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' .. '0 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
'1 STOREG g:imported_abs\_s*' .. '1 STOREG g:imported_abs\_s*' ..
'exported = 8888\_s*' .. 'abs.exported = 8888\_s*' ..
'2 PUSHNR 8888\_s*' .. '2 PUSHNR 8888\_s*' ..
'3 STORESCRIPT exported-2 in .*Xexport_abs.vim\_s*' .. '3 STORESCRIPT exported-2 in .*Xexport_abs.vim\_s*' ..
'g:imported_after = exported\_s*' .. 'g:imported_after = abs.exported\_s*' ..
'4 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' .. '4 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
'5 STOREG g:imported_after', '5 STOREG g:imported_after',
g:import_disassembled) g:import_disassembled)
@ -2194,8 +2105,8 @@ enddef
def Test_import_rtp() def Test_import_rtp()
var import_lines = [ var import_lines = [
'vim9script', 'vim9script',
'import exported from "Xexport_rtp.vim"', 'import "Xexport_rtp.vim" as rtp',
'g:imported_rtp = exported', 'g:imported_rtp = rtp.exported',
] ]
writefile(import_lines, 'Ximport_rtp.vim') writefile(import_lines, 'Ximport_rtp.vim')
mkdir('import', 'p') mkdir('import', 'p')
@ -2225,9 +2136,9 @@ def Test_import_compile_error()
var import_lines = [ var import_lines = [
'vim9script', 'vim9script',
'import ExpFunc from "./Xexported.vim"', 'import "./Xexported.vim" as expo',
'def ImpFunc()', 'def ImpFunc()',
' echo ExpFunc()', ' echo expo.ExpFunc()',
'enddef', 'enddef',
'defcompile', 'defcompile',
] ]
@ -2279,16 +2190,16 @@ def Test_func_overrules_import_fails()
var lines =<< trim END var lines =<< trim END
vim9script vim9script
import Func from './XexportedFunc.vim' import './XexportedFunc.vim' as Func
def Func() def Func()
echo 'local to function' echo 'local to function'
enddef enddef
END END
CheckScriptFailure(lines, 'E1041:') CheckScriptFailure(lines, 'E1236:')
lines =<< trim END lines =<< trim END
vim9script vim9script
import Func from './XexportedFunc.vim' import './XexportedFunc.vim' as Func
def Outer() def Outer()
def Func() def Func()
echo 'local to function' echo 'local to function'
@ -2296,7 +2207,7 @@ def Test_func_overrules_import_fails()
enddef enddef
defcompile defcompile
END END
CheckScriptFailure(lines, 'E1073:') CheckScriptFailure(lines, 'E1236:')
delete('XexportedFunc.vim') delete('XexportedFunc.vim')
enddef enddef
@ -3941,15 +3852,15 @@ def Test_source_vim9_from_legacy()
call assert_equal('global', global) call assert_equal('global', global)
call assert_equal('global', g:global) call assert_equal('global', g:global)
" imported variable becomes script-local "" imported variable becomes script-local
import exported from './Xvim9_script.vim' "import exported from './Xvim9_script.vim'
call assert_equal('exported', s:exported) "call assert_equal('exported', s:exported)
call assert_false(exists('exported')) "call assert_false(exists('exported'))
" imported function becomes script-local "" imported function becomes script-local
import GetText from './Xvim9_script.vim' "import GetText from './Xvim9_script.vim'
call assert_equal('text', s:GetText()) "call assert_equal('text', s:GetText())
call assert_false(exists('*GetText')) "call assert_false(exists('*GetText'))
END END
writefile(legacy_lines, 'Xlegacy_script.vim') writefile(legacy_lines, 'Xlegacy_script.vim')
@ -4248,7 +4159,8 @@ def Test_cmdline_win()
writefile(export_lines, 'rtp/syntax/Xexport.vim') writefile(export_lines, 'rtp/syntax/Xexport.vim')
var import_lines =<< trim END var import_lines =<< trim END
vim9script vim9script
import That from './Xexport.vim' import './Xexport.vim' as exp
echo exp.That
END END
writefile(import_lines, 'rtp/syntax/vim.vim') writefile(import_lines, 'rtp/syntax/vim.vim')
var save_rtp = &rtp var save_rtp = &rtp
@ -4594,36 +4506,36 @@ def Test_script_var_gone_when_sourced_twice()
unlet g:guard unlet g:guard
enddef enddef
def Test_import_gone_when_sourced_twice() "def Test_import_gone_when_sourced_twice()
var exportlines =<< trim END " var exportlines =<< trim END
vim9script " vim9script
if exists('g:guard') " if exists('g:guard')
finish " finish
endif " endif
g:guard = 1 " g:guard = 1
export var name = 'someName' " export var name = 'someName'
END " END
writefile(exportlines, 'XexportScript.vim') " writefile(exportlines, 'XexportScript.vim')
"
var lines =<< trim END " var lines =<< trim END
vim9script " vim9script
import name from './XexportScript.vim' " import name from './XexportScript.vim'
def g:GetName(): string " def g:GetName(): string
return name " return name
enddef " enddef
END " END
writefile(lines, 'XscriptImport.vim') " writefile(lines, 'XscriptImport.vim')
so XscriptImport.vim " so XscriptImport.vim
assert_equal('someName', g:GetName()) " assert_equal('someName', g:GetName())
"
so XexportScript.vim " so XexportScript.vim
assert_fails('call g:GetName()', 'E1149:') " assert_fails('call g:GetName()', 'E1149:')
"
delfunc g:GetName " delfunc g:GetName
delete('XexportScript.vim') " delete('XexportScript.vim')
delete('XscriptImport.vim') " delete('XscriptImport.vim')
unlet g:guard " unlet g:guard
enddef "enddef
def Test_unsupported_commands() def Test_unsupported_commands()
var lines =<< trim END var lines =<< trim END

View File

@ -1608,34 +1608,14 @@ deref_func_name(
} }
import = find_imported(p, len, NULL); import = find_imported(p, len, NULL);
// imported variable from another script // imported function from another script
if (import != NULL) if (import != NULL)
{ {
if (import->imp_funcname != NULL) name[len] = NUL;
{ semsg(_(e_cannot_use_str_itself_it_is_imported), name);
s = import->imp_funcname; name[len] = cc;
*lenp = (int)STRLEN(s); *lenp = 0;
return s; return (char_u *)""; // just in case
}
if (import->imp_flags & IMP_FLAGS_STAR)
{
name[len] = NUL;
semsg(_(e_cannot_use_str_itself_it_is_imported_with_star),
name);
name[len] = cc;
*lenp = 0;
return (char_u *)""; // just in case
}
else
{
scriptitem_T *si = SCRIPT_ITEM(import->imp_sid);
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
+ import->imp_var_vals_idx;
tv = sv->sv_tv;
if (type != NULL)
*type = sv->sv_type;
did_type = TRUE;
}
} }
} }
@ -1673,7 +1653,7 @@ deref_func_name(
{ {
if (!did_type && type != NULL && ht == get_script_local_ht()) if (!did_type && type != NULL && ht == get_script_local_ht())
{ {
svar_T *sv = find_typval_in_script(tv); svar_T *sv = find_typval_in_script(tv, 0);
if (sv != NULL) if (sv != NULL)
*type = sv->sv_type; *type = sv->sv_type;
@ -1905,16 +1885,13 @@ find_func_with_sid(char_u *name, int sid)
* Return NULL for unknown function. * Return NULL for unknown function.
*/ */
ufunc_T * ufunc_T *
find_func_even_dead(char_u *name, int is_global, cctx_T *cctx) find_func_even_dead(char_u *name, int is_global, cctx_T *cctx UNUSED)
{ {
hashitem_T *hi; hashitem_T *hi;
ufunc_T *func; ufunc_T *func;
imported_T *imported;
if (!is_global) if (!is_global)
{ {
char_u *after_script = NULL;
long sid = 0;
int find_script_local = in_vim9script() && eval_isnamec1(*name) int find_script_local = in_vim9script() && eval_isnamec1(*name)
&& (name[1] != ':' || *name == 's'); && (name[1] != ':' || *name == 's');
@ -1926,35 +1903,6 @@ find_func_even_dead(char_u *name, int is_global, cctx_T *cctx)
if (func != NULL) if (func != NULL)
return func; return func;
} }
if (name[0] == K_SPECIAL
&& name[1] == KS_EXTRA
&& name[2] == KE_SNR)
{
// Caller changes s: to <SNR>99_name.
after_script = name + 3;
sid = getdigits(&after_script);
if (*after_script == '_')
++after_script;
else
after_script = NULL;
}
if (find_script_local || after_script != NULL)
{
// Find imported function before global one.
if (after_script != NULL && sid != current_sctx.sc_sid)
imported = find_imported_in_script(after_script, 0, sid);
else
imported = find_imported(after_script == NULL
? name : after_script, 0, cctx);
if (imported != NULL && imported->imp_funcname != NULL)
{
hi = hash_find(&func_hashtab, imported->imp_funcname);
if (!HASHITEM_EMPTY(hi))
return HI2UF(hi);
}
}
} }
hi = hash_find(&func_hashtab, hi = hash_find(&func_hashtab,
@ -4257,8 +4205,8 @@ define_function(exarg_T *eap, char_u *name_arg, char_u **line_to_free)
// In Vim9 script a function cannot have the same name as a // In Vim9 script a function cannot have the same name as a
// variable. // variable.
if (vim9script && *arg == K_SPECIAL if (vim9script && *arg == K_SPECIAL
&& eval_variable(name_base, (int)STRLEN(name_base), NULL, NULL, && eval_variable(name_base, (int)STRLEN(name_base), 0, NULL,
EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT NULL, EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT
+ EVAL_VAR_NO_FUNC) == OK) + EVAL_VAR_NO_FUNC) == OK)
{ {
semsg(_(e_redefining_script_item_str), name_base); semsg(_(e_redefining_script_item_str), name_base);

View File

@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
4019,
/**/ /**/
4018, 4018,
/**/ /**/

View File

@ -1357,7 +1357,39 @@ compile_lhs(
// existing script-local variables should have a type // existing script-local variables should have a type
lhs->lhs_scriptvar_sid = current_sctx.sc_sid; lhs->lhs_scriptvar_sid = current_sctx.sc_sid;
if (import != NULL) if (import != NULL)
{
char_u *dot = vim_strchr(var_start, '.');
char_u *p;
// for an import the name is what comes after the dot
if (dot == NULL)
{
semsg(_(e_no_dot_after_imported_name_str),
var_start);
return FAIL;
}
p = skipwhite(dot + 1);
var_end = to_name_end(p, TRUE);
if (var_end == p)
{
semsg(_(e_missing_name_after_imported_name_str),
var_start);
return FAIL;
}
vim_free(lhs->lhs_name);
lhs->lhs_varlen = var_end - p;
lhs->lhs_name = vim_strnsave(p, lhs->lhs_varlen);
if (lhs->lhs_name == NULL)
return FAIL;
rawname = lhs->lhs_name;
lhs->lhs_scriptvar_sid = import->imp_sid; lhs->lhs_scriptvar_sid = import->imp_sid;
// TODO: where do we check this name is exported?
// Check if something follows: "exp.var[idx]" or
// "exp.var.key".
lhs->lhs_has_index = lhs->lhs_dest_end
> skipwhite(var_end);
}
if (SCRIPT_ID_VALID(lhs->lhs_scriptvar_sid)) if (SCRIPT_ID_VALID(lhs->lhs_scriptvar_sid))
{ {
// Check writable only when no index follows. // Check writable only when no index follows.

View File

@ -1160,7 +1160,7 @@ store_var(char_u *name, typval_T *tv)
if (tv->v_lock) if (tv->v_lock)
flags |= ASSIGN_CONST; flags |= ASSIGN_CONST;
save_funccal(&entry); save_funccal(&entry);
set_var_const(name, NULL, tv, FALSE, flags, 0); set_var_const(name, 0, NULL, tv, FALSE, flags, 0);
restore_funccal(); restore_funccal();
} }
@ -2252,7 +2252,7 @@ exec_instructions(ectx_T *ectx)
if (GA_GROW_FAILS(&ectx->ec_stack, 1)) if (GA_GROW_FAILS(&ectx->ec_stack, 1))
goto theend; goto theend;
SOURCING_LNUM = iptr->isn_lnum; SOURCING_LNUM = iptr->isn_lnum;
if (eval_variable(name, (int)STRLEN(name), if (eval_variable(name, (int)STRLEN(name), 0,
STACK_TV_BOT(0), NULL, EVAL_VAR_VERBOSE) == FAIL) STACK_TV_BOT(0), NULL, EVAL_VAR_VERBOSE) == FAIL)
goto on_error; goto on_error;
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;

View File

@ -240,7 +240,7 @@ compile_load_scriptvar(
cctx_T *cctx, cctx_T *cctx,
char_u *name, // variable NUL terminated char_u *name, // variable NUL terminated
char_u *start, // start of variable char_u *start, // start of variable
char_u **end, // end of variable char_u **end, // end of variable, may be NULL
int error) // when TRUE may give error int error) // when TRUE may give error
{ {
scriptitem_T *si; scriptitem_T *si;
@ -266,65 +266,56 @@ compile_load_scriptvar(
return OK; return OK;
} }
import = find_imported(name, 0, cctx); import = end == NULL ? NULL : find_imported(name, 0, cctx);
if (import != NULL) if (import != NULL)
{ {
if (import->imp_flags & IMP_FLAGS_STAR) char_u *p = skipwhite(*end);
char_u *exp_name;
int cc;
ufunc_T *ufunc;
type_T *type;
// Need to lookup the member.
if (*p != '.')
{ {
char_u *p = skipwhite(*end); semsg(_(e_expected_dot_after_name_str), start);
char_u *exp_name; return FAIL;
int cc;
ufunc_T *ufunc;
type_T *type;
// Used "import * as Name", need to lookup the member.
if (*p != '.')
{
semsg(_(e_expected_dot_after_name_str), start);
return FAIL;
}
++p;
if (VIM_ISWHITE(*p))
{
emsg(_(e_no_white_space_allowed_after_dot));
return FAIL;
}
// isolate one name
exp_name = p;
while (eval_isnamec(*p))
++p;
cc = *p;
*p = NUL;
idx = find_exported(import->imp_sid, exp_name, &ufunc, &type,
cctx, TRUE);
*p = cc;
p = skipwhite(p);
*end = p;
if (idx < 0)
{
if (*p == '(' && ufunc != NULL)
{
generate_PUSHFUNC(cctx, ufunc->uf_name, import->imp_type);
return OK;
}
return FAIL;
}
generate_VIM9SCRIPT(cctx, ISN_LOADSCRIPT,
import->imp_sid,
idx,
type);
} }
else if (import->imp_funcname != NULL) ++p;
generate_PUSHFUNC(cctx, import->imp_funcname, import->imp_type); if (VIM_ISWHITE(*p))
else {
generate_VIM9SCRIPT(cctx, ISN_LOADSCRIPT, emsg(_(e_no_white_space_allowed_after_dot));
import->imp_sid, return FAIL;
import->imp_var_vals_idx, }
import->imp_type);
// isolate one name
exp_name = p;
while (eval_isnamec(*p))
++p;
cc = *p;
*p = NUL;
idx = find_exported(import->imp_sid, exp_name, &ufunc, &type,
cctx, TRUE);
*p = cc;
p = skipwhite(p);
*end = p;
if (idx < 0)
{
if (ufunc != NULL)
{
// function call or function reference
generate_PUSHFUNC(cctx, ufunc->uf_name, NULL);
return OK;
}
return FAIL;
}
generate_VIM9SCRIPT(cctx, ISN_LOADSCRIPT,
import->imp_sid,
idx,
type);
return OK; return OK;
} }

View File

@ -363,121 +363,27 @@ handle_import(
void *cctx) void *cctx)
{ {
char_u *arg = arg_start; char_u *arg = arg_start;
char_u *cmd_end = NULL; char_u *nextarg;
int getnext;
char_u *expr_end;
int ret = FAIL; int ret = FAIL;
char_u *as_name = NULL;
typval_T tv; typval_T tv;
int sid = -1; int sid = -1;
int res; int res;
int mult = FALSE;
garray_T names;
garray_T as_names;
long start_lnum = SOURCING_LNUM; 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 // The name of the file can be an expression, which must evaluate to a
// string. // string.
arg = skipwhite_and_linebreak(arg + 4, evalarg); ret = eval0_retarg(arg, &tv, NULL, evalarg, &expr_end);
ret = eval0(arg, &tv, NULL, evalarg);
if (ret == FAIL) if (ret == FAIL)
goto erret; goto erret;
if (tv.v_type != VAR_STRING if (tv.v_type != VAR_STRING
|| tv.vval.v_string == NULL || *tv.vval.v_string == NUL) || 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; goto erret;
} }
cmd_end = arg;
// Give error messages for the start of the line. // Give error messages for the start of the line.
SOURCING_LNUM = start_lnum; SOURCING_LNUM = start_lnum;
@ -532,12 +438,55 @@ handle_import(
goto erret; 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; 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); imported = find_imported(as_name, STRLEN(as_name), cctx);
if (imported != NULL && imported->imp_sid == sid) if (imported != NULL && imported->imp_sid == sid)
{ {
@ -550,107 +499,27 @@ handle_import(
goto erret; goto erret;
} }
} }
else if (check_defined(as_name, STRLEN(as_name), cctx, FALSE) == FAIL)
goto erret;
imported = new_imported(gap != NULL ? gap imported = new_imported(gap != NULL ? gap
: &SCRIPT_ITEM(import_sid)->sn_imports); : &SCRIPT_ITEM(import_sid)->sn_imports);
if (imported == NULL) if (imported == NULL)
goto erret; goto erret;
imported->imp_name = as_name; imported->imp_name = as_name;
((char_u **)as_names.ga_data)[0] = NULL; as_name = NULL;
imported->imp_sid = sid; 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: erret:
clear_tv(&tv); clear_tv(&tv);
ga_clear_strings(&names); vim_free(as_name);
ga_clear_strings(&as_names); return arg;
return cmd_end;
} }
/* /*
* ":import Item from 'filename'" * ":import 'filename'"
* ":import Item as Alias from 'filename'" * ":import 'filename' as Name"
* ":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'"
*/ */
void void
ex_import(exarg_T *eap) 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 variable return the index.
* When it is a user function return "*ufunc". * When it is a user function return "*ufunc".
* When not found returns -1 and "*ufunc" is NULL. * When not found returns -1 and "*ufunc" is NULL.
@ -807,7 +676,7 @@ vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
init_tv.v_type = VAR_NUMBER; init_tv.v_type = VAR_NUMBER;
else else
init_tv.v_type = type->tt_type; 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); vim_free(name);
return p; return p;
@ -902,7 +771,7 @@ update_vim9_script_var(
} }
else else
{ {
sv = find_typval_in_script(&di->di_tv); sv = find_typval_in_script(&di->di_tv, 0);
} }
if (sv != NULL) if (sv != NULL)
{ {
@ -991,12 +860,13 @@ hide_script_var(scriptitem_T *si, int idx, int func_defined)
/* /*
* Find the script-local variable that links to "dest". * 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. * Returns NULL if not found and give an internal error.
*/ */
svar_T * 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; int idx;
if (si->sn_version != SCRIPT_VERSION_VIM9) if (si->sn_version != SCRIPT_VERSION_VIM9)