# HG changeset patch # User Bram Moolenaar # Date 1595181604 -7200 # Node ID 5cb6e676defdaf987f5d08bc80c7cb5b2ec40853 # Parent 5f89f2a27c66ea1e168f28bd54b82f5723a0402a patch 8.2.1250: Vim9: cannot use the g:, b:, t: and w: namespaces Commit: https://github.com/vim/vim/commit/2f8ce0ae8a8247563be0a77a308130e767e0566e Author: Bram Moolenaar Date: Sun Jul 19 19:47:35 2020 +0200 patch 8.2.1250: Vim9: cannot use the g:, b:, t: and w: namespaces Problem: Vim9: cannot use the g:, b:, t: and w: namespaces. Solution: Add instructions to push a dict for the namespaces. (closes https://github.com/vim/vim/issues/6480) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -21,9 +21,13 @@ def s:ScriptFuncLoad(arg: string) echo v:version echo s:scriptvar echo g:globalvar + echo get(g:, "global") echo b:buffervar + echo get(b:, "buffer") echo w:windowvar + echo get(w:, "window") echo t:tabpagevar + echo get(t:, "tab") echo &tabstop echo $ENVVAR echo @z @@ -47,9 +51,25 @@ def Test_disassemble_load() ' LOADV v:version.*' .. ' LOADS s:scriptvar from .*test_vim9_disassemble.vim.*' .. ' LOADG g:globalvar.*' .. + 'echo get(g:, "global")\_s*' .. + '\d\+ LOAD g:\_s*' .. + '\d\+ PUSHS "global"\_s*' .. + '\d\+ BCALL get(argc 2).*' .. ' LOADB b:buffervar.*' .. + 'echo get(b:, "buffer")\_s*' .. + '\d\+ LOAD b:\_s*' .. + '\d\+ PUSHS "buffer"\_s*' .. + '\d\+ BCALL get(argc 2).*' .. ' LOADW w:windowvar.*' .. + 'echo get(w:, "window")\_s*' .. + '\d\+ LOAD w:\_s*' .. + '\d\+ PUSHS "window"\_s*' .. + '\d\+ BCALL get(argc 2).*' .. ' LOADT t:tabpagevar.*' .. + 'echo get(t:, "tab")\_s*' .. + '\d\+ LOAD t:\_s*' .. + '\d\+ PUSHS "tab"\_s*' .. + '\d\+ BCALL get(argc 2).*' .. ' LOADENV $ENVVAR.*' .. ' LOADREG @z.*', res) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -1345,6 +1345,32 @@ def Test_expr7_register() assert_equal('register a', @a) enddef +def Test_expr7_namespace() + g:some_var = 'some' + assert_equal('some', get(g:, 'some_var')) + assert_equal('some', get(g:, 'some_var', 'xxx')) + assert_equal('xxx', get(g:, 'no_var', 'xxx')) + unlet g:some_var + + b:some_var = 'some' + assert_equal('some', get(b:, 'some_var')) + assert_equal('some', get(b:, 'some_var', 'xxx')) + assert_equal('xxx', get(b:, 'no_var', 'xxx')) + unlet b:some_var + + w:some_var = 'some' + assert_equal('some', get(w:, 'some_var')) + assert_equal('some', get(w:, 'some_var', 'xxx')) + assert_equal('xxx', get(w:, 'no_var', 'xxx')) + unlet w:some_var + + t:some_var = 'some' + assert_equal('some', get(t:, 'some_var')) + assert_equal('some', get(t:, 'some_var', 'xxx')) + assert_equal('xxx', get(t:, 'no_var', 'xxx')) + unlet t:some_var +enddef + def Test_expr7_parens() # (expr) assert_equal(4, (6 * 4) / 6) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1250, +/**/ 1249, /**/ 1248, diff --git a/src/vim9.h b/src/vim9.h --- a/src/vim9.h +++ b/src/vim9.h @@ -26,6 +26,10 @@ typedef enum { 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_LOADGDICT, // push g: dict + ISN_LOADBDICT, // push b: dict + ISN_LOADWDICT, // push w: dict + ISN_LOADTDICT, // push t: dict ISN_LOADS, // push s: variable isn_arg.loadstore ISN_LOADOUTER, // push variable from outer scope isn_arg.number ISN_LOADSCRIPT, // push script-local variable isn_arg.script. diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -147,6 +147,7 @@ static char e_var_notfound[] = N_("E1001 static char e_syntax_at[] = N_("E1002: Syntax error at %s"); static char e_used_as_arg[] = N_("E1006: %s is used as an argument"); static char e_cannot_use_void[] = N_("E1031: Cannot use void value"); +static char e_namespace[] = N_("E1075: Namespace not supported: %s"); static void delete_def_function_contents(dfunc_T *dfunc); static void arg_type_mismatch(type_T *expected, type_T *actual, int argidx); @@ -2781,7 +2782,7 @@ generate_funcref(cctx_T *cctx, char_u *n compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error) { type_T *type; - char_u *name; + char_u *name = NULL; char_u *end = end_arg; int res = FAIL; int prev_called_emsg = called_emsg; @@ -2790,48 +2791,52 @@ compile_load(char_u **arg, char_u *end_a { // load namespaced variable if (end <= *arg + 2) - name = vim_strsave((char_u *)"[empty]"); - else - name = vim_strnsave(*arg + 2, end - (*arg + 2)); - if (name == NULL) - return FAIL; - - if (**arg == 'v') { - res = generate_LOADV(cctx, name, error); - } - else if (**arg == 'g') - { - // Global variables can be defined later, thus we don't check if it - // exists, give error at runtime. - res = generate_LOAD(cctx, ISN_LOADG, 0, name, &t_any); - } - else if (**arg == 's') - { - res = compile_load_scriptvar(cctx, name, NULL, NULL, error); - } - else if (**arg == 'b') - { - // 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') - { - // 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') - { - // 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); + isntype_T isn_type; + + switch (**arg) + { + case 'g': isn_type = ISN_LOADGDICT; break; + case 'w': isn_type = ISN_LOADWDICT; break; + case 't': isn_type = ISN_LOADTDICT; break; + case 'b': isn_type = ISN_LOADBDICT; break; + default: + semsg(_(e_namespace), *arg); + goto theend; + } + if (generate_instr_type(cctx, isn_type, &t_dict_any) == NULL) + goto theend; + res = OK; } else { - semsg("E1075: Namespace not supported: %s", *arg); - goto theend; + isntype_T isn_type = ISN_DROP; + + name = vim_strnsave(*arg + 2, end - (*arg + 2)); + if (name == NULL) + return FAIL; + + switch (**arg) + { + case 'v': res = generate_LOADV(cctx, name, error); + break; + case 's': res = compile_load_scriptvar(cctx, name, + NULL, NULL, error); + break; + case 'g': isn_type = ISN_LOADG; break; + case 'w': isn_type = ISN_LOADW; break; + case 't': isn_type = ISN_LOADT; break; + case 'b': isn_type = ISN_LOADB; break; + default: semsg(_(e_namespace), *arg); + goto theend; + } + if (isn_type != ISN_DROP) + { + // Global, Buffer-local, Window-local and Tabpage-local + // variables can be defined later, thus we don't check if it + // exists, give error at runtime. + res = generate_LOAD(cctx, isn_type, 0, name, &t_any); + } } } else @@ -7556,10 +7561,14 @@ delete_instr(isn_T *isn) case ISN_MEMBER: case ISN_JUMP: case ISN_LOAD: + case ISN_LOADBDICT: + case ISN_LOADGDICT: case ISN_LOADOUTER: + case ISN_LOADREG: case ISN_LOADSCRIPT: - case ISN_LOADREG: + case ISN_LOADTDICT: case ISN_LOADV: + case ISN_LOADWDICT: case ISN_NEGATENR: case ISN_NEWDICT: case ISN_NEWLIST: diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1089,6 +1089,7 @@ call_def_function( dictitem_T *di = NULL; hashtab_T *ht = NULL; char namespace; + switch (iptr->isn_type) { case ISN_LOADG: @@ -1128,6 +1129,33 @@ call_def_function( } break; + // load g:/b:/w:/t: namespace + case ISN_LOADGDICT: + case ISN_LOADBDICT: + case ISN_LOADWDICT: + case ISN_LOADTDICT: + { + dict_T *d = NULL; + + switch (iptr->isn_type) + { + case ISN_LOADG: d = get_globvar_dict(); break; + case ISN_LOADB: d = &curbuf->b_vars; break; + case ISN_LOADW: d = &curwin->w_vars; break; + case ISN_LOADT: d = &curtab->tp_vars; break; + default: // Cannot reach here + goto failed; + } + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) + goto failed; + tv = STACK_TV_BOT(0); + tv->v_type = VAR_DICT; + tv->v_lock = 0; + tv->vval.v_dict = d; + ++ectx.ec_stack.ga_len; + } + break; + // load &option case ISN_LOADOPT: { @@ -1166,6 +1194,7 @@ call_def_function( goto failed; tv = STACK_TV_BOT(0); tv->v_type = VAR_STRING; + tv->v_lock = 0; tv->vval.v_string = get_reg_contents( iptr->isn_arg.number, GREG_EXPR_SRC); ++ectx.ec_stack.ga_len; @@ -1411,6 +1440,7 @@ call_def_function( if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; tv = STACK_TV_BOT(0); + tv->v_lock = 0; ++ectx.ec_stack.ga_len; switch (iptr->isn_type) { @@ -1529,6 +1559,7 @@ call_def_function( ++ectx.ec_stack.ga_len; tv = STACK_TV_BOT(-1); tv->v_type = VAR_DICT; + tv->v_lock = 0; tv->vval.v_dict = dict; ++dict->dv_refcount; } @@ -1673,6 +1704,7 @@ call_def_function( ++ectx.ec_stack.ga_len; tv->vval.v_partial = pt; tv->v_type = VAR_PARTIAL; + tv->v_lock = 0; } break; @@ -1719,6 +1751,7 @@ call_def_function( // non-materialized range() list tv = STACK_TV_BOT(0); tv->v_type = VAR_NUMBER; + tv->v_lock = 0; tv->vval.v_number = list_find_nr( list, idxtv->vval.v_number, NULL); ++ectx.ec_stack.ga_len; @@ -1762,6 +1795,7 @@ call_def_function( tv = STACK_TV_BOT(0); ++ectx.ec_stack.ga_len; tv->v_type = VAR_STRING; + tv->v_lock = 0; tv->vval.v_string = vim_strsave( (char_u *)current_exception->value); break; @@ -2626,6 +2660,18 @@ ex_disassemble(exarg_T *eap) case ISN_LOADT: smsg("%4d LOADT t:%s", current, iptr->isn_arg.string); break; + case ISN_LOADGDICT: + smsg("%4d LOAD g:", current); + break; + case ISN_LOADBDICT: + smsg("%4d LOAD b:", current); + break; + case ISN_LOADWDICT: + smsg("%4d LOAD w:", current); + break; + case ISN_LOADTDICT: + smsg("%4d LOAD t:", current); + break; case ISN_LOADOPT: smsg("%4d LOADOPT %s", current, iptr->isn_arg.string); break;