changeset 24533:9c404d78d767 v8.2.2806

patch 8.2.2806: Vim9: using "++nr" as a command might not work Commit: https://github.com/vim/vim/commit/bdc0f1c6986e5d64f647e0924a4de795b47c549a Author: Bram Moolenaar <Bram@vim.org> Date: Sat Apr 24 19:08:24 2021 +0200 patch 8.2.2806: Vim9: using "++nr" as a command might not work Problem: Vim9: using "++nr" as a command might not work. Solution: Do not recognize "++" and "--" in a following line as addition or subtraction.
author Bram Moolenaar <Bram@vim.org>
date Sat, 24 Apr 2021 19:15:04 +0200
parents 7660cdae6683
children 3d5661b90d53
files src/eval.c src/ex_cmdidxs.h src/ex_cmds.h src/ex_docmd.c src/proto/vim9script.pro src/testdir/test_vim9_assign.vim src/testdir/test_vim9_expr.vim src/version.c src/vim9compile.c src/vim9script.c
diffstat 10 files changed, 97 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -2856,12 +2856,15 @@ eval5(char_u **arg, typval_T *rettv, eva
 
 	// "." 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;
--- a/src/ex_cmdidxs.h
+++ b/src/ex_cmdidxs.h
@@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[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;
--- 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
--- 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
 
--- 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);
--- 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
--- 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()
--- 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,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -4688,6 +4688,10 @@ compile_expr5(char_u **arg, cctx_T *cctx
 	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 
     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 
 	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 
 			    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;
--- 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(..."