mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.2.2789: Vim9: using \=expr in :substitute does not handle jumps
Problem: Vim9: using \=expr in :substitute does not handle jumps. Solution: Start with instruction count zero. (closes #8128)
This commit is contained in:
@@ -1188,6 +1188,12 @@ def Test_substitute_expr()
|
|||||||
s/from/\=to .. '_' .. also/g#e
|
s/from/\=to .. '_' .. also/g#e
|
||||||
assert_equal('one repl_also two repl_also three', getline(1))
|
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")/'], 'E488:')
|
||||||
CheckDefFailure(['s/from/\="x"/9'], 'E488:')
|
CheckDefFailure(['s/from/\="x"/9'], 'E488:')
|
||||||
|
|
||||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2789,
|
||||||
/**/
|
/**/
|
||||||
2788,
|
2788,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -2179,33 +2179,6 @@ generate_EXECCONCAT(cctx_T *cctx, int count)
|
|||||||
return OK;
|
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.
|
* Generate ISN_RANGE. Consumes "range". Return OK/FAIL.
|
||||||
*/
|
*/
|
||||||
@@ -8522,6 +8495,17 @@ theend:
|
|||||||
return nextcmd;
|
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/
|
* :s/pat/repl/
|
||||||
*/
|
*/
|
||||||
@@ -8536,28 +8520,61 @@ compile_substitute(char_u *arg, exarg_T *eap, cctx_T *cctx)
|
|||||||
int delimiter = *cmd++;
|
int delimiter = *cmd++;
|
||||||
|
|
||||||
// There is a \=expr, find it in the substitute part.
|
// There is a \=expr, find it in the substitute part.
|
||||||
cmd = skip_regexp_ex(cmd, delimiter, magic_isset(),
|
cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), NULL, NULL, NULL);
|
||||||
NULL, NULL, NULL);
|
|
||||||
if (cmd[0] == delimiter && cmd[1] == '\\' && cmd[2] == '=')
|
if (cmd[0] == delimiter && cmd[1] == '\\' && cmd[2] == '=')
|
||||||
{
|
{
|
||||||
int instr_count = cctx->ctx_instr.ga_len;
|
garray_T save_ga = cctx->ctx_instr;
|
||||||
char_u *end;
|
char_u *end;
|
||||||
|
int trailing_error;
|
||||||
|
int instr_count;
|
||||||
|
isn_T *instr = NULL;
|
||||||
|
isn_T *isn;
|
||||||
|
|
||||||
cmd += 3;
|
cmd += 3;
|
||||||
end = skip_substitute(cmd, delimiter);
|
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);
|
compile_expr0(&cmd, cctx);
|
||||||
if (end[-1] == NUL)
|
if (end[-1] == NUL)
|
||||||
end[-1] = delimiter;
|
end[-1] = delimiter;
|
||||||
cmd = skipwhite(cmd);
|
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;
|
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;
|
return NULL;
|
||||||
|
}
|
||||||
|
isn->isn_arg.subs.subs_cmd = vim_strsave(arg);
|
||||||
|
isn->isn_arg.subs.subs_instr = instr;
|
||||||
|
|
||||||
// skip over flags
|
// skip over flags
|
||||||
if (*end == '&')
|
if (*end == '&')
|
||||||
@@ -9285,13 +9302,10 @@ nextline:
|
|||||||
erret:
|
erret:
|
||||||
if (ufunc->uf_def_status == UF_COMPILING)
|
if (ufunc->uf_def_status == UF_COMPILING)
|
||||||
{
|
{
|
||||||
int idx;
|
|
||||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||||
+ ufunc->uf_dfunc_idx;
|
+ ufunc->uf_dfunc_idx;
|
||||||
|
|
||||||
for (idx = 0; idx < instr->ga_len; ++idx)
|
clear_instr_ga(instr);
|
||||||
delete_instr(((isn_T *)instr->ga_data) + idx);
|
|
||||||
ga_clear(instr);
|
|
||||||
VIM_CLEAR(dfunc->df_name);
|
VIM_CLEAR(dfunc->df_name);
|
||||||
|
|
||||||
// If using the last entry in the table and it was added above, we
|
// If using the last entry in the table and it was added above, we
|
||||||
|
Reference in New Issue
Block a user