# HG changeset patch # User Bram Moolenaar # Date 1615665603 -3600 # Node ID 0346a59ed5bfd122f4a9a12f83ce548750c842f3 # Parent 33c1e030ceae50856403a4b3b433942ee6699fec patch 8.2.2597: Vim9: "import * as" does not work at script level Commit: https://github.com/vim/vim/commit/cb4e80fab9b1ee67249bde4f784526f900cda70c Author: Bram Moolenaar Date: Sat Mar 13 20:57:19 2021 +0100 patch 8.2.2597: Vim9: "import * as" does not work at script level Problem: Vim9: "import * as" does not work at script level. Solution: Implement using an imported namespace. diff --git a/src/errors.h b/src/errors.h --- a/src/errors.h +++ b/src/errors.h @@ -373,3 +373,5 @@ EXTERN char e_argument_name_shadows_exis INIT(= N_("E1167: Argument name shadows existing variable: %s")); EXTERN char e_argument_already_declared_in_script_str[] INIT(= N_("E1168: Argument already declared in the script: %s")); +EXTERN char e_import_as_name_not_supported_here[] + INIT(= N_("E1169: 'import * as {name}' not supported here")); diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -1370,7 +1370,7 @@ set_var_lval( // handle +=, -=, *=, /=, %= and .= di = NULL; if (eval_variable(lp->ll_name, (int)STRLEN(lp->ll_name), - &tv, &di, TRUE, FALSE) == OK) + &tv, &di, EVAL_VAR_VERBOSE) == OK) { if ((di == NULL || (!var_check_ro(di->di_flags, lp->ll_name, FALSE) @@ -3500,7 +3500,8 @@ eval7( ret = OK; } else - ret = eval_variable(s, len, rettv, NULL, TRUE, FALSE); + ret = eval_variable(s, len, rettv, NULL, + EVAL_VAR_VERBOSE + EVAL_VAR_IMPORT); } else { @@ -5760,6 +5761,63 @@ handle_subscript( check_white = FALSE; } + if (rettv->v_type == VAR_ANY) + { + char_u *exp_name; + int cc; + int idx; + ufunc_T *ufunc; + type_T *type; + + // Found script from "import * as {name}", script item name must + // follow. + if (**arg != '.') + { + if (verbose) + semsg(_(e_expected_str_but_got_str), "'.'", *arg); + ret = FAIL; + break; + } + ++*arg; + if (IS_WHITE_OR_NUL(**arg)) + { + if (verbose) + emsg(_(e_no_white_space_allowed_after_dot)); + ret = FAIL; + break; + } + + // isolate the name + exp_name = *arg; + while (eval_isnamec(**arg)) + ++*arg; + cc = **arg; + **arg = NUL; + + idx = find_exported(rettv->vval.v_number, exp_name, &ufunc, &type, + evalarg->eval_cctx, verbose); + **arg = cc; + *arg = skipwhite(*arg); + + if (idx < 0 && ufunc == NULL) + { + ret = FAIL; + break; + } + if (idx >= 0) + { + scriptitem_T *si = SCRIPT_ITEM(rettv->vval.v_number); + svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx; + + copy_tv(sv->sv_tv, rettv); + } + else + { + rettv->v_type = VAR_FUNC; + rettv->vval.v_string = vim_strsave(ufunc->uf_name); + } + } + if ((**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC || rettv->v_type == VAR_PARTIAL)) && (!check_white || !VIM_ISWHITE(*(*arg - 1)))) diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -1219,7 +1219,8 @@ list_arg_vars(exarg_T *eap, char_u *arg, arg = skipwhite(arg); if (tofree != NULL) name = tofree; - if (eval_variable(name, len, &tv, NULL, TRUE, FALSE) == FAIL) + if (eval_variable(name, len, &tv, NULL, + EVAL_VAR_VERBOSE) == FAIL) error = TRUE; else { @@ -2539,6 +2540,8 @@ set_cmdarg(exarg_T *eap, char_u *oldarg) /* * Get the value of internal variable "name". + * If "flags" has EVAL_VAR_IMPORT may return a VAR_ANY with v_number set to the + * imported script ID. * Return OK or FAIL. If OK is returned "rettv" must be cleared. */ int @@ -2547,12 +2550,11 @@ eval_variable( int len, // length of "name" typval_T *rettv, // NULL when only checking existence dictitem_T **dip, // non-NULL when typval's dict item is needed - int verbose, // may give error message - int no_autoload) // do not use script autoloading + int flags) // EVAL_VAR_ flags { int ret = OK; typval_T *tv = NULL; - int foundFunc = FALSE; + int found = FALSE; dictitem_T *v; int cc; @@ -2561,7 +2563,7 @@ eval_variable( name[len] = NUL; // Check for user-defined variables. - v = find_var(name, NULL, no_autoload); + v = find_var(name, NULL, flags & EVAL_VAR_NOAUTOLOAD); if (v != NULL) { tv = &v->di_tv; @@ -2581,7 +2583,7 @@ eval_variable( { if (import->imp_funcname != NULL) { - foundFunc = TRUE; + found = TRUE; if (rettv != NULL) { rettv->v_type = VAR_FUNC; @@ -2590,8 +2592,21 @@ eval_variable( } else if (import->imp_flags & IMP_FLAGS_STAR) { - emsg("Sorry, 'import * as X' not implemented yet"); - ret = FAIL; + if ((flags & EVAL_VAR_IMPORT) == 0) + { + 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 { @@ -2607,7 +2622,7 @@ eval_variable( if (ufunc != NULL) { - foundFunc = TRUE; + found = TRUE; if (rettv != NULL) { rettv->v_type = VAR_FUNC; @@ -2617,11 +2632,11 @@ eval_variable( } } - if (!foundFunc) + if (!found) { if (tv == NULL) { - if (rettv != NULL && verbose) + if (rettv != NULL && (flags & EVAL_VAR_VERBOSE)) semsg(_(e_undefined_variable_str), name); ret = FAIL; } @@ -3695,7 +3710,8 @@ var_exists(char_u *var) { if (tofree != NULL) name = tofree; - n = (eval_variable(name, len, &tv, NULL, FALSE, TRUE) == OK); + n = (eval_variable(name, len, &tv, NULL, + EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT) == OK); if (n) { // handle d.key, l[idx], f(expr) diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro --- a/src/proto/evalvars.pro +++ b/src/proto/evalvars.pro @@ -56,7 +56,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 verbose, int no_autoload); +int eval_variable(char_u *name, int len, 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); diff --git a/src/proto/vim9script.pro b/src/proto/vim9script.pro --- a/src/proto/vim9script.pro +++ b/src/proto/vim9script.pro @@ -7,7 +7,7 @@ void ex_export(exarg_T *eap); void free_imports_and_script_vars(int sid); void mark_imports_for_reload(int sid); void ex_import(exarg_T *eap); -int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx); +int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx, int verbose); char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, evalarg_T *evalarg, void *cctx); 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); 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 @@ -1031,13 +1031,17 @@ def Test_vim9_import_export() vim9script import * as Export from './Xexport.vim' def UseExport() - g:imported = Export.exported + g:imported_def = Export.exported enddef + g:imported_script = Export.exported + assert_equal(1, exists('Export.exported')) + assert_equal(0, exists('Export.notexported')) UseExport() END writefile(import_star_as_lines, 'Ximport.vim') source Ximport.vim - assert_equal(9883, g:imported) + assert_equal(9883, g:imported_def) + assert_equal(9883, g:imported_script) var import_star_as_lines_no_dot =<< trim END vim9script @@ -1072,6 +1076,22 @@ def Test_vim9_import_export() writefile(import_star_as_duplicated, 'Ximport.vim') assert_fails('source Ximport.vim', 'E1073:', '', 4, 'Ximport.vim') + var import_star_as_lines_script_no_dot =<< trim END + vim9script + import * as Export from './Xexport.vim' + g:imported_script = Export exported + END + writefile(import_star_as_lines_script_no_dot, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1029:') + + var import_star_as_lines_script_space_after_dot =<< trim END + vim9script + import * as Export from './Xexport.vim' + g:imported_script = Export. exported + END + writefile(import_star_as_lines_script_space_after_dot, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1074:') + var import_star_as_lines_missing_name =<< trim END vim9script import * as Export from './Xexport.vim' diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2597, +/**/ 2596, /**/ 2595, diff --git a/src/vim.h b/src/vim.h --- a/src/vim.h +++ b/src/vim.h @@ -2702,4 +2702,9 @@ long elapsed(DWORD start_tick); #define MCH_DELAY_IGNOREINPUT 1 #define MCH_DELAY_SETTMODE 2 +// Flags for eval_variable(). +#define EVAL_VAR_VERBOSE 1 // may give error message +#define EVAL_VAR_NOAUTOLOAD 2 // do not use script autoloading +#define EVAL_VAR_IMPORT 4 // may return special variable for import + #endif // VIM__H diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1765,7 +1765,7 @@ call_def_function( goto failed; SOURCING_LNUM = iptr->isn_lnum; if (eval_variable(name, (int)STRLEN(name), - STACK_TV_BOT(0), NULL, TRUE, FALSE) == FAIL) + STACK_TV_BOT(0), NULL, EVAL_VAR_VERBOSE) == FAIL) goto on_error; ++ectx.ec_stack.ga_len; } diff --git a/src/vim9script.c b/src/vim9script.c --- a/src/vim9script.c +++ b/src/vim9script.c @@ -257,7 +257,8 @@ find_exported( char_u *name, ufunc_T **ufunc, type_T **type, - cctx_T *cctx) + cctx_T *cctx, + int verbose) { int idx = -1; svar_T *sv; @@ -271,7 +272,8 @@ find_exported( sv = ((svar_T *)script->sn_var_vals.ga_data) + idx; if (!sv->sv_export) { - semsg(_(e_item_not_exported_in_script_str), name); + if (verbose) + semsg(_(e_item_not_exported_in_script_str), name); return -1; } *type = sv->sv_type; @@ -301,7 +303,8 @@ find_exported( if (*ufunc == NULL) { - semsg(_(e_item_not_found_in_script_str), name); + if (verbose) + semsg(_(e_item_not_found_in_script_str), name); return -1; } } @@ -532,7 +535,7 @@ handle_import( ufunc_T *ufunc = NULL; type_T *type; - idx = find_exported(sid, name, &ufunc, &type, cctx); + idx = find_exported(sid, name, &ufunc, &type, cctx, TRUE); if (idx < 0 && ufunc == NULL) goto erret;