0
0
mirror of https://github.com/vim/vim.git synced 2025-08-30 20:43:35 -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* *:imp* *E1094*
The exported items can be imported individually in another Vim9 script: >
import EXPORTED_CONST from "thatscript.vim"
import MyClass from "myclass.vim"
The exported items can be imported in another Vim9 script: >
import "myscript.vim"
To import multiple items at the same time: >
import {someValue, MyClass} from "thatscript.vim"
This makes each item available as "myscript.item".
In case the name is ambiguous, another name can be specified: >
import MyClass as ThatClass from "myclass.vim"
import {someValue, MyClass as ThatClass} from "myclass.vim"
To import all exported items under a specific identifier: >
import * as That from 'thatscript.vim'
In case the name is long or ambiguous, another name can be specified: >
import "thatscript.vim" as That
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
script file to avoid confusion. Also avoid command names, because the name
will shadow them.
to choose the name "That". Use something that will be recognized as referring
to the imported script. Avoid command names, because the name will shadow
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
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
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*
The `import` commands are executed when encountered. If that script (directly
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
other files to split up functionality in appropriate pieces. >
vim9script
import FilterFunc from "../import/someother.vim"
import "../import/someother.vim" as other
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
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"));
EXTERN char e_missing_from[]
INIT(= N_("E1070: Missing \"from\""));
EXTERN char e_invalid_string_after_from[]
INIT(= N_("E1071: Invalid string after \"from\""));
EXTERN char e_invalid_string_for_import_str[]
INIT(= N_("E1071: Invalid string for :import: %s"));
EXTERN char e_cannot_compare_str_with_str[]
INIT(= N_("E1072: Cannot compare %s with %s"));
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"));
EXTERN char e_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[]
INIT(= N_("E1236: Cannot use %s itself, it is imported with '*'"));
EXTERN char e_cannot_use_str_itself_it_is_imported[]
INIT(= N_("E1236: Cannot use %s itself, it is imported"));
EXTERN char e_no_such_user_defined_command_in_current_buffer_str[]
INIT(= N_("E1237: No such user-defined command in current buffer: %s"));
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>"));
EXTERN char e_string_or_function_required_for_argument_nr[]
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 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.
@ -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.
if ((*p != '[' && *p != '.') || lp->ll_name == NULL)
if ((*p != '[' && *p != '.'))
return p;
if (in_vim9script() && lval_root != NULL)
@ -997,7 +1024,7 @@ get_lval(
&& lp->ll_tv == &v->di_tv
&& 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
if (sv != NULL)
@ -1359,13 +1386,13 @@ set_var_lval(
// handle +=, -=, *=, /=, %= and .=
di = NULL;
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
|| (!var_check_ro(di->di_flags, lp->ll_name, FALSE)
&& !tv_check_lock(&di->di_tv, lp->ll_name, FALSE)))
&& 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);
clear_tv(&tv);
}
@ -1375,7 +1402,7 @@ set_var_lval(
if (lp->ll_type != NULL && check_typval_arg_type(lp->ll_type, rettv,
NULL, 0) == FAIL)
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);
}
*endp = cc;
@ -1389,7 +1416,7 @@ set_var_lval(
if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
&& (flags & ASSIGN_FOR_LOOP) == 0)
{
emsg(_("E996: Cannot lock a range"));
emsg(_(e_cannot_lock_range));
return;
}
@ -1404,7 +1431,7 @@ set_var_lval(
if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
&& (flags & ASSIGN_FOR_LOOP) == 0)
{
emsg(_("E996: Cannot lock a list or dict"));
emsg(_(e_cannot_lock_list_or_dict));
return;
}
@ -2089,7 +2116,7 @@ getline_peek_skip_comments(evalarg_T *evalarg)
* FALSE.
* "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)
{
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.
* Only called for Vim9 script.
*/
static char_u *
char_u *
eval_next_line(evalarg_T *evalarg)
{
garray_T *gap = &evalarg->eval_ga;
@ -2235,6 +2262,21 @@ eval0(
typval_T *rettv,
exarg_T *eap,
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;
char_u *p;
@ -2242,7 +2284,7 @@ eval0(
int did_emsg_before = did_emsg;
int called_emsg_before = called_emsg;
int flags = evalarg == NULL ? 0 : evalarg->eval_flags;
int check_for_end = TRUE;
int check_for_end = retarg == NULL;
int end_error = FALSE;
p = skipwhite(arg);
@ -2253,7 +2295,7 @@ eval0(
// In Vim9 script a command block is not split at NL characters for
// commands using an expression argument. Skip over a '#' comment to check
// 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 == '#')
{
char_u *nl = vim_strchr(p, NL);
@ -2298,7 +2340,9 @@ eval0(
return FAIL;
}
if (check_for_end && eap != NULL)
if (retarg != NULL)
*retarg = p;
else if (check_for_end && eap != NULL)
set_nextcmd(eap, p);
return ret;
@ -3669,7 +3713,7 @@ eval7(
ret = OK;
}
else
ret = eval_variable(s, len, rettv, NULL,
ret = eval_variable(s, len, 0, rettv, NULL,
EVAL_VAR_VERBOSE + EVAL_VAR_IMPORT);
}
else
@ -5887,7 +5931,7 @@ handle_subscript(
ufunc_T *ufunc;
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.
if (**arg != '.')
{
@ -5934,6 +5978,7 @@ handle_subscript(
rettv->v_type = VAR_FUNC;
rettv->vval.v_string = vim_strsave(ufunc->uf_name);
}
continue;
}
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);
if (tofree != NULL)
name = tofree;
if (eval_variable(name, len, &tv, NULL,
if (eval_variable(name, len, 0, &tv, NULL,
EVAL_VAR_VERBOSE) == FAIL)
error = TRUE;
else
@ -2645,6 +2645,7 @@ set_cmdarg(exarg_T *eap, char_u *oldarg)
eval_variable(
char_u *name,
int len, // length of "name"
scid_T sid, // script ID for imported item or zero
typval_T *rettv, // NULL when only checking existence
dictitem_T **dip, // non-NULL when typval's dict item is needed
int flags) // EVAL_VAR_ flags
@ -2678,48 +2679,50 @@ eval_variable(
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;
import = find_imported(p, 0, NULL);
if (sid == 0)
import = find_imported(p, 0, NULL);
// 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 (rettv != NULL)
if (sid != 0 && SCRIPT_ID_VALID(sid))
{
rettv->v_type = VAR_FUNC;
rettv->vval.v_string = vim_strsave(import->imp_funcname);
ht = &SCRIPT_VARS(sid);
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 if (import->imp_flags & IMP_FLAGS_STAR)
{
if ((flags & EVAL_VAR_IMPORT) == 0)
else
{
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
{
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;
type = sv->sv_type;
if (rettv != NULL)
{
rettv->v_type = VAR_ANY;
rettv->vval.v_number = sid != 0 ? sid : import->imp_sid;
}
found = TRUE;
}
}
else if (in_vim9script() && (flags & EVAL_VAR_NO_FUNC) == 0)
@ -2760,7 +2763,7 @@ eval_variable(
if (ht != NULL && ht == get_script_local_ht()
&& 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)
type = sv->sv_type;
@ -3278,17 +3281,19 @@ set_var(
typval_T *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".
* 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.
* Otherwise the variable is created.
*/
void
set_var_const(
char_u *name,
scid_T sid,
type_T *type_arg,
typval_T *tv_arg,
int copy, // make copy of value in "tv"
@ -3301,20 +3306,27 @@ set_var_const(
dictitem_T *di;
typval_T *dest_tv = NULL;
char_u *varname;
hashtab_T *ht;
hashtab_T *ht = NULL;
int is_script_local;
int vim9script = in_vim9script();
int var_in_vim9script;
int flags = flags_arg;
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)
{
semsg(_(e_illegal_variable_name_str), name);
goto failed;
}
is_script_local = ht == get_script_local_ht();
is_script_local = ht == get_script_local_ht() || sid != 0;
if (vim9script
&& !is_script_local
@ -3347,33 +3359,14 @@ set_var_const(
if (import != NULL)
{
scriptitem_T *si = SCRIPT_ITEM(import->imp_sid);
svar_T *sv;
where_T where = WHERE_INIT;
// imported variable from another script
// imported name space cannot be used
if ((flags & ASSIGN_NO_DECL) == 0)
{
semsg(_(e_redefining_imported_item_str), name);
goto failed;
}
if (import->imp_flags & IMP_FLAGS_STAR)
{
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);
semsg(_(e_cannot_use_str_itself_it_is_imported), name);
goto failed;
}
}
@ -3419,7 +3412,7 @@ set_var_const(
if (var_in_vim9script && (flags & ASSIGN_FOR_LOOP) == 0)
{
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)
{
@ -3956,7 +3949,7 @@ var_exists(char_u *var)
{
if (tofree != NULL)
name = tofree;
n = (eval_variable(name, len, &tv, NULL,
n = (eval_variable(name, len, 0, &tv, NULL,
EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT) == OK);
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 set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx);
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);
void init_evalarg(evalarg_T *evalarg);
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_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);
void eval_addblob(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_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 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);
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);
@ -72,7 +72,7 @@ void vars_clear(hashtab_T *ht);
void vars_clear_ext(hashtab_T *ht, int free_val);
void delete_var(hashtab_T *ht, hashitem_T *hi);
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_ro(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);
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);
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_reserved_name(char_u *name);
/* vim: set ft=c : */

View File

@ -1822,19 +1822,10 @@ struct svar_S {
typedef struct {
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
// 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;
#define IMP_FLAGS_STAR 1 // using "import * as Name"
#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)
type_T *ll_type; // type of variable (can be NULL)
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"
// isn't NULL it's the Dict to which to add
// the item.

View File

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

View File

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

View File

@ -1608,34 +1608,14 @@ deref_func_name(
}
import = find_imported(p, len, NULL);
// imported variable from another script
// imported function from another script
if (import != NULL)
{
if (import->imp_funcname != NULL)
{
s = import->imp_funcname;
*lenp = (int)STRLEN(s);
return s;
}
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;
}
name[len] = NUL;
semsg(_(e_cannot_use_str_itself_it_is_imported), name);
name[len] = cc;
*lenp = 0;
return (char_u *)""; // just in case
}
}
@ -1673,7 +1653,7 @@ deref_func_name(
{
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)
*type = sv->sv_type;
@ -1905,16 +1885,13 @@ find_func_with_sid(char_u *name, int sid)
* Return NULL for unknown function.
*/
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;
ufunc_T *func;
imported_T *imported;
if (!is_global)
{
char_u *after_script = NULL;
long sid = 0;
int find_script_local = in_vim9script() && eval_isnamec1(*name)
&& (name[1] != ':' || *name == 's');
@ -1926,35 +1903,6 @@ find_func_even_dead(char_u *name, int is_global, cctx_T *cctx)
if (func != NULL)
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,
@ -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
// variable.
if (vim9script && *arg == K_SPECIAL
&& eval_variable(name_base, (int)STRLEN(name_base), NULL, NULL,
EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT
&& eval_variable(name_base, (int)STRLEN(name_base), 0, NULL,
NULL, EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT
+ EVAL_VAR_NO_FUNC) == OK)
{
semsg(_(e_redefining_script_item_str), name_base);

View File

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

View File

@ -1357,7 +1357,39 @@ compile_lhs(
// existing script-local variables should have a type
lhs->lhs_scriptvar_sid = current_sctx.sc_sid;
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;
// 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))
{
// 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)
flags |= ASSIGN_CONST;
save_funccal(&entry);
set_var_const(name, NULL, tv, FALSE, flags, 0);
set_var_const(name, 0, NULL, tv, FALSE, flags, 0);
restore_funccal();
}
@ -2252,7 +2252,7 @@ exec_instructions(ectx_T *ectx)
if (GA_GROW_FAILS(&ectx->ec_stack, 1))
goto theend;
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)
goto on_error;
++ectx->ec_stack.ga_len;

View File

@ -240,7 +240,7 @@ compile_load_scriptvar(
cctx_T *cctx,
char_u *name, // variable NUL terminated
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
{
scriptitem_T *si;
@ -266,65 +266,56 @@ compile_load_scriptvar(
return OK;
}
import = find_imported(name, 0, cctx);
import = end == NULL ? NULL : find_imported(name, 0, cctx);
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);
char_u *exp_name;
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);
semsg(_(e_expected_dot_after_name_str), start);
return FAIL;
}
else if (import->imp_funcname != NULL)
generate_PUSHFUNC(cctx, import->imp_funcname, import->imp_type);
else
generate_VIM9SCRIPT(cctx, ISN_LOADSCRIPT,
import->imp_sid,
import->imp_var_vals_idx,
import->imp_type);
++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 (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;
}

View File

@ -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, char_u *arg)
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 idx, int func_defined)
/*
* 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)