From b2cb6c8bbd215177ed05c1d952e7ef2ad8f7ef4b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 28 Mar 2021 20:38:34 +0200 Subject: [PATCH] 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. --- src/errors.h | 2 ++ src/testdir/test_vim9_cmd.vim | 38 ++++++++++++++++++++ src/version.c | 2 ++ src/vim9compile.c | 65 +++++++++++++++++++++++++++++------ 4 files changed, 97 insertions(+), 10 deletions(-) diff --git a/src/errors.h b/src/errors.h index cb0f84652d..e43cddb856 100644 --- 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 index bc4cfa6e16..3b479f31d5 100644 --- 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 index 1937de1217..602fdb622c 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2672, /**/ 2671, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index c1adb36c67..26d346f434 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -6707,6 +6707,58 @@ compile_unlet( return ret; } +/* + * 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". @@ -6714,16 +6766,9 @@ compile_unlet( 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; }