]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.2162: Vim9: Cannot load or store autoload variables v8.2.2162
authorBram Moolenaar <Bram@vim.org>
Sat, 19 Dec 2020 15:30:44 +0000 (16:30 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 19 Dec 2020 15:30:44 +0000 (16:30 +0100)
Problem:    Vim9: Cannot load or store autoload variables.
Solution:   Add ISN_LOADAUTO and ISN_STOREAUTO. (closes #7485)

src/dict.c
src/eval.c
src/evalvars.c
src/proto/evalvars.pro
src/testdir/test_vim9_disassemble.vim
src/testdir/test_vim9_script.vim
src/version.c
src/vim9.h
src/vim9compile.c
src/vim9execute.c

index 051ba2f6ece00a6bc843efd415464a3993b810f3..5abb9964ae6180ec11bc35b016a217318f648c15 100644 (file)
@@ -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)
index 06c6adaf852f9388af4c18bf6fcbc0f4f06e7c62..496e20875624e16acd27cf44933b31b6a39eff96 100644 (file)
@@ -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)
index fde80d750d169ea364c352ad3e5c040f185e4d92..654eeff23086c957ffbf5155e8c1e17a5587f0a8 100644 (file)
@@ -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;
index 0449ea57aea17eb30e1becf0272713e79e920212..4c9d64582302f1dbb39fc588c9360799a2a25f97 100644 (file)
@@ -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);
index 7ea1491e6332b1621bd6f8a9261608365d1cb16d..d936bc29a408e3820c96cab5bb43738f48b43a8a 100644 (file)
@@ -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''.*' ..
index 2f651cd33cf4cbc9a0b3771587c0f33bf9adff78..5949acbc606b6a7e7e181367eb5a645492a89b85 100644 (file)
@@ -2779,8 +2779,32 @@ 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()
@@ -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()
index 9d2632b09f6c1dde80ce10d902a68f20c4706ae7..5ea062d05b1459ef861969832e3550d0264b291a 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2162,
 /**/
     2161,
 /**/
index 26b208025d868fda75611090921411ec7ae83ee8..26307c2707ae06259d0440c58e4be546f5fa12b4 100644 (file)
@@ -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
index 207ceb4eaccdb2e279895b2e5549454cd81e0ca6..c584918801dde2c1fcb3a206573332ce1bbe9f0c 100644 (file)
@@ -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:
index 4fd62ce9ed971d0078a531d9a42166d9add5af10..7e5a1dea3792e9e7b6abd8a2dd48010763ffe677 100644 (file)
@@ -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;