# HG changeset patch # User Bram Moolenaar # Date 1616957106 -7200 # Node ID d0e86f1b34e711615051296673c1b17bb9e41786 # Parent f5ada7905e93644d52d9e7f7062812cc341c37a4 patch 8.2.2672: Vim9: cannot use :lockvar and :unlockvar in compiled script Commit: https://github.com/vim/vim/commit/b2cb6c8bbd215177ed05c1d952e7ef2ad8f7ef4b Author: Bram Moolenaar 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. diff --git a/src/errors.h b/src/errors.h --- 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")); diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim --- 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 diff --git a/src/version.c b/src/version.c --- 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, diff --git a/src/vim9compile.c b/src/vim9compile.c --- 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; }