changeset 24262:d0e86f1b34e7 v8.2.2672

patch 8.2.2672: Vim9: cannot use :lockvar and :unlockvar in compiled script Commit: https://github.com/vim/vim/commit/b2cb6c8bbd215177ed05c1d952e7ef2ad8f7ef4b Author: Bram Moolenaar <Bram@vim.org> Date: Sun Mar 28 20:38:34 2021 +0200 patch 8.2.2672: Vim9: cannot use :lockvar and :unlockvar in compiled script Problem: Vim9: cannot use :lockvar and :unlockvar in compiled script. Solution: Implement locking support.
author Bram Moolenaar <Bram@vim.org>
date Sun, 28 Mar 2021 20:45:06 +0200
parents f5ada7905e93
children 7a463b5a2316
files src/errors.h src/testdir/test_vim9_cmd.vim src/version.c src/vim9compile.c
diffstat 4 files changed, 97 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/errors.h
+++ b/src/errors.h
@@ -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"));
--- a/src/testdir/test_vim9_cmd.vim
+++ b/src/testdir/test_vim9_cmd.vim
@@ -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
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2672,
+/**/
     2671,
 /**/
     2670,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -6708,22 +6708,67 @@ compile_unlet(
 }
 
 /*
+ * Callback passed to ex_unletlock().
+ */
+    static int
+compile_lock_unlock(
+    lval_T  *lvp,
+    char_u  *name_end,
+    exarg_T *eap,
+    int	    deep UNUSED,
+    void    *coookie)
+{
+    cctx_T	*cctx = coookie;
+    int		cc = *name_end;
+    char_u	*p = lvp->ll_name;
+    int		ret = OK;
+    size_t	len;
+    char_u	*buf;
+
+    if (cctx->ctx_skip == SKIP_YES)
+	return OK;
+
+    // Cannot use :lockvar and :unlockvar on local variables.
+    if (p[1] != ':')
+    {
+	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;
+	}
+    }
+
+    // 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)
 {
-    char_u *p = arg;
-
-    if (eap->cmdidx != CMD_unlet)
-    {
-	emsg("Sorry, :lock and unlock not implemented yet");
-	return NULL;
-    }
-
-    ex_unletlock(eap, p, 0, GLV_NO_AUTOLOAD | GLV_COMPILING,
-							  compile_unlet, 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;
 }