]> granicus.if.org Git - vim/commitdiff
patch 8.2.2672: Vim9: cannot use :lockvar and :unlockvar in compiled script v8.2.2672
authorBram Moolenaar <Bram@vim.org>
Sun, 28 Mar 2021 18:38:34 +0000 (20:38 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 28 Mar 2021 18:38:34 +0000 (20:38 +0200)
Problem:    Vim9: cannot use :lockvar and :unlockvar in compiled script.
Solution:   Implement locking support.

src/errors.h
src/testdir/test_vim9_cmd.vim
src/version.c
src/vim9compile.c

index cb0f84652d3b2cc016edf1006b52b2d46702a462..e43cddb8561f9a3a969e2856420085dbb8a36a4c 100644 (file)
@@ -391,3 +391,5 @@ EXTERN char e_misplaced_command_modifier[]
        INIT(= N_("E1176: Misplaced command modifier"));
 EXTERN char e_for_loop_on_str_not_supported[]
        INIT(= N_("E1177: For loop on %s not supported"));
+EXTERN char e_cannot_lock_unlock_local_variable[]
+       INIT(= N_("E1178: Cannot lock or unlock a local variable"));
index bc4cfa6e1633540c11de4be3fc17b4f2d6b5bf97..3b479f31d574e5546705ee8f465422b34f15f3c1 100644 (file)
@@ -1135,4 +1135,42 @@ def Test_windo_missing_endif()
   CheckDefExecFailure(lines, 'E171:', 1)
 enddef
 
+let s:theList = [1, 2, 3]
+
+def Test_lockvar()
+  s:theList[1] = 22
+  assert_equal([1, 22, 3], s:theList)
+  lockvar s:theList
+  assert_fails('theList[1] = 77', 'E741:')
+  unlockvar s:theList
+  s:theList[1] = 44
+  assert_equal([1, 44, 3], s:theList)
+
+  var lines =<< trim END
+      vim9script
+      var theList = [1, 2, 3]
+      def SetList()
+        theList[1] = 22
+        assert_equal([1, 22, 3], theList)
+        lockvar theList
+        theList[1] = 77
+      enddef
+      SetList()
+  END
+  CheckScriptFailure(lines, 'E1119', 4)
+
+  lines =<< trim END
+      var theList = [1, 2, 3]
+      lockvar theList
+  END
+  CheckDefFailure(lines, 'E1178', 2)
+
+  lines =<< trim END
+      var theList = [1, 2, 3]
+      unlockvar theList
+  END
+  CheckDefFailure(lines, 'E1178', 2)
+enddef
+
+
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
index 1937de1217dd066d06afa0bd19db96478a9ec875..602fdb622c2bbb56fbdcc453c45f3c30b32452f2 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2672,
 /**/
     2671,
 /**/
index c1adb36c67dc6a773e6b8af48137282a5931c176..26d346f4344323ec854c77ea3d45dbcfd5754314 100644 (file)
@@ -6708,22 +6708,67 @@ compile_unlet(
 }
 
 /*
- * compile "unlet var", "lock var" and "unlock var"
- * "arg" points to "var".
+ * Callback passed to ex_unletlock().
  */
-    static char_u *
-compile_unletlock(char_u *arg, exarg_T *eap, cctx_T *cctx)
+    static int
+compile_lock_unlock(
+    lval_T  *lvp,
+    char_u  *name_end,
+    exarg_T *eap,
+    int            deep UNUSED,
+    void    *coookie)
 {
-    char_u *p = arg;
+    cctx_T     *cctx = coookie;
+    int                cc = *name_end;
+    char_u     *p = lvp->ll_name;
+    int                ret = OK;
+    size_t     len;
+    char_u     *buf;
 
-    if (eap->cmdidx != CMD_unlet)
+    if (cctx->ctx_skip == SKIP_YES)
+       return OK;
+
+    // Cannot use :lockvar and :unlockvar on local variables.
+    if (p[1] != ':')
     {
-       emsg("Sorry, :lock and unlock not implemented yet");
-       return NULL;
+       char_u *end = skip_var_one(p, FALSE);
+
+       if (lookup_local(p, end - p, NULL, cctx) == OK)
+       {
+           emsg(_(e_cannot_lock_unlock_local_variable));
+           return FAIL;
+       }
     }
 
-    ex_unletlock(eap, p, 0, GLV_NO_AUTOLOAD | GLV_COMPILING,
-                                                         compile_unlet, cctx);
+    // Checking is done at runtime.
+    *name_end = NUL;
+    len = name_end - p + 20;
+    buf = alloc(len);
+    if (buf == NULL)
+       ret = FAIL;
+    else
+    {
+       vim_snprintf((char *)buf, len, "%s %s",
+               eap->cmdidx == CMD_lockvar ? "lockvar" : "unlockvar",
+               p);
+       ret = generate_EXEC(cctx, buf);
+
+       vim_free(buf);
+       *name_end = cc;
+    }
+    return ret;
+}
+
+/*
+ * compile "unlet var", "lock var" and "unlock var"
+ * "arg" points to "var".
+ */
+    static char_u *
+compile_unletlock(char_u *arg, exarg_T *eap, cctx_T *cctx)
+{
+    ex_unletlock(eap, arg, 0, GLV_NO_AUTOLOAD | GLV_COMPILING,
+           eap->cmdidx == CMD_unlet ? compile_unlet : compile_lock_unlock,
+           cctx);
     return eap->nextcmd == NULL ? (char_u *)"" : eap->nextcmd;
 }