diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-01-25 15:51:56 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-01-25 15:51:56 +0000 |
commit | 06b77229ca704d00c4f138ed0377556e54d5851f (patch) | |
tree | 6b24e9838841943803574a424599d687be2c05f1 /src/vim9execute.c | |
parent | dc5490e2cbc8c16022a23b449b48c1bd0083f366 (diff) | |
download | vim-git-06b77229ca704d00c4f138ed0377556e54d5851f.tar.gz |
patch 8.2.4216: Vim9: cannot use a function from an autoload import directlyv8.2.4216
Problem: Vim9: cannot use a function from an autoload import directly.
Solution: Add the AUTOLOAD instruction to figure out at runtime.
(closes #9620)
Diffstat (limited to 'src/vim9execute.c')
-rw-r--r-- | src/vim9execute.c | 163 |
1 files changed, 105 insertions, 58 deletions
diff --git a/src/vim9execute.c b/src/vim9execute.c index e58da5b5e..1232b35bb 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2260,6 +2260,77 @@ execute_for(isn_T *iptr, ectx_T *ectx) } /* + * Load instruction for w:/b:/g:/t: variable. + * "isn_type" is used instead of "iptr->isn_type". + */ + static int +load_namespace_var(ectx_T *ectx, isntype_T isn_type, isn_T *iptr) +{ + dictitem_T *di = NULL; + hashtab_T *ht = NULL; + char namespace; + + if (GA_GROW_FAILS(&ectx->ec_stack, 1)) + return NOTDONE; + switch (isn_type) + { + case ISN_LOADG: + ht = get_globvar_ht(); + namespace = 'g'; + break; + case ISN_LOADB: + ht = &curbuf->b_vars->dv_hashtab; + namespace = 'b'; + break; + case ISN_LOADW: + ht = &curwin->w_vars->dv_hashtab; + namespace = 'w'; + break; + case ISN_LOADT: + ht = &curtab->tp_vars->dv_hashtab; + namespace = 't'; + break; + default: // Cannot reach here + return NOTDONE; + } + di = find_var_in_ht(ht, 0, iptr->isn_arg.string, TRUE); + + if (di == NULL && ht == get_globvar_ht() + && vim_strchr(iptr->isn_arg.string, + AUTOLOAD_CHAR) != NULL) + { + // Global variable has an autoload name, may still need + // to load the script. + if (script_autoload(iptr->isn_arg.string, FALSE)) + di = find_var_in_ht(ht, 0, + iptr->isn_arg.string, TRUE); + if (did_emsg) + return FAIL; + } + + if (di == NULL) + { + SOURCING_LNUM = iptr->isn_lnum; + if (vim_strchr(iptr->isn_arg.string, + AUTOLOAD_CHAR) != NULL) + // no check if the item exists in the script but + // isn't exported, it is too complicated + semsg(_(e_item_not_found_in_script_str), + iptr->isn_arg.string); + else + semsg(_(e_undefined_variable_char_str), + namespace, iptr->isn_arg.string); + return FAIL; + } + else + { + copy_tv(&di->di_tv, STACK_TV_BOT(0)); + ++ectx->ec_stack.ga_len; + } + return OK; +} + +/* * Execute instructions in execution context "ectx". * Return OK or FAIL; */ @@ -2772,68 +2843,14 @@ exec_instructions(ectx_T *ectx) case ISN_LOADW: case ISN_LOADT: { - dictitem_T *di = NULL; - hashtab_T *ht = NULL; - char namespace; + int res = load_namespace_var(ectx, iptr->isn_type, iptr); - if (GA_GROW_FAILS(&ectx->ec_stack, 1)) + if (res == NOTDONE) goto theend; - switch (iptr->isn_type) - { - case ISN_LOADG: - ht = get_globvar_ht(); - namespace = 'g'; - break; - case ISN_LOADB: - ht = &curbuf->b_vars->dv_hashtab; - namespace = 'b'; - break; - case ISN_LOADW: - ht = &curwin->w_vars->dv_hashtab; - namespace = 'w'; - break; - case ISN_LOADT: - ht = &curtab->tp_vars->dv_hashtab; - namespace = 't'; - break; - default: // Cannot reach here - goto theend; - } - di = find_var_in_ht(ht, 0, iptr->isn_arg.string, TRUE); - - if (di == NULL && ht == get_globvar_ht() - && vim_strchr(iptr->isn_arg.string, - AUTOLOAD_CHAR) != NULL) - { - // Global variable has an autoload name, may still need - // to load the script. - if (script_autoload(iptr->isn_arg.string, FALSE)) - di = find_var_in_ht(ht, 0, - iptr->isn_arg.string, TRUE); - if (did_emsg) - goto on_error; - } - - if (di == NULL) - { - SOURCING_LNUM = iptr->isn_lnum; - if (vim_strchr(iptr->isn_arg.string, - AUTOLOAD_CHAR) != NULL) - // no check if the item exists in the script but - // isn't exported, it is too complicated - semsg(_(e_item_not_found_in_script_str), - iptr->isn_arg.string); - else - semsg(_(e_undefined_variable_char_str), - namespace, iptr->isn_arg.string); + if (res == FAIL) goto on_error; - } - else - { - copy_tv(&di->di_tv, STACK_TV_BOT(0)); - ++ectx->ec_stack.ga_len; - } } + break; // load autoload variable @@ -3264,6 +3281,33 @@ exec_instructions(ectx_T *ectx) } break; + case ISN_AUTOLOAD: + { + char_u *name = iptr->isn_arg.string; + + (void)script_autoload(name, FALSE); + if (find_func(name, TRUE)) + { + if (GA_GROW_FAILS(&ectx->ec_stack, 1)) + goto theend; + tv = STACK_TV_BOT(0); + tv->v_lock = 0; + ++ectx->ec_stack.ga_len; + tv->v_type = VAR_FUNC; + tv->vval.v_string = vim_strsave(name); + } + else + { + int res = load_namespace_var(ectx, ISN_LOADG, iptr); + + if (res == NOTDONE) + goto theend; + if (res == FAIL) + goto on_error; + } + } + break; + case ISN_UNLET: if (do_unlet(iptr->isn_arg.unlet.ul_name, iptr->isn_arg.unlet.ul_forceit) == FAIL) @@ -5596,6 +5640,9 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc) case ISN_PUSHEXC: smsg("%s%4d PUSH v:exception", pfx, current); break; + case ISN_AUTOLOAD: + smsg("%s%4d AUTOLOAD %s", pfx, current, iptr->isn_arg.string); + break; case ISN_UNLET: smsg("%s%4d UNLET%s %s", pfx, current, iptr->isn_arg.unlet.ul_forceit ? "!" : "", |