0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

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)
This commit is contained in:
Bram Moolenaar
2020-12-22 21:19:39 +01:00
parent 3bdc90b7df
commit 89b474dd4f
5 changed files with 70 additions and 15 deletions

View File

@@ -738,14 +738,14 @@ ex_let(exarg_T *eap)
int first = TRUE; int first = TRUE;
int concat; int concat;
int has_assign; int has_assign;
int flags = eap->cmdidx == CMD_const ? ASSIGN_CONST : 0; int flags = 0;
int vim9script = in_vim9script(); int vim9script = in_vim9script();
if (eap->cmdidx == CMD_final && !vim9script) if (eap->cmdidx == CMD_final && !vim9script)
{ {
// In legacy Vim script ":final" is short for ":finally". // In legacy Vim script ":final" is short for ":finally".
ex_finally(eap); ex_finally(eap);
return; return;
} }
if (eap->cmdidx == CMD_let && vim9script) if (eap->cmdidx == CMD_let && vim9script)
{ {
@@ -756,7 +756,12 @@ ex_let(exarg_T *eap)
// In legacy Vim script ":const" works like ":final". // In legacy Vim script ":const" works like ":final".
eap->cmdidx = CMD_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) if (eap->arg == eap->cmd)
flags |= ASSIGN_NO_DECL; flags |= ASSIGN_NO_DECL;
@@ -909,7 +914,7 @@ ex_let_vars(
int copy, // copy values from "tv", don't move int copy, // copy values from "tv", don't move
int semicolon, // from skip_var_list() int semicolon, // from skip_var_list()
int var_count, // 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 *op)
{ {
char_u *arg = arg_start; char_u *arg = arg_start;
@@ -1264,7 +1269,7 @@ ex_let_one(
char_u *arg, // points to variable name char_u *arg, // points to variable name
typval_T *tv, // value to assign to variable typval_T *tv, // value to assign to variable
int copy, // copy value from "tv" 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 *endchars, // valid chars after variable name or NULL
char_u *op) // "+", "-", "." or NULL char_u *op) // "+", "-", "." or NULL
{ {
@@ -1277,6 +1282,7 @@ ex_let_one(
char_u *tofree = NULL; char_u *tofree = NULL;
if (in_vim9script() && (flags & ASSIGN_NO_DECL) == 0 if (in_vim9script() && (flags & ASSIGN_NO_DECL) == 0
&& (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
&& vim_strchr((char_u *)"$@&", *arg) != NULL) && vim_strchr((char_u *)"$@&", *arg) != NULL)
{ {
vim9_declare_error(arg); vim9_declare_error(arg);
@@ -1286,7 +1292,7 @@ ex_let_one(
// ":let $VAR = expr": Set environment variable. // ":let $VAR = expr": Set environment variable.
if (*arg == '$') if (*arg == '$')
{ {
if (flags & ASSIGN_CONST) if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
{ {
emsg(_("E996: Cannot lock an environment variable")); emsg(_("E996: Cannot lock an environment variable"));
return NULL; return NULL;
@@ -1338,7 +1344,7 @@ ex_let_one(
// ":let &g:option = expr": Set global option value. // ":let &g:option = expr": Set global option value.
else if (*arg == '&') else if (*arg == '&')
{ {
if (flags & ASSIGN_CONST) if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
{ {
emsg(_(e_const_option)); emsg(_(e_const_option));
return NULL; return NULL;
@@ -1422,7 +1428,7 @@ ex_let_one(
// ":let @r = expr": Set register contents. // ":let @r = expr": Set register contents.
else if (*arg == '@') else if (*arg == '@')
{ {
if (flags & ASSIGN_CONST) if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
{ {
emsg(_("E996: Cannot lock a register")); emsg(_("E996: Cannot lock a register"));
return NULL; return NULL;
@@ -3056,7 +3062,7 @@ set_var_const(
type_T *type, type_T *type,
typval_T *tv_arg, typval_T *tv_arg,
int copy, // make copy of value in "tv" 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 *tv = tv_arg;
typval_T bool_tv; typval_T bool_tv;
@@ -3077,6 +3083,7 @@ set_var_const(
if (vim9script if (vim9script
&& !is_script_local && !is_script_local
&& (flags & ASSIGN_NO_DECL) == 0 && (flags & ASSIGN_NO_DECL) == 0
&& (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
&& name[1] == ':') && name[1] == ':')
{ {
vim9_declare_error(name); vim9_declare_error(name);
@@ -3106,7 +3113,7 @@ set_var_const(
{ {
if ((di->di_flags & DI_FLAGS_RELOAD) == 0) if ((di->di_flags & DI_FLAGS_RELOAD) == 0)
{ {
if (flags & ASSIGN_CONST) if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
{ {
emsg(_(e_cannot_mod)); emsg(_(e_cannot_mod));
goto failed; goto failed;
@@ -3206,7 +3213,7 @@ set_var_const(
goto failed; goto failed;
} }
di->di_flags = DI_FLAGS_ALLOC; di->di_flags = DI_FLAGS_ALLOC;
if (flags & ASSIGN_CONST) if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
di->di_flags |= DI_FLAGS_LOCK; di->di_flags |= DI_FLAGS_LOCK;
// A Vim9 script-local variable is also added to sn_all_vars and // A Vim9 script-local variable is also added to sn_all_vars and

View File

@@ -1127,6 +1127,30 @@ def Test_var_declaration()
const FOO: number = 123 const FOO: number = 123
assert_equal(123, FOO) 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 var s:other: number
other = 1234 other = 1234
@@ -1150,6 +1174,12 @@ def Test_var_declaration()
unlet g:var_test unlet g:var_test
unlet g:var_prefixed unlet g:var_prefixed
unlet g:other_var unlet g:other_var
unlet g:FOO
unlet g:FOOS
unlet g:FLIST
unlet w:FOO
unlet w:FOOS
unlet w:FLIST
enddef enddef
def Test_var_declaration_fails() def Test_var_declaration_fails()
@@ -1159,6 +1189,22 @@ def Test_var_declaration_fails()
END END
CheckScriptFailure(lines, 'E1125:') 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 lines =<< trim END
vim9script vim9script
const var: string const var: string

View File

@@ -1032,7 +1032,7 @@ def Test_vim9script_call_fail_const()
call Change() call Change()
unlet g:Aconst unlet g:Aconst
END END
CheckScriptFailure(lines, 'E741: Value is locked: Aconst', 2) CheckScriptFailure(lines, 'E1122: Variable is locked: Aconst', 2)
enddef enddef
" Test that inside :function a Python function can be defined, :def is not " Test that inside :function a Python function can be defined, :def is not

View File

@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2194,
/**/ /**/
2193, 2193,
/**/ /**/

View File

@@ -2144,7 +2144,7 @@ typedef enum {
// Flags for assignment functions. // Flags for assignment functions.
#define ASSIGN_FINAL 1 // ":final" #define ASSIGN_FINAL 1 // ":final"
#define ASSIGN_CONST 2 // ":const" #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 "ex_cmds.h" // Ex command defines
#include "spell.h" // spell checking stuff #include "spell.h" // spell checking stuff