summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-07-28 22:38:37 +0200
committerBram Moolenaar <Bram@vim.org>2020-07-28 22:38:37 +0200
commitb5ed266037dea49024e00c4e1f9c89f3a9ebaa60 (patch)
tree7c7468a10b0991deece40bfedac43947fcc9b45a /src
parent066b12e36c32a87725303c0f71e968eb3f9a9f32 (diff)
downloadvim-git-b5ed266037dea49024e00c4e1f9c89f3a9ebaa60.tar.gz
patch 8.2.1313: Vim9 script: cannot assign to environment variablev8.2.1313
Problem: Vim9 script: cannot assign to environment variable. Solution: Recognize environment variable assignment. (closes #6548) Also options and registers.
Diffstat (limited to 'src')
-rw-r--r--src/ex_docmd.c148
-rw-r--r--src/testdir/test_vim9_script.vim25
-rw-r--r--src/version.c2
3 files changed, 108 insertions, 67 deletions
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 6a2e91c9f..536850edc 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -1710,7 +1710,7 @@ do_one_cmd(
char_u *cmd;
int starts_with_colon = FALSE;
#ifdef FEAT_EVAL
- int starts_with_quote;
+ int may_have_range;
int vim9script = in_vim9script();
#endif
@@ -1773,8 +1773,9 @@ do_one_cmd(
*/
cmd = ea.cmd;
#ifdef FEAT_EVAL
- starts_with_quote = vim9script && !starts_with_colon && *ea.cmd == '\'';
- if (!starts_with_quote)
+ // In Vim9 script a colon is required before the range.
+ may_have_range = !vim9script || starts_with_colon;
+ if (may_have_range)
#endif
ea.cmd = skip_range(ea.cmd, NULL);
if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL)
@@ -1783,7 +1784,10 @@ do_one_cmd(
#ifdef FEAT_EVAL
if (vim9script && !starts_with_colon)
{
- if (ea.cmd > cmd)
+ if (ea.cmd == cmd + 1 && *cmd == '$')
+ // should be "$VAR = val"
+ --ea.cmd;
+ else if (ea.cmd > cmd)
{
emsg(_(e_colon_required));
goto doend;
@@ -1876,7 +1880,7 @@ do_one_cmd(
ea.cmd = cmd;
#ifdef FEAT_EVAL
- if (!starts_with_quote)
+ if (may_have_range)
#endif
if (parse_cmd_address(&ea, &errormsg, FALSE) == FAIL)
goto doend;
@@ -3267,80 +3271,90 @@ find_ex_command(
* "lvar = value", "lvar(arg)", "[1, 2 3]->Func()"
*/
p = eap->cmd;
- if (lookup != NULL && (vim_strchr((char_u *)"{('[", *p) != NULL
- || ((p = to_name_const_end(eap->cmd)) > eap->cmd
- && *p != NUL)))
+ if (lookup != NULL)
{
- int oplen;
- int heredoc;
+ // Skip over first char for "&opt = val", "$ENV = val" and "@r = val".
+ char_u *pskip = (*eap->cmd == '&' || *eap->cmd == '$'
+ || *eap->cmd == '@') ? eap->cmd + 1 : eap->cmd;
- if (
- // "(..." is an expression.
- // "funcname(" is always a function call.
- *p == '('
- || (p == eap->cmd
- ? (
- // "{..." is an dict expression.
- *eap->cmd == '{'
- // "'string'->func()" is an expression.
- || *eap->cmd == '\''
- // "g:varname" is an expression.
- || eap->cmd[1] == ':'
- )
- : (
- // "varname[]" is an expression.
- *p == '['
- // "varname->func()" is an expression.
- || (*p == '-' && p[1] == '>')
- // "varname.expr" is an expression.
- || (*p == '.' && ASCII_ISALPHA(p[1]))
- )))
- {
- eap->cmdidx = CMD_eval;
- return eap->cmd;
- }
-
- // "[...]->Method()" is a list expression, but "[a, b] = Func()" is
- // an assignment.
- // If there is no line break inside the "[...]" then "p" is advanced to
- // after the "]" by to_name_const_end(): check if a "=" follows.
- // If "[...]" has a line break "p" still points at the "[" and it can't
- // be an assignment.
- if (*eap->cmd == '[')
- {
- p = to_name_const_end(eap->cmd);
- if (p == eap->cmd || *skipwhite(p) != '=')
+ if (vim_strchr((char_u *)"{('[", *p) != NULL
+ || ((p = to_name_const_end(pskip)) > eap->cmd && *p != NUL))
+ {
+ int oplen;
+ int heredoc;
+
+ if (
+ // "(..." is an expression.
+ // "funcname(" is always a function call.
+ *p == '('
+ || (p == eap->cmd
+ ? (
+ // "{..." is an dict expression.
+ *eap->cmd == '{'
+ // "'string'->func()" is an expression.
+ || *eap->cmd == '\''
+ // "g:varname" is an expression.
+ || eap->cmd[1] == ':'
+ )
+ : (
+ // "varname[]" is an expression.
+ *p == '['
+ // "varname->func()" is an expression.
+ || (*p == '-' && p[1] == '>')
+ // "varname.expr" is an expression.
+ || (*p == '.' && ASCII_ISALPHA(p[1]))
+ )))
{
eap->cmdidx = CMD_eval;
return eap->cmd;
}
- if (p > eap->cmd && *skipwhite(p) == '=')
+
+ // "[...]->Method()" is a list expression, but "[a, b] = Func()" is
+ // an assignment.
+ // If there is no line break inside the "[...]" then "p" is
+ // advanced to after the "]" by to_name_const_end(): check if a "="
+ // follows.
+ // If "[...]" has a line break "p" still points at the "[" and it
+ // can't be an assignment.
+ if (*eap->cmd == '[')
{
- eap->cmdidx = CMD_let;
- return eap->cmd;
+ p = to_name_const_end(eap->cmd);
+ if (p == eap->cmd || *skipwhite(p) != '=')
+ {
+ eap->cmdidx = CMD_eval;
+ return eap->cmd;
+ }
+ if (p > eap->cmd && *skipwhite(p) == '=')
+ {
+ eap->cmdidx = CMD_let;
+ return eap->cmd;
+ }
}
- }
- // Recognize an assignment if we recognize the variable name:
- // "g:var = expr"
- // "var = expr" where "var" is a local var name.
- oplen = assignment_len(skipwhite(p), &heredoc);
- if (oplen > 0)
- {
- if (((p - eap->cmd) > 2 && eap->cmd[1] == ':')
- || lookup(eap->cmd, p - eap->cmd, cctx) != NULL)
+ // Recognize an assignment if we recognize the variable name:
+ // "g:var = expr"
+ // "var = expr" where "var" is a local var name.
+ oplen = assignment_len(skipwhite(p), &heredoc);
+ if (oplen > 0)
{
- eap->cmdidx = CMD_let;
- return eap->cmd;
+ if (((p - eap->cmd) > 2 && eap->cmd[1] == ':')
+ || *eap->cmd == '&'
+ || *eap->cmd == '$'
+ || *eap->cmd == '@'
+ || lookup(eap->cmd, p - eap->cmd, cctx) != NULL)
+ {
+ eap->cmdidx = CMD_let;
+ return eap->cmd;
+ }
}
- }
- // Recognize using a type for a w:, b:, t: or g: variable:
- // "w:varname: number = 123".
- if (eap->cmd[1] == ':' && *p == ':')
- {
- eap->cmdidx = CMD_eval;
- return eap->cmd;
+ // Recognize using a type for a w:, b:, t: or g: variable:
+ // "w:varname: number = 123".
+ if (eap->cmd[1] == ':' && *p == ':')
+ {
+ eap->cmdidx = CMD_eval;
+ return eap->cmd;
+ }
}
}
#endif
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 379245f39..427e91238 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -61,6 +61,14 @@ def Test_assignment()
assert_equal('foobar', $ENVVAR)
$ENVVAR = ''
+ let lines =<< trim END
+ vim9script
+ $ENVVAR = 'barfoo'
+ assert_equal('barfoo', $ENVVAR)
+ $ENVVAR = ''
+ END
+ call CheckScriptSuccess(lines)
+
s:appendToMe ..= 'yyy'
assert_equal('xxxyyy', s:appendToMe)
s:addToMe += 222
@@ -80,6 +88,15 @@ def Test_assignment()
set ts=10
&ts %= 4
assert_equal(2, &ts)
+
+ lines =<< trim END
+ vim9script
+ &ts = 6
+ &ts += 3
+ assert_equal(9, &ts)
+ END
+ call CheckScriptSuccess(lines)
+
call CheckDefFailure(['&notex += 3'], 'E113:')
call CheckDefFailure(['&ts ..= "xxx"'], 'E1019:')
call CheckDefFailure(['&ts = [7]'], 'E1013:')
@@ -106,6 +123,14 @@ def Test_assignment()
call CheckDefFailure(['@a += "more"'], 'E1013:')
call CheckDefFailure(['@a += 123'], 'E1013:')
+ lines =<< trim END
+ vim9script
+ @c = 'areg'
+ @c ..= 'add'
+ assert_equal('aregadd', @c)
+ END
+ call CheckScriptSuccess(lines)
+
v:errmsg = 'none'
v:errmsg ..= 'again'
assert_equal('noneagain', v:errmsg)
diff --git a/src/version.c b/src/version.c
index 26bd7ac65..fce921888 100644
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1313,
+/**/
1312,
/**/
1311,