From 89b474dd4f0de878b4c48eeb9e223f0c22ee1442 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Dec 2020 21:19:39 +0100 Subject: patch 8.2.2194: Vim9: cannot use :const or :final at the script level Problem: Vim9: cannot use :const or :final at the script level. Solution: Support using :const and :final. (closes #7526) --- src/evalvars.c | 33 ++++++++++++++++------------ src/testdir/test_vim9_assign.vim | 46 ++++++++++++++++++++++++++++++++++++++++ src/testdir/test_vim9_func.vim | 2 +- src/version.c | 2 ++ src/vim.h | 2 +- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/evalvars.c b/src/evalvars.c index ec3f508ed3..7c4cc7a1a8 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -738,14 +738,14 @@ ex_let(exarg_T *eap) int first = TRUE; int concat; int has_assign; - int flags = eap->cmdidx == CMD_const ? ASSIGN_CONST : 0; + int flags = 0; int vim9script = in_vim9script(); if (eap->cmdidx == CMD_final && !vim9script) { - // In legacy Vim script ":final" is short for ":finally". - ex_finally(eap); - return; + // In legacy Vim script ":final" is short for ":finally". + ex_finally(eap); + return; } if (eap->cmdidx == CMD_let && vim9script) { @@ -756,7 +756,12 @@ ex_let(exarg_T *eap) // In legacy Vim script ":const" works like ":final". eap->cmdidx = CMD_final; - // detect Vim9 assignment without ":let" or ":const" + if (eap->cmdidx == CMD_const) + flags |= ASSIGN_CONST; + else if (eap->cmdidx == CMD_final) + flags |= ASSIGN_FINAL; + + // Vim9 assignment without ":let", ":const" or ":final" if (eap->arg == eap->cmd) flags |= ASSIGN_NO_DECL; @@ -909,7 +914,7 @@ ex_let_vars( int copy, // copy values from "tv", don't move int semicolon, // from skip_var_list() int var_count, // from skip_var_list() - int flags, // ASSIGN_CONST, ASSIGN_NO_DECL + int flags, // ASSIGN_FINAL, ASSIGN_CONST, ASSIGN_NO_DECL char_u *op) { char_u *arg = arg_start; @@ -1264,7 +1269,7 @@ ex_let_one( char_u *arg, // points to variable name typval_T *tv, // value to assign to variable int copy, // copy value from "tv" - int flags, // ASSIGN_CONST, ASSIGN_NO_DECL + int flags, // ASSIGN_CONST, ASSIGN_FINAL, ASSIGN_NO_DECL char_u *endchars, // valid chars after variable name or NULL char_u *op) // "+", "-", "." or NULL { @@ -1277,6 +1282,7 @@ ex_let_one( char_u *tofree = NULL; if (in_vim9script() && (flags & ASSIGN_NO_DECL) == 0 + && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0 && vim_strchr((char_u *)"$@&", *arg) != NULL) { vim9_declare_error(arg); @@ -1286,7 +1292,7 @@ ex_let_one( // ":let $VAR = expr": Set environment variable. if (*arg == '$') { - if (flags & ASSIGN_CONST) + if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_("E996: Cannot lock an environment variable")); return NULL; @@ -1338,7 +1344,7 @@ ex_let_one( // ":let &g:option = expr": Set global option value. else if (*arg == '&') { - if (flags & ASSIGN_CONST) + if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_(e_const_option)); return NULL; @@ -1422,7 +1428,7 @@ ex_let_one( // ":let @r = expr": Set register contents. else if (*arg == '@') { - if (flags & ASSIGN_CONST) + if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_("E996: Cannot lock a register")); return NULL; @@ -3056,7 +3062,7 @@ set_var_const( type_T *type, typval_T *tv_arg, int copy, // make copy of value in "tv" - int flags) // ASSIGN_CONST, ASSIGN_NO_DECL + int flags) // ASSIGN_CONST, ASSIGN_FINAL, ASSIGN_NO_DECL { typval_T *tv = tv_arg; typval_T bool_tv; @@ -3077,6 +3083,7 @@ set_var_const( if (vim9script && !is_script_local && (flags & ASSIGN_NO_DECL) == 0 + && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0 && name[1] == ':') { vim9_declare_error(name); @@ -3106,7 +3113,7 @@ set_var_const( { if ((di->di_flags & DI_FLAGS_RELOAD) == 0) { - if (flags & ASSIGN_CONST) + if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_(e_cannot_mod)); goto failed; @@ -3206,7 +3213,7 @@ set_var_const( goto failed; } di->di_flags = DI_FLAGS_ALLOC; - if (flags & ASSIGN_CONST) + if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) di->di_flags |= DI_FLAGS_LOCK; // A Vim9 script-local variable is also added to sn_all_vars and diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index bfc2d20de8..d5e1b33378 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -1127,6 +1127,30 @@ def Test_var_declaration() const FOO: number = 123 assert_equal(123, FOO) + const FOOS = 'foos' + assert_equal('foos', FOOS) + final FLIST = [1] + assert_equal([1], FLIST) + FLIST[0] = 11 + assert_equal([11], FLIST) + + const g:FOO: number = 321 + assert_equal(321, g:FOO) + const g:FOOS = 'gfoos' + assert_equal('gfoos', g:FOOS) + final g:FLIST = [2] + assert_equal([2], g:FLIST) + g:FLIST[0] = 22 + assert_equal([22], g:FLIST) + + const w:FOO: number = 46 + assert_equal(46, w:FOO) + const w:FOOS = 'wfoos' + assert_equal('wfoos', w:FOOS) + final w:FLIST = [3] + assert_equal([3], w:FLIST) + w:FLIST[0] = 33 + assert_equal([33], w:FLIST) var s:other: number other = 1234 @@ -1150,6 +1174,12 @@ def Test_var_declaration() unlet g:var_test unlet g:var_prefixed unlet g:other_var + unlet g:FOO + unlet g:FOOS + unlet g:FLIST + unlet w:FOO + unlet w:FOOS + unlet w:FLIST enddef def Test_var_declaration_fails() @@ -1159,6 +1189,22 @@ def Test_var_declaration_fails() END CheckScriptFailure(lines, 'E1125:') + lines =<< trim END + vim9script + const g:constvar = 'string' + g:constvar = 'xx' + END + CheckScriptFailure(lines, 'E741:') + unlet g:constvar + + lines =<< trim END + vim9script + final w:finalvar = [9] + w:finalvar = [8] + END + CheckScriptFailure(lines, 'E1122:') + unlet w:finalvar + lines =<< trim END vim9script const var: string diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index bdced0257b..749b8e8428 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -1032,7 +1032,7 @@ def Test_vim9script_call_fail_const() call Change() unlet g:Aconst END - CheckScriptFailure(lines, 'E741: Value is locked: Aconst', 2) + CheckScriptFailure(lines, 'E1122: Variable is locked: Aconst', 2) enddef " Test that inside :function a Python function can be defined, :def is not diff --git a/src/version.c b/src/version.c index 73a80aaf96..d4ca3c42a0 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 */ +/**/ + 2194, /**/ 2193, /**/ diff --git a/src/vim.h b/src/vim.h index ebd7db441e..1dedd81413 100644 --- a/src/vim.h +++ b/src/vim.h @@ -2144,7 +2144,7 @@ typedef enum { // Flags for assignment functions. #define ASSIGN_FINAL 1 // ":final" #define ASSIGN_CONST 2 // ":const" -#define ASSIGN_NO_DECL 4 // "name = expr" without ":let" or ":const" +#define ASSIGN_NO_DECL 4 // "name = expr" without ":let"/":const"/":final" #include "ex_cmds.h" // Ex command defines #include "spell.h" // spell checking stuff -- cgit v1.2.3