mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
patch 8.2.0600: Vim9: cannot read or write w:, t: and b: variables
Problem: Vim9: cannot read or write w:, t: and b: variables. Solution: Implement load and store for w:, t: and b: variables. (closes #5950)
This commit is contained in:
@@ -8,6 +8,9 @@ endfunc
|
||||
|
||||
let s:scriptvar = 4
|
||||
let g:globalvar = 'g'
|
||||
let b:buffervar = 'b'
|
||||
let w:windowvar = 'w'
|
||||
let t:tabpagevar = 't'
|
||||
|
||||
def s:ScriptFuncLoad(arg: string)
|
||||
let local = 1
|
||||
@@ -17,6 +20,9 @@ def s:ScriptFuncLoad(arg: string)
|
||||
echo v:version
|
||||
echo s:scriptvar
|
||||
echo g:globalvar
|
||||
echo b:buffervar
|
||||
echo w:windowvar
|
||||
echo t:tabpagevar
|
||||
echo &tabstop
|
||||
echo $ENVVAR
|
||||
echo @z
|
||||
@@ -39,6 +45,9 @@ def Test_disassemble_load()
|
||||
' LOADV v:version.*' ..
|
||||
' LOADS s:scriptvar from .*test_vim9_disassemble.vim.*' ..
|
||||
' LOADG g:globalvar.*' ..
|
||||
' LOADB b:buffervar.*' ..
|
||||
' LOADW w:windowvar.*' ..
|
||||
' LOADT t:tabpagevar.*' ..
|
||||
' LOADENV $ENVVAR.*' ..
|
||||
' LOADREG @z.*',
|
||||
res)
|
||||
@@ -79,6 +88,9 @@ def s:ScriptFuncStore()
|
||||
v:char = 'abc'
|
||||
s:scriptvar = 'sv'
|
||||
g:globalvar = 'gv'
|
||||
b:buffervar = 'bv'
|
||||
w:windowvar = 'wv'
|
||||
t:tabpagevar = 'tv'
|
||||
&tabstop = 8
|
||||
$ENVVAR = 'ev'
|
||||
@z = 'rv'
|
||||
@@ -99,6 +111,12 @@ def Test_disassemble_store()
|
||||
' STORES s:scriptvar in .*test_vim9_disassemble.vim.*' ..
|
||||
'g:globalvar = ''gv''.*' ..
|
||||
' STOREG g:globalvar.*' ..
|
||||
'b:buffervar = ''bv''.*' ..
|
||||
' STOREB b:buffervar.*' ..
|
||||
'w:windowvar = ''wv''.*' ..
|
||||
' STOREW w:windowvar.*' ..
|
||||
't:tabpagevar = ''tv''.*' ..
|
||||
' STORET t:tabpagevar.*' ..
|
||||
'&tabstop = 8.*' ..
|
||||
' STOREOPT &tabstop.*' ..
|
||||
'$ENVVAR = ''ev''.*' ..
|
||||
|
@@ -931,11 +931,6 @@ func Test_expr7_fails()
|
||||
call CheckDefFailure("echo l:somevar", 'E1075:')
|
||||
call CheckDefFailure("echo x:somevar", 'E1075:')
|
||||
|
||||
" TODO
|
||||
call CheckDefFailure("echo b:somevar", 'not supported yet')
|
||||
call CheckDefFailure("echo w:somevar", 'not supported yet')
|
||||
call CheckDefFailure("echo t:somevar", 'not supported yet')
|
||||
|
||||
call CheckDefExecFailure("let x = +g:astring", 'E1030:')
|
||||
call CheckDefExecFailure("let x = +g:ablob", 'E974:')
|
||||
call CheckDefExecFailure("let x = +g:alist", 'E745:')
|
||||
|
@@ -135,6 +135,38 @@ def Test_assignment()
|
||||
call CheckDefFailure(['v:errmsg += 123'], 'E1013:')
|
||||
enddef
|
||||
|
||||
def Test_assignment_local()
|
||||
" Test in a separated file in order not to the current buffer/window/tab is
|
||||
" changed.
|
||||
let script_lines: list<string> =<< trim END
|
||||
let b:existing = 'yes'
|
||||
let w:existing = 'yes'
|
||||
let t:existing = 'yes'
|
||||
|
||||
def Test_assignment_local_internal()
|
||||
b:newvar = 'new'
|
||||
assert_equal('new', b:newvar)
|
||||
assert_equal('yes', b:existing)
|
||||
b:existing = 'no'
|
||||
assert_equal('no', b:existing)
|
||||
|
||||
w:newvar = 'new'
|
||||
assert_equal('new', w:newvar)
|
||||
assert_equal('yes', w:existing)
|
||||
w:existing = 'no'
|
||||
assert_equal('no', w:existing)
|
||||
|
||||
t:newvar = 'new'
|
||||
assert_equal('new', t:newvar)
|
||||
assert_equal('yes', t:existing)
|
||||
t:existing = 'no'
|
||||
assert_equal('no', t:existing)
|
||||
enddef
|
||||
call Test_assignment_local_internal()
|
||||
END
|
||||
call CheckScriptSuccess(script_lines)
|
||||
enddef
|
||||
|
||||
def Test_assignment_default()
|
||||
|
||||
# Test default values.
|
||||
@@ -201,11 +233,17 @@ func Test_assignment_failure()
|
||||
call CheckDefFailure(['let @a = 5'], 'E1066:')
|
||||
|
||||
call CheckDefFailure(['let g:var = 5'], 'E1016:')
|
||||
call CheckDefFailure(['let w:var = 5'], 'E1079:')
|
||||
call CheckDefFailure(['let b:var = 5'], 'E1078:')
|
||||
call CheckDefFailure(['let t:var = 5'], 'E1080:')
|
||||
|
||||
call CheckDefFailure(['let anr = 4', 'anr ..= "text"'], 'E1019:')
|
||||
call CheckDefFailure(['let xnr += 4'], 'E1020:')
|
||||
|
||||
call CheckScriptFailure(['vim9script', 'def Func()', 'let dummy = s:notfound', 'enddef'], 'E1050:')
|
||||
" TODO: implement this error
|
||||
"call CheckScriptFailure(['vim9script', 'let svar = 123', 'unlet svar'], 'E1050:')
|
||||
"call CheckScriptFailure(['vim9script', 'let svar = 123', 'unlet s:svar'], 'E1050:')
|
||||
|
||||
call CheckDefFailure(['let var: list<string> = [123]'], 'expected list<string> but got list<number>')
|
||||
call CheckDefFailure(['let var: list<number> = ["xx"]'], 'expected list<number> but got list<string>')
|
||||
|
@@ -746,6 +746,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
600,
|
||||
/**/
|
||||
599,
|
||||
/**/
|
||||
|
@@ -20,6 +20,9 @@ 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_LOADB, // push b: variable isn_arg.string
|
||||
ISN_LOADW, // push w: variable isn_arg.string
|
||||
ISN_LOADT, // push t: variable isn_arg.string
|
||||
ISN_LOADS, // push s: variable isn_arg.loadstore
|
||||
ISN_LOADSCRIPT, // push script-local variable isn_arg.script.
|
||||
ISN_LOADOPT, // push option isn_arg.string
|
||||
@@ -29,6 +32,9 @@ 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_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
|
||||
ISN_STORES, // pop into script variable isn_arg.loadstore
|
||||
ISN_STORESCRIPT, // pop into script variable isn_arg.script
|
||||
ISN_STOREOPT, // pop into option isn_arg.string
|
||||
|
@@ -2235,18 +2235,21 @@ compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error)
|
||||
}
|
||||
else if (**arg == 'b')
|
||||
{
|
||||
semsg("Namespace b: not supported yet: %s", *arg);
|
||||
goto theend;
|
||||
// Buffer-local variables can be defined later, thus we don't check
|
||||
// if it exists, give error at runtime.
|
||||
res = generate_LOAD(cctx, ISN_LOADB, 0, name, &t_any);
|
||||
}
|
||||
else if (**arg == 'w')
|
||||
{
|
||||
semsg("Namespace w: not supported yet: %s", *arg);
|
||||
goto theend;
|
||||
// Window-local variables can be defined later, thus we don't check
|
||||
// if it exists, give error at runtime.
|
||||
res = generate_LOAD(cctx, ISN_LOADW, 0, name, &t_any);
|
||||
}
|
||||
else if (**arg == 't')
|
||||
{
|
||||
semsg("Namespace t: not supported yet: %s", *arg);
|
||||
goto theend;
|
||||
// Tabpage-local variables can be defined later, thus we don't
|
||||
// check if it exists, give error at runtime.
|
||||
res = generate_LOAD(cctx, ISN_LOADT, 0, name, &t_any);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3958,6 +3961,9 @@ typedef enum {
|
||||
dest_option,
|
||||
dest_env,
|
||||
dest_global,
|
||||
dest_buffer,
|
||||
dest_window,
|
||||
dest_tab,
|
||||
dest_vimvar,
|
||||
dest_script,
|
||||
dest_reg,
|
||||
@@ -4087,6 +4093,33 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
else if (STRNCMP(arg, "b:", 2) == 0)
|
||||
{
|
||||
dest = dest_buffer;
|
||||
if (is_decl)
|
||||
{
|
||||
semsg(_("E1078: Cannot declare a buffer variable: %s"), name);
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
else if (STRNCMP(arg, "w:", 2) == 0)
|
||||
{
|
||||
dest = dest_window;
|
||||
if (is_decl)
|
||||
{
|
||||
semsg(_("E1079: Cannot declare a window variable: %s"), name);
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
else if (STRNCMP(arg, "t:", 2) == 0)
|
||||
{
|
||||
dest = dest_tab;
|
||||
if (is_decl)
|
||||
{
|
||||
semsg(_("E1080: Cannot declare a tab variable: %s"), name);
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
else if (STRNCMP(arg, "v:", 2) == 0)
|
||||
{
|
||||
typval_T *vtv;
|
||||
@@ -4245,6 +4278,15 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
case dest_global:
|
||||
generate_LOAD(cctx, ISN_LOADG, 0, name + 2, type);
|
||||
break;
|
||||
case dest_buffer:
|
||||
generate_LOAD(cctx, ISN_LOADB, 0, name + 2, type);
|
||||
break;
|
||||
case dest_window:
|
||||
generate_LOAD(cctx, ISN_LOADW, 0, name + 2, type);
|
||||
break;
|
||||
case dest_tab:
|
||||
generate_LOAD(cctx, ISN_LOADT, 0, name + 2, type);
|
||||
break;
|
||||
case dest_script:
|
||||
compile_load_scriptvar(cctx,
|
||||
name + (name[1] == ':' ? 2 : 0), NULL, NULL, TRUE);
|
||||
@@ -4410,6 +4452,18 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
// include g: with the name, easier to execute that way
|
||||
generate_STORE(cctx, ISN_STOREG, 0, name);
|
||||
break;
|
||||
case dest_buffer:
|
||||
// include b: with the name, easier to execute that way
|
||||
generate_STORE(cctx, ISN_STOREB, 0, name);
|
||||
break;
|
||||
case dest_window:
|
||||
// include w: with the name, easier to execute that way
|
||||
generate_STORE(cctx, ISN_STOREW, 0, name);
|
||||
break;
|
||||
case dest_tab:
|
||||
// include t: with the name, easier to execute that way
|
||||
generate_STORE(cctx, ISN_STORET, 0, name);
|
||||
break;
|
||||
case dest_env:
|
||||
generate_STORE(cctx, ISN_STOREENV, 0, name + 1);
|
||||
break;
|
||||
@@ -6189,12 +6243,18 @@ delete_instr(isn_T *isn)
|
||||
case ISN_EXEC:
|
||||
case ISN_LOADENV:
|
||||
case ISN_LOADG:
|
||||
case ISN_LOADB:
|
||||
case ISN_LOADW:
|
||||
case ISN_LOADT:
|
||||
case ISN_LOADOPT:
|
||||
case ISN_MEMBER:
|
||||
case ISN_PUSHEXC:
|
||||
case ISN_PUSHS:
|
||||
case ISN_STOREENV:
|
||||
case ISN_STOREG:
|
||||
case ISN_STOREB:
|
||||
case ISN_STOREW:
|
||||
case ISN_STORET:
|
||||
case ISN_PUSHFUNC:
|
||||
vim_free(isn->isn_arg.string);
|
||||
break;
|
||||
|
@@ -446,6 +446,7 @@ store_var(char_u *name, typval_T *tv)
|
||||
restore_funccal();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Execute a function by "name".
|
||||
* This can be a builtin function, user function or a funcref.
|
||||
@@ -757,16 +758,42 @@ call_def_function(
|
||||
}
|
||||
break;
|
||||
|
||||
// load g: variable
|
||||
// load g:/b:/w:/t: variable
|
||||
case ISN_LOADG:
|
||||
case ISN_LOADB:
|
||||
case ISN_LOADW:
|
||||
case ISN_LOADT:
|
||||
{
|
||||
dictitem_T *di = find_var_in_ht(get_globvar_ht(), 0,
|
||||
iptr->isn_arg.string, TRUE);
|
||||
dictitem_T *di = NULL;
|
||||
hashtab_T *ht = NULL;
|
||||
char namespace;
|
||||
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 failed;
|
||||
}
|
||||
di = find_var_in_ht(ht, 0, iptr->isn_arg.string, TRUE);
|
||||
|
||||
if (di == NULL)
|
||||
{
|
||||
semsg(_("E121: Undefined variable: g:%s"),
|
||||
iptr->isn_arg.string);
|
||||
semsg(_("E121: Undefined variable: %c:%s"),
|
||||
namespace, iptr->isn_arg.string);
|
||||
goto failed;
|
||||
}
|
||||
else
|
||||
@@ -925,13 +952,34 @@ call_def_function(
|
||||
goto failed;
|
||||
break;
|
||||
|
||||
// store g: variable
|
||||
// store g:/b:/w:/t: variable
|
||||
case ISN_STOREG:
|
||||
case ISN_STOREB:
|
||||
case ISN_STOREW:
|
||||
case ISN_STORET:
|
||||
{
|
||||
dictitem_T *di;
|
||||
hashtab_T *ht;
|
||||
switch (iptr->isn_type)
|
||||
{
|
||||
case ISN_STOREG:
|
||||
ht = get_globvar_ht();
|
||||
break;
|
||||
case ISN_STOREB:
|
||||
ht = &curbuf->b_vars->dv_hashtab;
|
||||
break;
|
||||
case ISN_STOREW:
|
||||
ht = &curwin->w_vars->dv_hashtab;
|
||||
break;
|
||||
case ISN_STORET:
|
||||
ht = &curtab->tp_vars->dv_hashtab;
|
||||
break;
|
||||
default: // Cannot reach here
|
||||
goto failed;
|
||||
}
|
||||
|
||||
--ectx.ec_stack.ga_len;
|
||||
di = find_var_in_ht(get_globvar_ht(), 0,
|
||||
di = find_var_in_ht(ht, 0,
|
||||
iptr->isn_arg.string + 2, TRUE);
|
||||
if (di == NULL)
|
||||
store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
|
||||
@@ -1918,6 +1966,15 @@ ex_disassemble(exarg_T *eap)
|
||||
case ISN_LOADG:
|
||||
smsg("%4d LOADG g:%s", current, iptr->isn_arg.string);
|
||||
break;
|
||||
case ISN_LOADB:
|
||||
smsg("%4d LOADB b:%s", current, iptr->isn_arg.string);
|
||||
break;
|
||||
case ISN_LOADW:
|
||||
smsg("%4d LOADW w:%s", current, iptr->isn_arg.string);
|
||||
break;
|
||||
case ISN_LOADT:
|
||||
smsg("%4d LOADT t:%s", current, iptr->isn_arg.string);
|
||||
break;
|
||||
case ISN_LOADOPT:
|
||||
smsg("%4d LOADOPT %s", current, iptr->isn_arg.string);
|
||||
break;
|
||||
@@ -1943,6 +2000,15 @@ ex_disassemble(exarg_T *eap)
|
||||
case ISN_STOREG:
|
||||
smsg("%4d STOREG %s", current, iptr->isn_arg.string);
|
||||
break;
|
||||
case ISN_STOREB:
|
||||
smsg("%4d STOREB %s", current, iptr->isn_arg.string);
|
||||
break;
|
||||
case ISN_STOREW:
|
||||
smsg("%4d STOREW %s", current, iptr->isn_arg.string);
|
||||
break;
|
||||
case ISN_STORET:
|
||||
smsg("%4d STORET %s", current, iptr->isn_arg.string);
|
||||
break;
|
||||
case ISN_STORES:
|
||||
{
|
||||
scriptitem_T *si = SCRIPT_ITEM(
|
||||
|
Reference in New Issue
Block a user