Patch 8.2.0600
Problem:    Vim9: cannot read or write w:, t: and b: variables.
Solution:   Implement load and store for w:, t: and b: variables.
            (closes #5950) 
Files:      src/testdir/test_vim9_disassemble.vim,
            src/testdir/test_vim9_expr.vim, src/testdir/test_vim9_script.vim,
            src/vim9.h, src/vim9compile.c, src/vim9execute.c


*** ../vim-8.2.0599/src/testdir/test_vim9_disassemble.vim       2020-04-18 
19:53:24.535912281 +0200
--- src/testdir/test_vim9_disassemble.vim       2020-04-19 14:19:23.685767255 
+0200
***************
*** 8,13 ****
--- 8,16 ----
  
  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,22 ****
--- 20,28 ----
    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,44 ****
--- 45,53 ----
          ' 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,84 ****
--- 88,96 ----
    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,104 ****
--- 111,122 ----
          ' 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''.*' ..
*** ../vim-8.2.0599/src/testdir/test_vim9_expr.vim      2020-04-13 
17:20:56.174130307 +0200
--- src/testdir/test_vim9_expr.vim      2020-04-19 14:19:23.685767255 +0200
***************
*** 931,941 ****
    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:')
--- 931,936 ----
*** ../vim-8.2.0599/src/testdir/test_vim9_script.vim    2020-04-18 
19:53:24.535912281 +0200
--- src/testdir/test_vim9_script.vim    2020-04-19 14:30:18.184264079 +0200
***************
*** 135,140 ****
--- 135,172 ----
    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,211 ****
--- 233,249 ----
    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>')
*** ../vim-8.2.0599/src/vim9.h  2020-04-09 21:08:06.298505479 +0200
--- src/vim9.h  2020-04-19 14:19:23.685767255 +0200
***************
*** 20,25 ****
--- 20,28 ----
      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,34 ****
--- 32,40 ----
      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
*** ../vim-8.2.0599/src/vim9compile.c   2020-04-18 19:53:24.531912284 +0200
--- src/vim9compile.c   2020-04-19 14:19:23.685767255 +0200
***************
*** 2235,2252 ****
        }
        else if (**arg == 'b')
        {
!           semsg("Namespace b: not supported yet: %s", *arg);
!           goto theend;
        }
        else if (**arg == 'w')
        {
!           semsg("Namespace w: not supported yet: %s", *arg);
!           goto theend;
        }
        else if (**arg == 't')
        {
!           semsg("Namespace t: not supported yet: %s", *arg);
!           goto theend;
        }
        else
        {
--- 2235,2255 ----
        }
        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);
        }
        else
        {
***************
*** 3958,3963 ****
--- 3961,3969 ----
      dest_option,
      dest_env,
      dest_global,
+     dest_buffer,
+     dest_window,
+     dest_tab,
      dest_vimvar,
      dest_script,
      dest_reg,
***************
*** 4087,4092 ****
--- 4093,4125 ----
                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,4250 ****
--- 4278,4292 ----
                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,4415 ****
--- 4452,4469 ----
            // 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,6200 ****
--- 6243,6260 ----
        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;
*** ../vim-8.2.0599/src/vim9execute.c   2020-04-18 19:53:24.531912284 +0200
--- src/vim9execute.c   2020-04-19 14:19:23.685767255 +0200
***************
*** 446,451 ****
--- 446,452 ----
      restore_funccal();
  }
  
+ 
  /*
   * Execute a function by "name".
   * This can be a builtin function, user function or a funcref.
***************
*** 757,772 ****
                }
                break;
  
!           // load g: variable
            case ISN_LOADG:
!               {
!                   dictitem_T *di = find_var_in_ht(get_globvar_ht(), 0,
!                                                  iptr->isn_arg.string, TRUE);
  
                    if (di == NULL)
                    {
!                       semsg(_("E121: Undefined variable: g:%s"),
!                                                        iptr->isn_arg.string);
                        goto failed;
                    }
                    else
--- 758,799 ----
                }
                break;
  
!           // load g:/b:/w:/t: variable
            case ISN_LOADG:
!           case ISN_LOADB:
!           case ISN_LOADW:
!           case ISN_LOADT:
!               {
!                   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: %c:%s"),
!                                            namespace, iptr->isn_arg.string);
                        goto failed;
                    }
                    else
***************
*** 925,937 ****
                    goto failed;
                break;
  
!           // store g: variable
            case ISN_STOREG:
                {
                    dictitem_T *di;
  
                    --ectx.ec_stack.ga_len;
!                   di = find_var_in_ht(get_globvar_ht(), 0,
                                               iptr->isn_arg.string + 2, TRUE);
                    if (di == NULL)
                        store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
--- 952,985 ----
                    goto failed;
                break;
  
!           // 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(ht, 0,
                                               iptr->isn_arg.string + 2, TRUE);
                    if (di == NULL)
                        store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
***************
*** 1918,1923 ****
--- 1966,1980 ----
            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,1948 ****
--- 2000,2014 ----
            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(
*** ../vim-8.2.0599/src/version.c       2020-04-19 14:02:22.427687032 +0200
--- src/version.c       2020-04-19 14:21:27.801488599 +0200
***************
*** 748,749 ****
--- 748,751 ----
  {   /* Add new patch number below this line */
+ /**/
+     600,
  /**/

-- 
The only way the average employee can speak to an executive is by taking a
second job as a golf caddie.
                                (Scott Adams - The Dilbert principle)

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202004191241.03JCfNUL003247%40masaka.moolenaar.net.

Raspunde prin e-mail lui