summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-04-20 21:10:48 +0200
committerBram Moolenaar <Bram@vim.org>2021-04-20 21:10:48 +0200
commit8238f08838c0b481d0b14a741bc03f2e45c211d3 (patch)
treeba10a1e6685a38dd05ed8102b8680d2dc628c1fc /src
parent3f88e71fa2b8b1fc97f3c218989474ea8687d197 (diff)
patch 8.2.2789: Vim9: using \=expr in :substitute does not handle jumpsv8.2.2789
Problem: Vim9: using \=expr in :substitute does not handle jumps. Solution: Start with instruction count zero. (closes #8128)
Diffstat (limited to 'src')
-rw-r--r--src/testdir/test_vim9_cmd.vim6
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c90
3 files changed, 60 insertions, 38 deletions
diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim
index be33f74326..0ff2e280f2 100644
--- a/src/testdir/test_vim9_cmd.vim
+++ b/src/testdir/test_vim9_cmd.vim
@@ -1188,6 +1188,12 @@ def Test_substitute_expr()
s/from/\=to .. '_' .. also/g#e
assert_equal('one repl_also two repl_also three', getline(1))
+ setline(1, 'abc abc abc')
+ for choice in [true, false]
+ :1s/abc/\=choice ? 'yes' : 'no'/
+ endfor
+ assert_equal('yes no abc', getline(1))
+
CheckDefFailure(['s/from/\="x")/'], 'E488:')
CheckDefFailure(['s/from/\="x"/9'], 'E488:')
diff --git a/src/version.c b/src/version.c
index 192672460e..86d6f36bd7 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 */
/**/
+ 2789,
+/**/
2788,
/**/
2787,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 0695879e32..279a8c3a3e 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2179,33 +2179,6 @@ generate_EXECCONCAT(cctx_T *cctx, int count)
return OK;
}
- static int
-generate_substitute(char_u *cmd, int instr_start, cctx_T *cctx)
-{
- isn_T *isn;
- isn_T *instr;
- int instr_count = cctx->ctx_instr.ga_len - instr_start;
-
- instr = ALLOC_MULT(isn_T, instr_count + 1);
- if (instr == NULL)
- return FAIL;
- // Move the generated instructions into the ISN_SUBSTITUTE instructions,
- // then truncate the list of instructions, so they are used only once.
- mch_memmove(instr, ((isn_T *)cctx->ctx_instr.ga_data) + instr_start,
- instr_count * sizeof(isn_T));
- instr[instr_count].isn_type = ISN_FINISH;
- cctx->ctx_instr.ga_len = instr_start;
-
- if ((isn = generate_instr(cctx, ISN_SUBSTITUTE)) == NULL)
- {
- vim_free(instr);
- return FAIL;
- }
- isn->isn_arg.subs.subs_cmd = vim_strsave(cmd);
- isn->isn_arg.subs.subs_instr = instr;
- return OK;
-}
-
/*
* Generate ISN_RANGE. Consumes "range". Return OK/FAIL.
*/
@@ -8522,6 +8495,17 @@ theend:
return nextcmd;
}
+
+ static void
+clear_instr_ga(garray_T *gap)
+{
+ int idx;
+
+ for (idx = 0; idx < gap->ga_len; ++idx)
+ delete_instr(((isn_T *)gap->ga_data) + idx);
+ ga_clear(gap);
+}
+
/*
* :s/pat/repl/
*/
@@ -8536,28 +8520,61 @@ compile_substitute(char_u *arg, exarg_T *eap, cctx_T *cctx)
int delimiter = *cmd++;
// There is a \=expr, find it in the substitute part.
- cmd = skip_regexp_ex(cmd, delimiter, magic_isset(),
- NULL, NULL, NULL);
+ cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), NULL, NULL, NULL);
if (cmd[0] == delimiter && cmd[1] == '\\' && cmd[2] == '=')
{
- int instr_count = cctx->ctx_instr.ga_len;
- char_u *end;
+ garray_T save_ga = cctx->ctx_instr;
+ char_u *end;
+ int trailing_error;
+ int instr_count;
+ isn_T *instr = NULL;
+ isn_T *isn;
cmd += 3;
end = skip_substitute(cmd, delimiter);
+ // Temporarily reset the list of instructions so that the jumps
+ // labels are correct.
+ cctx->ctx_instr.ga_len = 0;
+ cctx->ctx_instr.ga_maxlen = 0;
+ cctx->ctx_instr.ga_data = NULL;
compile_expr0(&cmd, cctx);
if (end[-1] == NUL)
end[-1] = delimiter;
cmd = skipwhite(cmd);
- if (*cmd != delimiter && *cmd != NUL)
+ trailing_error = *cmd != delimiter && *cmd != NUL;
+
+ instr_count = cctx->ctx_instr.ga_len;
+ instr = ALLOC_MULT(isn_T, instr_count + 1);
+ if (trailing_error || instr == NULL)
{
- semsg(_(e_trailing_arg), cmd);
+ if (trailing_error)
+ semsg(_(e_trailing_arg), cmd);
+ clear_instr_ga(&cctx->ctx_instr);
+ cctx->ctx_instr = save_ga;
+ vim_free(instr);
return NULL;
}
- if (generate_substitute(arg, instr_count, cctx) == FAIL)
+ // Move the generated instructions into the ISN_SUBSTITUTE
+ // instructions, then restore the list of instructions before
+ // adding the ISN_SUBSTITUTE instruction.
+ mch_memmove(instr, cctx->ctx_instr.ga_data,
+ instr_count * sizeof(isn_T));
+ instr[instr_count].isn_type = ISN_FINISH;
+
+ cctx->ctx_instr = save_ga;
+ if ((isn = generate_instr(cctx, ISN_SUBSTITUTE)) == NULL)
+ {
+ int idx;
+
+ for (idx = 0; idx < instr_count; ++idx)
+ delete_instr(instr + idx);
+ vim_free(instr);
return NULL;
+ }
+ isn->isn_arg.subs.subs_cmd = vim_strsave(arg);
+ isn->isn_arg.subs.subs_instr = instr;
// skip over flags
if (*end == '&')
@@ -9285,13 +9302,10 @@ nextline:
erret:
if (ufunc->uf_def_status == UF_COMPILING)
{
- int idx;
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ ufunc->uf_dfunc_idx;
- for (idx = 0; idx < instr->ga_len; ++idx)
- delete_instr(((isn_T *)instr->ga_data) + idx);
- ga_clear(instr);
+ clear_instr_ga(instr);
VIM_CLEAR(dfunc->df_name);
// If using the last entry in the table and it was added above, we