summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-04-24 19:08:24 +0200
committerBram Moolenaar <Bram@vim.org>2021-04-24 19:08:24 +0200
commitbdc0f1c6986e5d64f647e0924a4de795b47c549a (patch)
treed314ca4f02d7e8e13072ebef2ed4ba92be403083
parent96cf4ba8fb96e5778192d2dab7458b9a7da0a49d (diff)
patch 8.2.2806: Vim9: using "++nr" as a command might not workv8.2.2806
Problem: Vim9: using "++nr" as a command might not work. Solution: Do not recognize "++" and "--" in a following line as addition or subtraction.
-rw-r--r--src/eval.c3
-rw-r--r--src/ex_cmdidxs.h2
-rw-r--r--src/ex_cmds.h8
-rw-r--r--src/ex_docmd.c7
-rw-r--r--src/proto/vim9script.pro1
-rw-r--r--src/testdir/test_vim9_assign.vim16
-rw-r--r--src/testdir/test_vim9_expr.vim13
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c50
-rw-r--r--src/vim9script.c22
10 files changed, 97 insertions, 27 deletions
diff --git a/src/eval.c b/src/eval.c
index fbf4f57a52..97a00f759e 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2856,12 +2856,15 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
// "." is only string concatenation when scriptversion is 1
// "+=", "-=" and "..=" are assignments
+ // "++" and "--" on the next line are a separate command.
p = eval_next_non_blank(*arg, evalarg, &getnext);
op = *p;
concat = op == '.' && (*(p + 1) == '.' || current_sctx.sc_version < 2);
if ((op != '+' && op != '-' && !concat) || p[1] == '='
|| (p[1] == '.' && p[2] == '='))
break;
+ if (getnext && (op == '+' || op == '-') && p[0] == p[1])
+ break;
evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
oplen = (concat && p[1] == '.') ? 2 : 1;
diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h
index 0d148d7d44..2696128af7 100644
--- a/src/ex_cmdidxs.h
+++ b/src/ex_cmdidxs.h
@@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] =
/* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
-static const int command_count = 577;
+static const int command_count = 579;
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index 819cf732c8..aee2e6f72e 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -1846,6 +1846,14 @@ EXCMD(CMD_X, "X", ex_X,
EX_TRLBAR,
ADDR_NONE),
+// Commands that are recognized only in find_ex_command().
+EXCMD(CMD_increment, "++", ex_incdec,
+ EX_EXTRA|EX_NOTRLCOM|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
+ ADDR_NONE),
+EXCMD(CMD_decrement, "--", ex_incdec,
+ EX_EXTRA|EX_NOTRLCOM|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
+ ADDR_NONE),
+
#undef EXCMD
#ifndef DO_DECLARE_EXCMD
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 0d87a89440..85fecbbbf1 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -3531,6 +3531,13 @@ find_ex_command(
eap->cmdidx = CMD_eval;
return eap->cmd;
}
+
+ // Check for "++nr" and "--nr".
+ if (p == eap->cmd && p[0] == p[1] && (*p == '+' || *p == '-'))
+ {
+ eap->cmdidx = *p == '+' ? CMD_increment : CMD_decrement;
+ return eap->cmd + 2;
+ }
}
#endif
diff --git a/src/proto/vim9script.pro b/src/proto/vim9script.pro
index cb5a30d2e0..2c4bd79606 100644
--- a/src/proto/vim9script.pro
+++ b/src/proto/vim9script.pro
@@ -5,6 +5,7 @@ void ex_vim9script(exarg_T *eap);
int not_in_vim9(exarg_T *eap);
int vim9_bad_comment(char_u *p);
int vim9_comment_start(char_u *p);
+void ex_incdec(exarg_T *eap);
void ex_export(exarg_T *eap);
void free_imports_and_script_vars(int sid);
void mark_imports_for_reload(int sid);
diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim
index a0175cd281..246284c86f 100644
--- a/src/testdir/test_vim9_assign.vim
+++ b/src/testdir/test_vim9_assign.vim
@@ -1837,5 +1837,21 @@ def Test_script_funcref_case()
CheckScriptFailure(lines, 'E704:')
enddef
+def Test_inc_dec()
+ var lines =<< trim END
+ var nr = 7
+ ++nr
+ echo nr
+ --nr
+ echo nr
+
+ var ll = [1, 2]
+ --ll[0]
+ ++ll[1]
+ echo ll
+ END
+ CheckDefAndScriptSuccess(lines)
+enddef
+
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim
index fd9b406b24..fdedd5f042 100644
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -2768,19 +2768,6 @@ def Test_expr7_negate_add()
echo + +n
END
CheckDefAndScriptFailure(lines, 'E15:')
-
- lines =<< trim END
- var n = 12
- :1
- ++n
- END
- CheckDefAndScriptFailure(lines, 'E1050:')
- lines =<< trim END
- var n = 12
- :1
- --n
- END
- CheckDefAndScriptFailure(lines, 'E1050:')
enddef
def Test_expr7_legacy_script()
diff --git a/src/version.c b/src/version.c
index 4c266eff6c..1931aae031 100644
--- 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 */
/**/
+ 2806,
+/**/
2805,
/**/
2804,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index c65f1c37c6..a3154c3316 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -4688,6 +4688,10 @@ compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
op = may_peek_next_line(cctx, *arg, &next);
if (*op != '+' && *op != '-' && !(*op == '.' && *(op + 1) == '.'))
break;
+ if (op[0] == op[1] && *op != '.' && next)
+ // Finding "++" or "--" on the next line is a separate command.
+ // But ".." is concatenation.
+ break;
oplen = (*op == '.' ? 2 : 1);
if (next != NULL)
{
@@ -6395,6 +6399,7 @@ compile_assign_unlet(
* "const name = expr"
* "name = expr"
* "arg" points to "name".
+ * "++arg" and "--arg"
* Return NULL for an error.
* Return "arg" if it does not look like a variable list.
*/
@@ -6413,6 +6418,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
char_u *op;
int oplen = 0;
int heredoc = FALSE;
+ int incdec = FALSE;
type_T *rhs_type = &t_any;
char_u *sp;
int is_decl = is_decl_command(cmdidx);
@@ -6447,6 +6453,12 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
error_white_both(op, oplen);
return NULL;
}
+ if (eap->cmdidx == CMD_increment || eap->cmdidx == CMD_decrement)
+ {
+ op = (char_u *)(eap->cmdidx == CMD_increment ? "+=" : "-=");
+ oplen = 2;
+ incdec = TRUE;
+ }
if (heredoc)
{
@@ -6571,23 +6583,31 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
- // Compile the expression. Temporarily hide the new local
- // variable here, it is not available to this expression.
- if (lhs.lhs_new_local)
- --cctx->ctx_locals.ga_len;
+ // Compile the expression.
instr_count = instr->ga_len;
- wp = op + oplen;
- if (may_get_next_line_error(wp, &p, cctx) == FAIL)
+ if (incdec)
{
+ r = generate_PUSHNR(cctx, 1);
+ }
+ else
+ {
+ // Temporarily hide the new local variable here, it is
+ // not available to this expression.
+ if (lhs.lhs_new_local)
+ --cctx->ctx_locals.ga_len;
+ wp = op + oplen;
+ if (may_get_next_line_error(wp, &p, cctx) == FAIL)
+ {
+ if (lhs.lhs_new_local)
+ ++cctx->ctx_locals.ga_len;
+ goto theend;
+ }
+ r = compile_expr0_ext(&p, cctx, &is_const);
if (lhs.lhs_new_local)
++cctx->ctx_locals.ga_len;
- goto theend;
+ if (r == FAIL)
+ goto theend;
}
- r = compile_expr0_ext(&p, cctx, &is_const);
- if (lhs.lhs_new_local)
- ++cctx->ctx_locals.ga_len;
- if (r == FAIL)
- goto theend;
}
else if (semicolon && var_idx == var_count - 1)
{
@@ -9018,9 +9038,11 @@ compile_def_function(
/*
* COMMAND after range
* 'text'->func() should not be confused with 'a mark
+ * "++nr" and "--nr" are eval commands
*/
cmd = ea.cmd;
- if (*cmd != '\'' || starts_with_colon)
+ if (starts_with_colon || !(*cmd == '\''
+ || (cmd[0] == cmd[1] && (*cmd == '+' || *cmd == '-'))))
{
ea.cmd = skip_range(ea.cmd, TRUE, NULL);
if (ea.cmd > cmd)
@@ -9125,6 +9147,8 @@ compile_def_function(
case CMD_var:
case CMD_final:
case CMD_const:
+ case CMD_increment:
+ case CMD_decrement:
line = compile_assignment(p, &ea, ea.cmdidx, &cctx);
if (line == p)
line = NULL;
diff --git a/src/vim9script.c b/src/vim9script.c
index ddbae781c6..02c04e2ea7 100644
--- a/src/vim9script.c
+++ b/src/vim9script.c
@@ -160,6 +160,28 @@ vim9_comment_start(char_u *p)
#if defined(FEAT_EVAL) || defined(PROTO)
/*
+ * "++nr" and "--nr" commands.
+ */
+ void
+ex_incdec(exarg_T *eap)
+{
+ char_u *cmd = eap->cmd;
+ size_t len = STRLEN(eap->cmd) + 6;
+
+ // This works like "nr += 1" or "nr -= 1".
+ eap->cmd = alloc(len);
+ if (eap->cmd == NULL)
+ return;
+ vim_snprintf((char *)eap->cmd, len, "%s %c= 1", cmd + 2,
+ eap->cmdidx == CMD_increment ? '+' : '-');
+ eap->arg = eap->cmd;
+ eap->cmdidx = CMD_var;
+ ex_let(eap);
+ vim_free(eap->cmd);
+ eap->cmd = cmd;
+}
+
+/*
* ":export let Name: type"
* ":export const Name: type"
* ":export def Name(..."