Mercurial > vim
comparison src/vim9compile.c @ 24498:bfa495227ac6 v8.2.2789
patch 8.2.2789: Vim9: using =expr in :substitute does not handle jumps
Commit: https://github.com/vim/vim/commit/8238f08838c0b481d0b14a741bc03f2e45c211d3
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Apr 20 21:10:48 2021 +0200
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 https://github.com/vim/vim/issues/8128)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Tue, 20 Apr 2021 21:15:04 +0200 |
parents | cca0a1b4e878 |
children | 5baac0b4b41c |
comparison
equal
deleted
inserted
replaced
24497:b444a9f9b467 | 24498:bfa495227ac6 |
---|---|
2174 isn_T *isn; | 2174 isn_T *isn; |
2175 | 2175 |
2176 if ((isn = generate_instr_drop(cctx, ISN_EXECCONCAT, count)) == NULL) | 2176 if ((isn = generate_instr_drop(cctx, ISN_EXECCONCAT, count)) == NULL) |
2177 return FAIL; | 2177 return FAIL; |
2178 isn->isn_arg.number = count; | 2178 isn->isn_arg.number = count; |
2179 return OK; | |
2180 } | |
2181 | |
2182 static int | |
2183 generate_substitute(char_u *cmd, int instr_start, cctx_T *cctx) | |
2184 { | |
2185 isn_T *isn; | |
2186 isn_T *instr; | |
2187 int instr_count = cctx->ctx_instr.ga_len - instr_start; | |
2188 | |
2189 instr = ALLOC_MULT(isn_T, instr_count + 1); | |
2190 if (instr == NULL) | |
2191 return FAIL; | |
2192 // Move the generated instructions into the ISN_SUBSTITUTE instructions, | |
2193 // then truncate the list of instructions, so they are used only once. | |
2194 mch_memmove(instr, ((isn_T *)cctx->ctx_instr.ga_data) + instr_start, | |
2195 instr_count * sizeof(isn_T)); | |
2196 instr[instr_count].isn_type = ISN_FINISH; | |
2197 cctx->ctx_instr.ga_len = instr_start; | |
2198 | |
2199 if ((isn = generate_instr(cctx, ISN_SUBSTITUTE)) == NULL) | |
2200 { | |
2201 vim_free(instr); | |
2202 return FAIL; | |
2203 } | |
2204 isn->isn_arg.subs.subs_cmd = vim_strsave(cmd); | |
2205 isn->isn_arg.subs.subs_instr = instr; | |
2206 return OK; | 2179 return OK; |
2207 } | 2180 } |
2208 | 2181 |
2209 /* | 2182 /* |
2210 * Generate ISN_RANGE. Consumes "range". Return OK/FAIL. | 2183 * Generate ISN_RANGE. Consumes "range". Return OK/FAIL. |
8520 } | 8493 } |
8521 | 8494 |
8522 return nextcmd; | 8495 return nextcmd; |
8523 } | 8496 } |
8524 | 8497 |
8498 | |
8499 static void | |
8500 clear_instr_ga(garray_T *gap) | |
8501 { | |
8502 int idx; | |
8503 | |
8504 for (idx = 0; idx < gap->ga_len; ++idx) | |
8505 delete_instr(((isn_T *)gap->ga_data) + idx); | |
8506 ga_clear(gap); | |
8507 } | |
8508 | |
8525 /* | 8509 /* |
8526 * :s/pat/repl/ | 8510 * :s/pat/repl/ |
8527 */ | 8511 */ |
8528 static char_u * | 8512 static char_u * |
8529 compile_substitute(char_u *arg, exarg_T *eap, cctx_T *cctx) | 8513 compile_substitute(char_u *arg, exarg_T *eap, cctx_T *cctx) |
8534 if (expr != NULL) | 8518 if (expr != NULL) |
8535 { | 8519 { |
8536 int delimiter = *cmd++; | 8520 int delimiter = *cmd++; |
8537 | 8521 |
8538 // There is a \=expr, find it in the substitute part. | 8522 // There is a \=expr, find it in the substitute part. |
8539 cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), | 8523 cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), NULL, NULL, NULL); |
8540 NULL, NULL, NULL); | |
8541 if (cmd[0] == delimiter && cmd[1] == '\\' && cmd[2] == '=') | 8524 if (cmd[0] == delimiter && cmd[1] == '\\' && cmd[2] == '=') |
8542 { | 8525 { |
8543 int instr_count = cctx->ctx_instr.ga_len; | 8526 garray_T save_ga = cctx->ctx_instr; |
8544 char_u *end; | 8527 char_u *end; |
8528 int trailing_error; | |
8529 int instr_count; | |
8530 isn_T *instr = NULL; | |
8531 isn_T *isn; | |
8545 | 8532 |
8546 cmd += 3; | 8533 cmd += 3; |
8547 end = skip_substitute(cmd, delimiter); | 8534 end = skip_substitute(cmd, delimiter); |
8548 | 8535 |
8536 // Temporarily reset the list of instructions so that the jumps | |
8537 // labels are correct. | |
8538 cctx->ctx_instr.ga_len = 0; | |
8539 cctx->ctx_instr.ga_maxlen = 0; | |
8540 cctx->ctx_instr.ga_data = NULL; | |
8549 compile_expr0(&cmd, cctx); | 8541 compile_expr0(&cmd, cctx); |
8550 if (end[-1] == NUL) | 8542 if (end[-1] == NUL) |
8551 end[-1] = delimiter; | 8543 end[-1] = delimiter; |
8552 cmd = skipwhite(cmd); | 8544 cmd = skipwhite(cmd); |
8553 if (*cmd != delimiter && *cmd != NUL) | 8545 trailing_error = *cmd != delimiter && *cmd != NUL; |
8554 { | 8546 |
8555 semsg(_(e_trailing_arg), cmd); | 8547 instr_count = cctx->ctx_instr.ga_len; |
8548 instr = ALLOC_MULT(isn_T, instr_count + 1); | |
8549 if (trailing_error || instr == NULL) | |
8550 { | |
8551 if (trailing_error) | |
8552 semsg(_(e_trailing_arg), cmd); | |
8553 clear_instr_ga(&cctx->ctx_instr); | |
8554 cctx->ctx_instr = save_ga; | |
8555 vim_free(instr); | |
8556 return NULL; | 8556 return NULL; |
8557 } | 8557 } |
8558 | 8558 |
8559 if (generate_substitute(arg, instr_count, cctx) == FAIL) | 8559 // Move the generated instructions into the ISN_SUBSTITUTE |
8560 // instructions, then restore the list of instructions before | |
8561 // adding the ISN_SUBSTITUTE instruction. | |
8562 mch_memmove(instr, cctx->ctx_instr.ga_data, | |
8563 instr_count * sizeof(isn_T)); | |
8564 instr[instr_count].isn_type = ISN_FINISH; | |
8565 | |
8566 cctx->ctx_instr = save_ga; | |
8567 if ((isn = generate_instr(cctx, ISN_SUBSTITUTE)) == NULL) | |
8568 { | |
8569 int idx; | |
8570 | |
8571 for (idx = 0; idx < instr_count; ++idx) | |
8572 delete_instr(instr + idx); | |
8573 vim_free(instr); | |
8560 return NULL; | 8574 return NULL; |
8575 } | |
8576 isn->isn_arg.subs.subs_cmd = vim_strsave(arg); | |
8577 isn->isn_arg.subs.subs_instr = instr; | |
8561 | 8578 |
8562 // skip over flags | 8579 // skip over flags |
8563 if (*end == '&') | 8580 if (*end == '&') |
8564 ++end; | 8581 ++end; |
8565 while (ASCII_ISALPHA(*end) || *end == '#') | 8582 while (ASCII_ISALPHA(*end) || *end == '#') |
9283 ret = OK; | 9300 ret = OK; |
9284 | 9301 |
9285 erret: | 9302 erret: |
9286 if (ufunc->uf_def_status == UF_COMPILING) | 9303 if (ufunc->uf_def_status == UF_COMPILING) |
9287 { | 9304 { |
9288 int idx; | |
9289 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) | 9305 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) |
9290 + ufunc->uf_dfunc_idx; | 9306 + ufunc->uf_dfunc_idx; |
9291 | 9307 |
9292 for (idx = 0; idx < instr->ga_len; ++idx) | 9308 clear_instr_ga(instr); |
9293 delete_instr(((isn_T *)instr->ga_data) + idx); | |
9294 ga_clear(instr); | |
9295 VIM_CLEAR(dfunc->df_name); | 9309 VIM_CLEAR(dfunc->df_name); |
9296 | 9310 |
9297 // If using the last entry in the table and it was added above, we | 9311 // If using the last entry in the table and it was added above, we |
9298 // might as well remove it. | 9312 // might as well remove it. |
9299 if (!dfunc->df_deleted && new_def_function | 9313 if (!dfunc->df_deleted && new_def_function |