Problem: Vim9: import mechanism is too complicated.
Solution: Do not use the Javascript mechanism but a much simpler one.
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.
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
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
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[]
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[]
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"));
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.
}
}
}
+ 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)
&& 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)
// 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);
}
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;
if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
&& (flags & ASSIGN_FOR_LOOP) == 0)
{
- emsg(_("E996: Cannot lock a range"));
+ emsg(_(e_cannot_lock_range));
return;
}
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;
}
* 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);
* 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;
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;
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);
// 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);
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;
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
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 != '.')
{
rettv->v_type = VAR_FUNC;
rettv->vval.v_string = vim_strsave(ufunc->uf_name);
}
+ continue;
}
if ((**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC
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
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
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)
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;
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"
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
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;
}
}
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)
{
{
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)
{
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);
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);
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);
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 : */
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
/*
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.
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'
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()
+
+ expo.ExportedInc()
+ g:exported_i1 = expo.exported
+ g:exported_i2 = expo.ExportedValue()
- exported = 11
- g:exported_s1 = exported
- g:exported_s2 = ExportedValue()
+ expo.exported = 11
+ g:exported_s1 = expo.exported
+ g:exported_s2 = expo.ExportedValue()
- g:imported_func = Exported()
+ 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)
# 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
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
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
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
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
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')
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')
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')
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
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
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')
# 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
# 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')
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')
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()
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:')
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>"
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')
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')
&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
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:')
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
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
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
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
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")',
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)
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')
var import_lines = [
'vim9script',
- 'import ExpFunc from "./Xexported.vim"',
+ 'import "./Xexported.vim" as expo',
'def ImpFunc()',
- ' echo ExpFunc()',
+ ' echo expo.ExpFunc()',
'enddef',
'defcompile',
]
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'
enddef
defcompile
END
- CheckScriptFailure(lines, 'E1073:')
+ CheckScriptFailure(lines, 'E1236:')
delete('XexportedFunc.vim')
enddef
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')
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
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
}
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
}
}
{
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;
* 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');
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,
// 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);
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 4019,
/**/
4018,
/**/
// 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.
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();
}
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;
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;
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;
+ 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;
+ }
- // Used "import * as Name", need to lookup the member.
- if (*p != '.')
- {
- semsg(_(e_expected_dot_after_name_str), start);
- return FAIL;
- }
+ // isolate one name
+ exp_name = p;
+ while (eval_isnamec(*p))
++p;
- if (VIM_ISWHITE(*p))
- {
- emsg(_(e_no_white_space_allowed_after_dot));
- return FAIL;
- }
+ cc = *p;
+ *p = NUL;
- // 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,
+ idx = find_exported(import->imp_sid, exp_name, &ufunc, &type,
cctx, TRUE);
- *p = cc;
- p = skipwhite(p);
- *end = p;
+ *p = cc;
+ p = skipwhite(p);
+ *end = p;
- if (idx < 0)
+ if (idx < 0)
+ {
+ if (ufunc != NULL)
{
- if (*p == '(' && ufunc != NULL)
- {
- generate_PUSHFUNC(cctx, ufunc->uf_name, import->imp_type);
- return OK;
- }
- return FAIL;
+ // function call or function reference
+ generate_PUSHFUNC(cctx, ufunc->uf_name, NULL);
+ return OK;
}
-
- generate_VIM9SCRIPT(cctx, ISN_LOADSCRIPT,
- import->imp_sid,
- idx,
- type);
+ 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);
+
+ generate_VIM9SCRIPT(cctx, ISN_LOADSCRIPT,
+ import->imp_sid,
+ idx,
+ type);
return OK;
}
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;
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)
{
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)
}
/*
- * 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.
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;
}
else
{
- sv = find_typval_in_script(&di->di_tv);
+ sv = find_typval_in_script(&di->di_tv, 0);
}
if (sv != NULL)
{
/*
* 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)