summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-12-19 16:30:44 +0100
committerBram Moolenaar <Bram@vim.org>2020-12-19 16:30:44 +0100
commit03290b8444b69c6d7307755770467bc488384e1a (patch)
tree7b6b7eaaa41c2f2194a0712f6848fe8209552af6
parent1f33e0a7c4cd278158b37f91a2aa44f0bcd1f21a (diff)
patch 8.2.2162: Vim9: Cannot load or store autoload variablesv8.2.2162
Problem: Vim9: Cannot load or store autoload variables. Solution: Add ISN_LOADAUTO and ISN_STOREAUTO. (closes #7485)
-rw-r--r--src/dict.c2
-rw-r--r--src/eval.c2
-rw-r--r--src/evalvars.c12
-rw-r--r--src/proto/evalvars.pro2
-rw-r--r--src/testdir/test_vim9_disassemble.vim14
-rw-r--r--src/testdir/test_vim9_script.vim32
-rw-r--r--src/version.c2
-rw-r--r--src/vim9.h2
-rw-r--r--src/vim9compile.c24
-rw-r--r--src/vim9execute.c29
10 files changed, 106 insertions, 15 deletions
diff --git a/src/dict.c b/src/dict.c
index 051ba2f6ec..5abb9964ae 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -1073,7 +1073,7 @@ dict_extend(dict_T *d1, dict_T *d2, char_u *action)
&& HI2DI(hi2)->di_tv.v_type == VAR_FUNC
&& var_wrong_func_name(hi2->hi_key, di1 == NULL))
break;
- if (!valid_varname(hi2->hi_key))
+ if (!valid_varname(hi2->hi_key, TRUE))
break;
}
if (di1 == NULL)
diff --git a/src/eval.c b/src/eval.c
index 06c6adaf85..496e208756 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1049,7 +1049,7 @@ get_lval(
wrong = (lp->ll_dict->dv_scope == VAR_DEF_SCOPE
&& rettv->v_type == VAR_FUNC
&& var_wrong_func_name(key, lp->ll_di == NULL))
- || !valid_varname(key);
+ || !valid_varname(key, TRUE);
if (len != -1)
key[len] = prevval;
if (wrong)
diff --git a/src/evalvars.c b/src/evalvars.c
index fde80d750d..654eeff230 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -3195,8 +3195,10 @@ set_var_const(
goto failed;
}
- // Make sure the variable name is valid.
- if (!valid_varname(varname))
+ // Make sure the variable name is valid. In Vim9 script an autoload
+ // variable must be prefixed with "g:".
+ if (!valid_varname(varname, !vim9script
+ || STRNCMP(name, "g:", 2) == 0))
goto failed;
di = alloc(sizeof(dictitem_T) + STRLEN(varname));
@@ -3349,17 +3351,17 @@ value_check_lock(int lock, char_u *name, int use_gettext)
}
/*
- * Check if a variable name is valid.
+ * Check if a variable name is valid. When "autoload" is true "#" is allowed.
* Return FALSE and give an error if not.
*/
int
-valid_varname(char_u *varname)
+valid_varname(char_u *varname, int autoload)
{
char_u *p;
for (p = varname; *p != NUL; ++p)
if (!eval_isnamec1(*p) && (p == varname || !VIM_ISDIGIT(*p))
- && *p != AUTOLOAD_CHAR)
+ && !(autoload && *p == AUTOLOAD_CHAR))
{
semsg(_(e_illvar), varname);
return FALSE;
diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro
index 0449ea57ae..4c9d645823 100644
--- a/src/proto/evalvars.pro
+++ b/src/proto/evalvars.pro
@@ -75,7 +75,7 @@ int var_check_lock(int flags, char_u *name, int use_gettext);
int var_check_fixed(int flags, char_u *name, int use_gettext);
int var_wrong_func_name(char_u *name, int new_var);
int value_check_lock(int lock, char_u *name, int use_gettext);
-int valid_varname(char_u *varname);
+int valid_varname(char_u *varname, int autoload);
void reset_v_option_vars(void);
void assert_error(garray_T *gap);
int var_exists(char_u *var);
diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim
index 7ea1491e63..d936bc29a4 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -23,6 +23,7 @@ def s:ScriptFuncLoad(arg: string)
echo s:scriptvar
echo g:globalvar
echo get(g:, "global")
+ echo g:auto#var
echo b:buffervar
echo get(b:, "buffer")
echo w:windowvar
@@ -68,8 +69,14 @@ def Test_disassemble_load()
'echo get(g:, "global")\_s*' ..
'\d\+ LOAD g:\_s*' ..
'\d\+ PUSHS "global"\_s*' ..
- '\d\+ BCALL get(argc 2).*' ..
- ' LOADB b:buffervar.*' ..
+ '\d\+ BCALL get(argc 2)\_s*' ..
+ '\d\+ ECHO 1\_s*' ..
+ 'echo g:auto#var\_s*' ..
+ '\d\+ LOADAUTO g:auto#var\_s*' ..
+ '\d\+ ECHO 1\_s*' ..
+ 'echo b:buffervar\_s*' ..
+ '\d\+ LOADB b:buffervar\_s*' ..
+ '\d\+ ECHO 1\_s*' ..
'echo get(b:, "buffer")\_s*' ..
'\d\+ LOAD b:\_s*' ..
'\d\+ PUSHS "buffer"\_s*' ..
@@ -197,6 +204,7 @@ def s:ScriptFuncStore()
v:char = 'abc'
s:scriptvar = 'sv'
g:globalvar = 'gv'
+ g:auto#var = 'av'
b:buffervar = 'bv'
w:windowvar = 'wv'
t:tabpagevar = 'tv'
@@ -220,6 +228,8 @@ def Test_disassemble_store()
' STORES s:scriptvar in .*test_vim9_disassemble.vim.*' ..
'g:globalvar = ''gv''.*' ..
' STOREG g:globalvar.*' ..
+ 'g:auto#var = ''av''.*' ..
+ ' STOREAUTO g:auto#var.*' ..
'b:buffervar = ''bv''.*' ..
' STOREB b:buffervar.*' ..
'w:windowvar = ''wv''.*' ..
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 2f651cd33c..5949acbc60 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -2779,10 +2779,34 @@ def Test_vim9_copen()
quit
enddef
-" test using a vim9script that is auto-loaded from an autocmd
+" test using an auto-loaded function and variable
def Test_vim9_autoload()
var lines =<< trim END
vim9script
+ def some#gettest(): string
+ return 'test'
+ enddef
+ g:some#name = 'name'
+ END
+
+ mkdir('Xdir/autoload', 'p')
+ writefile(lines, 'Xdir/autoload/some.vim')
+ var save_rtp = &rtp
+ exe 'set rtp^=' .. getcwd() .. '/Xdir'
+
+ assert_equal('test', g:some#gettest())
+ assert_equal('name', g:some#name)
+ g:some#other = 'other'
+ assert_equal('other', g:some#other)
+
+ delete('Xdir', 'rf')
+ &rtp = save_rtp
+enddef
+
+" test using a vim9script that is auto-loaded from an autocmd
+def Test_vim9_aucmd_autoload()
+ var lines =<< trim END
+ vim9script
def foo#test()
echomsg getreg('"')
enddef
@@ -2842,6 +2866,12 @@ def Test_vim9_autoload_error()
delete('Xdidit')
delete('Xscript')
delete('Xruntime', 'rf')
+
+ lines =<< trim END
+ vim9script
+ var foo#bar = 'asdf'
+ END
+ CheckScriptFailure(lines, 'E461: Illegal variable name: foo#bar', 2)
enddef
def Test_script_var_in_autocmd()
diff --git a/src/version.c b/src/version.c
index 9d2632b09f..5ea062d05b 100644
--- 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 */
/**/
+ 2162,
+/**/
2161,
/**/
2160,
diff --git a/src/vim9.h b/src/vim9.h
index 26b208025d..26307c2707 100644
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -24,6 +24,7 @@ typedef enum {
ISN_LOAD, // push local variable isn_arg.number
ISN_LOADV, // push v: variable isn_arg.number
ISN_LOADG, // push g: variable isn_arg.string
+ ISN_LOADAUTO, // push g: autoload variable isn_arg.string
ISN_LOADB, // push b: variable isn_arg.string
ISN_LOADW, // push w: variable isn_arg.string
ISN_LOADT, // push t: variable isn_arg.string
@@ -41,6 +42,7 @@ typedef enum {
ISN_STORE, // pop into local variable isn_arg.number
ISN_STOREV, // pop into v: variable isn_arg.number
ISN_STOREG, // pop into global variable isn_arg.string
+ ISN_STOREAUTO, // pop into global autoload variable isn_arg.string
ISN_STOREB, // pop into buffer-local variable isn_arg.string
ISN_STOREW, // pop into window-local variable isn_arg.string
ISN_STORET, // pop into tab-local variable isn_arg.string
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 207ceb4eac..c584918801 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2535,7 +2535,17 @@ compile_load(
case 's': res = compile_load_scriptvar(cctx, name,
NULL, NULL, error);
break;
- case 'g': isn_type = ISN_LOADG; break;
+ case 'g': if (vim_strchr(name, AUTOLOAD_CHAR) == NULL)
+ isn_type = ISN_LOADG;
+ else
+ {
+ isn_type = ISN_LOADAUTO;
+ vim_free(name);
+ name = vim_strnsave(*arg, end - *arg);
+ if (name == NULL)
+ return FAIL;
+ }
+ break;
case 'w': isn_type = ISN_LOADW; break;
case 't': isn_type = ISN_LOADT; break;
case 'b': isn_type = ISN_LOADB; break;
@@ -2738,7 +2748,7 @@ compile_call(
if (compile_arguments(arg, cctx, &argcount) == FAIL)
goto theend;
- is_autoload = vim_strchr(name, '#') != NULL;
+ is_autoload = vim_strchr(name, AUTOLOAD_CHAR) != NULL;
if (ASCII_ISLOWER(*name) && name[1] != ':' && !is_autoload)
{
int idx;
@@ -4986,7 +4996,10 @@ generate_loadvar(
generate_LOAD(cctx, ISN_LOADOPT, 0, name, type);
break;
case dest_global:
- generate_LOAD(cctx, ISN_LOADG, 0, name + 2, type);
+ if (vim_strchr(name, AUTOLOAD_CHAR) == NULL)
+ generate_LOAD(cctx, ISN_LOADG, 0, name + 2, type);
+ else
+ generate_LOAD(cctx, ISN_LOADAUTO, 0, name, type);
break;
case dest_buffer:
generate_LOAD(cctx, ISN_LOADB, 0, name + 2, type);
@@ -5198,7 +5211,8 @@ generate_store_var(
opt_flags);
case dest_global:
// include g: with the name, easier to execute that way
- return generate_STORE(cctx, ISN_STOREG, 0, name);
+ return generate_STORE(cctx, vim_strchr(name, AUTOLOAD_CHAR) == NULL
+ ? ISN_STOREG : ISN_STOREAUTO, 0, name);
case dest_buffer:
// include b: with the name, easier to execute that way
return generate_STORE(cctx, ISN_STOREB, 0, name);
@@ -8007,6 +8021,7 @@ delete_instr(isn_T *isn)
{
case ISN_DEF:
case ISN_EXEC:
+ case ISN_LOADAUTO:
case ISN_LOADB:
case ISN_LOADENV:
case ISN_LOADG:
@@ -8017,6 +8032,7 @@ delete_instr(isn_T *isn)
case ISN_PUSHFUNC:
case ISN_PUSHS:
case ISN_RANGE:
+ case ISN_STOREAUTO:
case ISN_STOREB:
case ISN_STOREENV:
case ISN_STOREG:
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 4fd62ce9ed..7e5a1dea37 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -1391,6 +1391,21 @@ call_def_function(
}
break;
+ // load autoload variable
+ case ISN_LOADAUTO:
+ {
+ char_u *name = iptr->isn_arg.string;
+
+ if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
+ goto failed;
+ SOURCING_LNUM = iptr->isn_lnum;
+ if (eval_variable(name, STRLEN(name),
+ STACK_TV_BOT(0), NULL, TRUE, FALSE) == FAIL)
+ goto on_error;
+ ++ectx.ec_stack.ga_len;
+ }
+ break;
+
// load g:/b:/w:/t: namespace
case ISN_LOADGDICT:
case ISN_LOADBDICT:
@@ -1611,6 +1626,14 @@ call_def_function(
}
break;
+ // store an autoload variable
+ case ISN_STOREAUTO:
+ SOURCING_LNUM = iptr->isn_lnum;
+ set_var(iptr->isn_arg.string, STACK_TV_BOT(-1), TRUE);
+ clear_tv(STACK_TV_BOT(-1));
+ --ectx.ec_stack.ga_len;
+ break;
+
// store number in local variable
case ISN_STORENR:
tv = STACK_TV_VAR(iptr->isn_arg.storenr.stnr_idx);
@@ -3286,6 +3309,9 @@ ex_disassemble(exarg_T *eap)
iptr->isn_arg.loadstore.ls_name, si->sn_name);
}
break;
+ case ISN_LOADAUTO:
+ smsg("%4d LOADAUTO %s", current, iptr->isn_arg.string);
+ break;
case ISN_LOADG:
smsg("%4d LOADG g:%s", current, iptr->isn_arg.string);
break;
@@ -3337,6 +3363,9 @@ ex_disassemble(exarg_T *eap)
smsg("%4d STOREV v:%s", current,
get_vim_var_name(iptr->isn_arg.number));
break;
+ case ISN_STOREAUTO:
+ smsg("%4d STOREAUTO %s", current, iptr->isn_arg.string);
+ break;
case ISN_STOREG:
smsg("%4d STOREG %s", current, iptr->isn_arg.string);
break;