# HG changeset patch # User Bram Moolenaar # Date 1619284504 -7200 # Node ID 9c404d78d767635f90bc21ad0b336ec70efd42a5 # Parent 7660cdae6683d92d2c567576c13ab12a45e2b37f patch 8.2.2806: Vim9: using "++nr" as a command might not work Commit: https://github.com/vim/vim/commit/bdc0f1c6986e5d64f647e0924a4de795b47c549a Author: Bram Moolenaar 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. diff --git a/src/eval.c b/src/eval.c --- 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; diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h --- 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; diff --git a/src/ex_cmds.h b/src/ex_cmds.h --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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; diff --git a/src/vim9script.c b/src/vim9script.c --- 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(..."