# HG changeset patch # User Bram Moolenaar # Date 1582489803 -3600 # Node ID 17f0d6dc6a73cd025b81d86a89f0d4f8830fd345 # Parent 6afcef2bfba3152cb11f4781e975500a2f329653 patch 8.2.0312: Vim9: insufficient script tests Commit: https://github.com/vim/vim/commit/f2d5c240a56853c0bbbc7979e9bff095de6c73ec Author: Bram Moolenaar Date: Sun Feb 23 21:25:54 2020 +0100 patch 8.2.0312: Vim9: insufficient script tests Problem: Vim9: insufficient script tests. Solution: Add more tests. Make "import * as Name" work. diff --git a/src/proto/vim9script.pro b/src/proto/vim9script.pro --- a/src/proto/vim9script.pro +++ b/src/proto/vim9script.pro @@ -4,5 +4,6 @@ void ex_vim9script(exarg_T *eap); void ex_export(exarg_T *eap); void free_imports(int sid); void ex_import(exarg_T *eap); -char_u *handle_import(char_u *arg_start, garray_T *gap, int sid); +int find_exported(int sid, char_u **argp, int *name_len, ufunc_T **ufunc, type_T **type); +char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid); /* vim: set ft=c : */ diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -331,6 +331,28 @@ def Test_vim9script() unlet g:imported_func unlet g:imported_name g:imported_name_appended delete('Ximport.vim') + + let import_star_as_lines =<< trim END + vim9script + import * as Export from './Xexport.vim' + def UseExport() + g:imported = Export.exported + enddef + UseExport() + END + writefile(import_star_as_lines, 'Ximport.vim') + source Ximport.vim + assert_equal(9876, g:imported) + + let import_star_lines =<< trim END + vim9script + import * from './Xexport.vim' + g:imported = exported + END + writefile(import_star_lines, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1045:') + + delete('Ximport.vim') delete('Xexport.vim') " Check that in a Vim9 script 'cpo' is set to the Vim default. @@ -352,6 +374,7 @@ def Test_vim9script_fails() CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:') CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:') CheckScriptFailure(['export let some = 123'], 'E1042:') + CheckScriptFailure(['import some from "./Xexport.vim"'], 'E1042:') CheckScriptFailure(['vim9script', 'export let g:some'], 'E1044:') CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:') diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -739,6 +739,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 312, +/**/ 311, /**/ 310, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1522,7 +1522,11 @@ find_imported(char_u *name, size_t len, * Generate an instruction to load script-local variable "name". */ static int -compile_load_scriptvar(cctx_T *cctx, char_u *name) +compile_load_scriptvar( + cctx_T *cctx, + char_u *name, // variable NUL terminated + char_u *start, // start of variable + char_u **end) // end of variable { scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); int idx = get_script_item_idx(current_sctx.sc_sid, name, FALSE); @@ -1546,11 +1550,40 @@ compile_load_scriptvar(cctx_T *cctx, cha import = find_imported(name, 0, cctx); if (import != NULL) { - // TODO: check this is a variable, not a function - generate_VIM9SCRIPT(cctx, ISN_LOADSCRIPT, - import->imp_sid, - import->imp_var_vals_idx, - import->imp_type); + if (import->imp_all) + { + char_u *p = skipwhite(*end); + int name_len; + ufunc_T *ufunc; + type_T *type; + + // Used "import * as Name", need to lookup the member. + if (*p != '.') + { + semsg(_("E1060: expected dot after name: %s"), start); + return FAIL; + } + ++p; + + idx = find_exported(import->imp_sid, &p, &name_len, &ufunc, &type); + // TODO: what if it is a function? + if (idx < 0) + return FAIL; + *end = p; + + generate_VIM9SCRIPT(cctx, ISN_LOADSCRIPT, + import->imp_sid, + idx, + type); + } + else + { + // TODO: check this is a variable, not a function + generate_VIM9SCRIPT(cctx, ISN_LOADSCRIPT, + import->imp_sid, + import->imp_var_vals_idx, + import->imp_type); + } return OK; } @@ -1564,10 +1597,11 @@ compile_load_scriptvar(cctx_T *cctx, cha * When "error" is FALSE do not give an error when not found. */ static int -compile_load(char_u **arg, char_u *end, cctx_T *cctx, int error) +compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error) { type_T *type; char_u *name; + char_u *end = end_arg; int res = FAIL; if (*(*arg + 1) == ':') @@ -1589,7 +1623,7 @@ compile_load(char_u **arg, char_u *end, } else if (**arg == 's') { - res = compile_load_scriptvar(cctx, name); + res = compile_load_scriptvar(cctx, name, NULL, NULL); } else { @@ -1645,7 +1679,7 @@ compile_load(char_u **arg, char_u *end, else if (SCRIPT_ITEM(current_sctx.sc_sid)->sn_version == SCRIPT_VERSION_VIM9) // in Vim9 script "var" can be script-local. - res = compile_load_scriptvar(cctx, name); + res = compile_load_scriptvar(cctx, name, *arg, &end); } } if (gen_load) @@ -3412,7 +3446,7 @@ compile_assignment(char_u *arg, exarg_T generate_LOAD(cctx, ISN_LOADG, 0, name + 2, type); break; case dest_script: - compile_load_scriptvar(cctx, name + (name[1] == ':' ? 2 : 0)); + compile_load_scriptvar(cctx, name + (name[1] == ':' ? 2 : 0), NULL, NULL); break; case dest_env: // Include $ in the name here diff --git a/src/vim9script.c b/src/vim9script.c --- a/src/vim9script.c +++ b/src/vim9script.c @@ -151,6 +151,88 @@ ex_import(exarg_T *eap) } /* + * Find an exported item in "sid" matching the name at "*argp". + * 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. + */ + int +find_exported( + int sid, + char_u **argp, + int *name_len, + ufunc_T **ufunc, + type_T **type) +{ + char_u *name = *argp; + char_u *arg = *argp; + int cc; + int idx = -1; + svar_T *sv; + scriptitem_T *script = SCRIPT_ITEM(sid); + + // isolate one name + while (eval_isnamec1(*arg)) + ++arg; + *name_len = (int)(arg - name); + + // find name in "script" + // TODO: also find script-local user function + cc = *arg; + *arg = NUL; + idx = get_script_item_idx(sid, name, FALSE); + if (idx >= 0) + { + sv = ((svar_T *)script->sn_var_vals.ga_data) + idx; + if (!sv->sv_export) + { + semsg(_("E1049: Item not exported in script: %s"), name); + *arg = cc; + return -1; + } + *type = sv->sv_type; + *ufunc = NULL; + } + else + { + char_u buffer[200]; + char_u *funcname; + + // it could be a user function. + if (STRLEN(name) < sizeof(buffer) - 10) + funcname = buffer; + else + { + funcname = alloc(STRLEN(name) + 10); + if (funcname == NULL) + { + *arg = cc; + return -1; + } + } + funcname[0] = K_SPECIAL; + funcname[1] = KS_EXTRA; + funcname[2] = (int)KE_SNR; + sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name); + *ufunc = find_func(funcname, NULL); + if (funcname != buffer) + vim_free(funcname); + + if (*ufunc == NULL) + { + semsg(_("E1048: Item not found in script: %s"), name); + *arg = cc; + return -1; + } + } + *arg = cc; + arg = skipwhite(arg); + *argp = arg; + + return idx; +} + +/* * Handle an ":import" command and add the resulting imported_T to "gap", when * not NULL, or script "import_sid" sn_imports. * Returns a pointer to after the command or NULL in case of failure @@ -289,8 +371,6 @@ handle_import(char_u *arg_start, garray_ } else { - scriptitem_T *script = SCRIPT_ITEM(sid); - arg = arg_start; if (*arg == '{') arg = skipwhite(arg + 1); @@ -298,68 +378,15 @@ handle_import(char_u *arg_start, garray_ { char_u *name = arg; int name_len; - int cc; int idx; - svar_T *sv; imported_T *imported; - ufunc_T *ufunc; - - // isolate one name - while (eval_isnamec1(*arg)) - ++arg; - name_len = (int)(arg - name); + ufunc_T *ufunc = NULL; + type_T *type; - // find name in "script" - // TODO: also find script-local user function - cc = *arg; - *arg = NUL; - idx = get_script_item_idx(sid, name, FALSE); - if (idx >= 0) - { - sv = ((svar_T *)script->sn_var_vals.ga_data) + idx; - if (!sv->sv_export) - { - semsg(_("E1049: Item not exported in script: %s"), name); - *arg = cc; - return NULL; - } - ufunc = NULL; - } - else - { - char_u buffer[200]; - char_u *funcname; + idx = find_exported(sid, &arg, &name_len, &ufunc, &type); - // it could be a user function. - if (STRLEN(name) < sizeof(buffer) - 10) - funcname = buffer; - else - { - funcname = alloc(STRLEN(name) + 10); - if (funcname == NULL) - { - *arg = cc; - return NULL; - } - } - funcname[0] = K_SPECIAL; - funcname[1] = KS_EXTRA; - funcname[2] = (int)KE_SNR; - sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name); - ufunc = find_func(funcname, NULL); - if (funcname != buffer) - vim_free(funcname); - - if (ufunc == NULL) - { - semsg(_("E1048: Item not found in script: %s"), name); - *arg = cc; - return NULL; - } - sv = NULL; - } - *arg = cc; - arg = skipwhite(arg); + if (idx < 0 && ufunc == NULL) + return NULL; imported = new_imported(gap != NULL ? gap : &SCRIPT_ITEM(import_sid)->sn_imports); @@ -372,7 +399,7 @@ handle_import(char_u *arg_start, garray_ imported->imp_sid = sid; if (idx >= 0) { - imported->imp_type = sv->sv_type; + imported->imp_type = type; imported->imp_var_vals_idx = idx; } else