Patch 8.2.2789
Problem: Vim9: using \=expr in :substitute does not handle jumps.
Solution: Start with instruction count zero. (closes #8128)
Files: src/vim9compile.c, src/testdir/test_vim9_cmd.vim
*** ../vim-8.2.2788/src/vim9compile.c 2021-04-19 21:06:27.454353644 +0200
--- src/vim9compile.c 2021-04-20 21:09:32.038843810 +0200
***************
*** 2179,2211 ****
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.
*/
--- 2179,2184 ----
***************
*** 8522,8527 ****
--- 8495,8511 ----
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,8563 ****
int delimiter = *cmd++;
// There is a \=expr, find it in the substitute part.
! 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;
cmd += 3;
end = skip_substitute(cmd, delimiter);
compile_expr0(&cmd, cctx);
if (end[-1] == NUL)
end[-1] = delimiter;
cmd = skipwhite(cmd);
! if (*cmd != delimiter && *cmd != NUL)
! {
! semsg(_(e_trailing_arg), cmd);
return NULL;
}
! if (generate_substitute(arg, instr_count, cctx) == FAIL)
return NULL;
// skip over flags
if (*end == '&')
--- 8520,8580 ----
int delimiter = *cmd++;
// There is a \=expr, find it in the substitute part.
! cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), NULL, NULL, NULL);
if (cmd[0] == delimiter && cmd[1] == '\\' && cmd[2] == '=')
{
! 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);
! 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)
! {
! if (trailing_error)
! semsg(_(e_trailing_arg), cmd);
! clear_instr_ga(&cctx->ctx_instr);
! cctx->ctx_instr = save_ga;
! vim_free(instr);
return NULL;
}
! // 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,9297 ****
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);
VIM_CLEAR(dfunc->df_name);
// If using the last entry in the table and it was added above, we
--- 9302,9311 ----
erret:
if (ufunc->uf_def_status == UF_COMPILING)
{
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ ufunc->uf_dfunc_idx;
! clear_instr_ga(instr);
VIM_CLEAR(dfunc->df_name);
// If using the last entry in the table and it was added above, we
*** ../vim-8.2.2788/src/testdir/test_vim9_cmd.vim 2021-04-19
20:49:58.156857538 +0200
--- src/testdir/test_vim9_cmd.vim 2021-04-20 21:05:13.535665815 +0200
***************
*** 1188,1193 ****
--- 1188,1199 ----
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:')
*** ../vim-8.2.2788/src/version.c 2021-04-20 20:21:19.763851843 +0200
--- src/version.c 2021-04-20 21:10:16.838702338 +0200
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 2789,
/**/
--
hundred-and-one symptoms of being an internet addict:
131. You challenge authority and society by portnuking people
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/202104201911.13KJBVl1915480%40masaka.moolenaar.net.