To: vim_dev@googlegroups.com Subject: Patch 8.2.4053 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4053 Problem: Vim9: autoload mechanism doesn't fully work yet. Solution: Define functions and variables with their autoload name, add the prefix when calling a function, find the variable in the table of script variables. Files: src/structs.h, src/scriptfile.c, src/proto/scriptfile.pro, src/vim9script.c, src/proto/vim9script.pro, src/userfunc.c, src/evalvars.c, src/testdir/test_vim9_script.vim *** ../vim-8.2.4052/src/structs.h 2022-01-09 21:32:57.709739119 +0000 --- src/structs.h 2022-01-10 17:31:10.464636150 +0000 *************** *** 1864,1870 **** int sn_state; // SN_STATE_ values char_u *sn_save_cpo; // 'cpo' value when :vim9script found char sn_is_vimrc; // .vimrc file, do not restore 'cpo' ! char sn_is_autoload; // "vim9script autoload" # ifdef FEAT_PROFILE int sn_prof_on; // TRUE when script is/was profiled --- 1864,1872 ---- int sn_state; // SN_STATE_ values char_u *sn_save_cpo; // 'cpo' value when :vim9script found char sn_is_vimrc; // .vimrc file, do not restore 'cpo' ! ! // for "vim9script autoload" this is "dir#scriptname#" ! char_u *sn_autoload_prefix; # ifdef FEAT_PROFILE int sn_prof_on; // TRUE when script is/was profiled *** ../vim-8.2.4052/src/scriptfile.c 2022-01-10 11:26:27.913657607 +0000 --- src/scriptfile.c 2022-01-10 15:47:47.934211210 +0000 *************** *** 1711,1716 **** --- 1711,1717 ---- # ifdef FEAT_PROFILE ga_clear(&si->sn_prl_ga); # endif + vim_free(si->sn_autoload_prefix); vim_free(si); } ga_clear(&script_items); *************** *** 2142,2147 **** --- 2143,2183 ---- } /* + * For an autoload script "autoload/dir/script.vim" return the prefix + * "dir#script#" in allocated memory. + * Returns NULL if anything is wrong. + */ + char_u * + get_autoload_prefix(scriptitem_T *si) + { + char_u *p = script_name_after_autoload(si); + char_u *prefix; + + if (p == NULL) + return NULL; + prefix = vim_strsave(p); + if (prefix == NULL) + return NULL; + + // replace all '/' with '#' and locate ".vim" at the end + for (p = prefix; *p != NUL; p += mb_ptr2len(p)) + { + if (vim_ispathsep(*p)) + *p = '#'; + else if (STRCMP(p, ".vim") == 0) + { + p[0] = '#'; + p[1] = NUL; + return prefix; + } + } + + // did not find ".vim" at the end + vim_free(prefix); + return NULL; + } + + /* * If in a Vim9 autoload script return "name" with the autoload prefix for the * script. If successful "name" is freed, the returned name is allocated. * Otherwise it returns "name" unmodified. *************** *** 2153,2189 **** { scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); ! if (si->sn_is_autoload) { ! char_u *p = script_name_after_autoload(si); ! if (p != NULL) { ! char_u *tail = vim_strsave(p); ! if (tail != NULL) ! { ! for (p = tail; *p != NUL; p += mb_ptr2len(p)) ! { ! if (vim_ispathsep(*p)) ! *p = '#'; ! else if (STRCMP(p, ".vim")) ! { ! size_t len = (p - tail) + STRLEN(name) + 2; ! char_u *res = alloc(len); ! ! if (res == NULL) ! break; ! *p = NUL; ! vim_snprintf((char *)res, len, "%s#%s", tail, name); ! vim_free(name); ! vim_free(tail); ! return res; ! } ! } ! } ! // did not find ".vim" at the end ! vim_free(tail); } } } --- 2189,2216 ---- { scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); ! if (si->sn_autoload_prefix != NULL) { ! char_u *basename = name; ! size_t len; ! char_u *res; ! if (*name == K_SPECIAL) { ! char_u *p = vim_strchr(name, '_'); ! // skip over "99_" ! if (p != NULL) ! basename = p + 1; ! } ! ! len = STRLEN(si->sn_autoload_prefix) + STRLEN(basename) + 2; ! res = alloc(len); ! if (res != NULL) ! { ! vim_snprintf((char *)res, len, "%s%s", ! si->sn_autoload_prefix, basename); ! return res; } } } *** ../vim-8.2.4052/src/proto/scriptfile.pro 2022-01-09 21:32:57.709739119 +0000 --- src/proto/scriptfile.pro 2022-01-10 15:34:51.665158700 +0000 *************** *** 38,43 **** --- 38,44 ---- void do_finish(exarg_T *eap, int reanimate); int source_finished(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie); char_u *script_name_after_autoload(scriptitem_T *si); + char_u *get_autoload_prefix(scriptitem_T *si); char_u *may_prefix_autoload(char_u *name); char_u *autoload_name(char_u *name); int script_autoload(char_u *name, int reload); *** ../vim-8.2.4052/src/vim9script.c 2022-01-09 21:32:57.709739119 +0000 --- src/vim9script.c 2022-01-10 17:29:34.380663156 +0000 *************** *** 132,138 **** } si->sn_state = SN_STATE_HAD_COMMAND; ! si->sn_is_autoload = found_autoload; current_sctx.sc_version = SCRIPT_VERSION_VIM9; si->sn_version = SCRIPT_VERSION_VIM9; --- 132,139 ---- } si->sn_state = SN_STATE_HAD_COMMAND; ! // Store the prefix with the script. It isused to find exported functions. ! si->sn_autoload_prefix = get_autoload_prefix(si); current_sctx.sc_version = SCRIPT_VERSION_VIM9; si->sn_version = SCRIPT_VERSION_VIM9; *************** *** 663,684 **** } else { char_u buffer[200]; char_u *funcname; ! // it could be a user function. ! if (STRLEN(name) < sizeof(buffer) - 15) funcname = buffer; else { ! funcname = alloc(STRLEN(name) + 15); if (funcname == NULL) 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, FALSE, NULL); if (funcname != buffer) vim_free(funcname); --- 664,700 ---- } else { + size_t len = STRLEN(name); char_u buffer[200]; char_u *funcname; ! // It could be a user function. Normally this is stored as ! // "99_name". For an autoload script a function is stored with ! // the autoload prefix: "dir#script#name". ! if (script->sn_autoload_prefix != NULL) ! len += STRLEN(script->sn_autoload_prefix) + 2; ! else ! len += 15; ! ! if (len < sizeof(buffer)) funcname = buffer; else { ! funcname = alloc(len); if (funcname == NULL) return -1; } ! if (script->sn_autoload_prefix != NULL) ! { ! sprintf((char *)funcname, "%s%s", script->sn_autoload_prefix, name); ! } ! else ! { ! 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, FALSE, NULL); if (funcname != buffer) vim_free(funcname); *************** *** 782,787 **** --- 798,804 ---- update_vim9_script_var( int create, dictitem_T *di, + char_u *name, int flags, typval_T *tv, type_T **type, *************** *** 801,807 **** if (ga_grow(&si->sn_var_vals, 1) == FAIL) return; ! hi = hash_find(&si->sn_all_vars.dv_hashtab, di->di_key); if (!HASHITEM_EMPTY(hi)) { // Variable with this name exists, either in this block or in --- 818,824 ---- if (ga_grow(&si->sn_var_vals, 1) == FAIL) return; ! hi = hash_find(&si->sn_all_vars.dv_hashtab, name); if (!HASHITEM_EMPTY(hi)) { // Variable with this name exists, either in this block or in *************** *** 833,839 **** // svar_T and create a new sallvar_T. sv = ((svar_T *)si->sn_var_vals.ga_data) + si->sn_var_vals.ga_len; newsav = (sallvar_T *)alloc_clear( ! sizeof(sallvar_T) + STRLEN(di->di_key)); if (newsav == NULL) return; --- 850,856 ---- // svar_T and create a new sallvar_T. sv = ((svar_T *)si->sn_var_vals.ga_data) + si->sn_var_vals.ga_len; newsav = (sallvar_T *)alloc_clear( ! sizeof(sallvar_T) + STRLEN(name)); if (newsav == NULL) return; *************** *** 843,849 **** sv->sv_export = is_export; newsav->sav_var_vals_idx = si->sn_var_vals.ga_len; ++si->sn_var_vals.ga_len; ! STRCPY(&newsav->sav_key, di->di_key); sv->sv_name = newsav->sav_key; newsav->sav_di = di; newsav->sav_block_id = si->sn_current_block_id; --- 860,866 ---- sv->sv_export = is_export; newsav->sav_var_vals_idx = si->sn_var_vals.ga_len; ++si->sn_var_vals.ga_len; ! STRCPY(&newsav->sav_key, name); sv->sv_name = newsav->sav_key; newsav->sav_di = di; newsav->sav_block_id = si->sn_current_block_id; *** ../vim-8.2.4052/src/proto/vim9script.pro 2022-01-06 21:10:24.465027868 +0000 --- src/proto/vim9script.pro 2022-01-10 17:30:49.312643816 +0000 *************** *** 13,19 **** void ex_import(exarg_T *eap); int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx, int verbose); 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, scid_T sid); int check_script_var_type(svar_T *sv, typval_T *value, char_u *name, where_T where); --- 13,19 ---- void ex_import(exarg_T *eap); int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx, int verbose); char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg); ! void update_vim9_script_var(int create, dictitem_T *di, char_u *name, 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, scid_T sid); int check_script_var_type(svar_T *sv, typval_T *value, char_u *name, where_T where); *** ../vim-8.2.4052/src/userfunc.c 2022-01-09 21:32:57.709739119 +0000 --- src/userfunc.c 2022-01-10 15:09:29.206253888 +0000 *************** *** 4080,4087 **** eap->skip = TRUE; } ! // if (is_export) ! // name = may_prefix_autoload(name); } // An error in a function call during evaluation of an expression in magic --- 4080,4090 ---- eap->skip = TRUE; } ! // For "export def FuncName()" in an autoload script the function name ! // is stored with the legacy autoload name "dir#script#FuncName" so ! // that it can also be found in legacy script. ! if (is_export) ! name = may_prefix_autoload(name); } // An error in a function call during evaluation of an expression in magic *** ../vim-8.2.4052/src/evalvars.c 2022-01-09 21:32:57.713739111 +0000 --- src/evalvars.c 2022-01-10 17:35:06.940495934 +0000 *************** *** 3339,3348 **** --- 3339,3350 ---- dictitem_T *di; typval_T *dest_tv = NULL; char_u *varname; + char_u *name_tofree = NULL; hashtab_T *ht = NULL; int is_script_local; int vim9script = in_vim9script(); int var_in_vim9script; + int var_in_autoload = FALSE; int flags = flags_arg; int free_tv_arg = !copy; // free tv_arg if not used *************** *** 3353,3365 **** 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() || sid != 0; if (vim9script && !is_script_local --- 3355,3388 ---- varname = name; } else ! { ! if (in_vim9script() && SCRIPT_ID_VALID(current_sctx.sc_sid) ! && SCRIPT_ITEM(current_sctx.sc_sid)->sn_autoload_prefix != NULL ! && is_export) ! { ! scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); ! size_t len = STRLEN(name) + STRLEN(si->sn_autoload_prefix) + 1; ! ! // In a vim9 autoload script an exported variable is put in the ! // global namespace with the autoload prefix. ! var_in_autoload = TRUE; ! varname = alloc(len); ! if (varname == NULL) ! goto failed; ! name_tofree = varname; ! vim_snprintf((char *)varname, len, "%s%s", ! si->sn_autoload_prefix, name); ! ht = &globvarht; ! } ! 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() || sid != 0 || var_in_autoload; if (vim9script && !is_script_local *************** *** 3470,3478 **** // A Vim9 script-local variable is also present in sn_all_vars // and sn_var_vals. It may set "type" from "tv". ! if (var_in_vim9script) ! update_vim9_script_var(FALSE, di, flags, tv, &type, ! (flags & ASSIGN_NO_MEMBER_TYPE) == 0); } // existing variable, need to clear the value --- 3493,3502 ---- // A Vim9 script-local variable is also present in sn_all_vars // and sn_var_vals. It may set "type" from "tv". ! if (var_in_vim9script || var_in_autoload) ! update_vim9_script_var(FALSE, di, ! var_in_autoload ? name : di->di_key, flags, ! tv, &type, (flags & ASSIGN_NO_MEMBER_TYPE) == 0); } // existing variable, need to clear the value *************** *** 3550,3559 **** goto failed; } ! // Make sure the variable name is valid. In Vim9 script an autoload ! // variable must be prefixed with "g:". if (!valid_varname(varname, -1, !vim9script ! || STRNCMP(name, "g:", 2) == 0)) goto failed; di = alloc(sizeof(dictitem_T) + STRLEN(varname)); --- 3574,3584 ---- goto failed; } ! // Make sure the variable name is valid. In Vim9 script an ! // autoload variable must be prefixed with "g:" unless in an ! // autoload script. if (!valid_varname(varname, -1, !vim9script ! || STRNCMP(name, "g:", 2) == 0 || var_in_autoload)) goto failed; di = alloc(sizeof(dictitem_T) + STRLEN(varname)); *************** *** 3571,3579 **** // A Vim9 script-local variable is also added to sn_all_vars and // sn_var_vals. It may set "type" from "tv". ! if (var_in_vim9script) ! update_vim9_script_var(TRUE, di, flags, tv, &type, ! (flags & ASSIGN_NO_MEMBER_TYPE) == 0); } dest_tv = &di->di_tv; --- 3596,3605 ---- // A Vim9 script-local variable is also added to sn_all_vars and // sn_var_vals. It may set "type" from "tv". ! if (var_in_vim9script || var_in_autoload) ! update_vim9_script_var(TRUE, di, ! var_in_autoload ? name : di->di_key, flags, ! tv, &type, (flags & ASSIGN_NO_MEMBER_TYPE) == 0); } dest_tv = &di->di_tv; *************** *** 3618,3623 **** --- 3644,3650 ---- item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE); failed: + vim_free(name_tofree); if (free_tv_arg) clear_tv(tv_arg); } *** ../vim-8.2.4052/src/testdir/test_vim9_script.vim 2022-01-09 21:32:57.713739111 +0000 --- src/testdir/test_vim9_script.vim 2022-01-10 17:53:36.878611178 +0000 *************** *** 3049,3054 **** --- 3049,3062 ---- assert_false(exists('g:prefixed_loaded')) assert_equal('test', prefixed.Gettest()) assert_equal('yes', g:prefixed_loaded) + assert_equal('name', prefixed.name) + END + CheckScriptSuccess(lines) + + # can also get the items by autoload name + lines =<< trim END + call assert_equal('test', prefixed#Gettest()) + call assert_equal('name', prefixed#name) END CheckScriptSuccess(lines) *** ../vim-8.2.4052/src/version.c 2022-01-10 13:36:31.264892417 +0000 --- src/version.c 2022-01-10 15:49:28.510212127 +0000 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 4053, /**/ -- MAN: Fetchez la vache! GUARD: Quoi? MAN: Fetchez la vache! "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///