Mercurial > vim
comparison src/vim9compile.c @ 24488:f293bb501b30 v8.2.2784
patch 8.2.2784: Vim9: cannot use =expr in :substitute
Commit: https://github.com/vim/vim/commit/4c13721482d7786f92f5a56e43b0f5c499264b7e
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Apr 19 16:48:48 2021 +0200
patch 8.2.2784: Vim9: cannot use \=expr in :substitute
Problem: Vim9: cannot use \=expr in :substitute.
Solution: Compile the expression into instructions and execute them when
invoked.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 19 Apr 2021 17:00:04 +0200 |
parents | 943e9b1d2d16 |
children | 08050e45bd06 |
comparison
equal
deleted
inserted
replaced
24487:2bcec3ba6a08 | 24488:f293bb501b30 |
---|---|
2125 isn_T *isn; | 2125 isn_T *isn; |
2126 | 2126 |
2127 if ((isn = generate_instr_drop(cctx, ISN_EXECCONCAT, count)) == NULL) | 2127 if ((isn = generate_instr_drop(cctx, ISN_EXECCONCAT, count)) == NULL) |
2128 return FAIL; | 2128 return FAIL; |
2129 isn->isn_arg.number = count; | 2129 isn->isn_arg.number = count; |
2130 return OK; | |
2131 } | |
2132 | |
2133 static int | |
2134 generate_substitute(char_u *cmd, int instr_start, cctx_T *cctx) | |
2135 { | |
2136 isn_T *isn; | |
2137 isn_T *instr; | |
2138 int instr_count = cctx->ctx_instr.ga_len - instr_start; | |
2139 | |
2140 instr = ALLOC_MULT(isn_T, instr_count + 1); | |
2141 if (instr == NULL) | |
2142 return FAIL; | |
2143 // Move the generated instructions into the ISN_SUBSTITUTE instructions, | |
2144 // then truncate the list of instructions, so they are used only once. | |
2145 mch_memmove(instr, ((isn_T *)cctx->ctx_instr.ga_data) + instr_start, | |
2146 instr_count * sizeof(isn_T)); | |
2147 instr[instr_count].isn_type = ISN_FINISH; | |
2148 cctx->ctx_instr.ga_len = instr_start; | |
2149 | |
2150 if ((isn = generate_instr(cctx, ISN_SUBSTITUTE)) == NULL) | |
2151 { | |
2152 vim_free(instr); | |
2153 return FAIL; | |
2154 } | |
2155 isn->isn_arg.subs.subs_cmd = vim_strsave(cmd); | |
2156 isn->isn_arg.subs.subs_instr = instr; | |
2130 return OK; | 2157 return OK; |
2131 } | 2158 } |
2132 | 2159 |
2133 /* | 2160 /* |
2134 * Generate ISN_RANGE. Consumes "range". Return OK/FAIL. | 2161 * Generate ISN_RANGE. Consumes "range". Return OK/FAIL. |
8464 | 8491 |
8465 return nextcmd; | 8492 return nextcmd; |
8466 } | 8493 } |
8467 | 8494 |
8468 /* | 8495 /* |
8496 * :s/pat/repl/ | |
8497 */ | |
8498 static char_u * | |
8499 compile_substitute(char_u *arg, exarg_T *eap, cctx_T *cctx) | |
8500 { | |
8501 char_u *cmd = eap->arg; | |
8502 char_u *expr = (char_u *)strstr((char *)cmd, "\\="); | |
8503 | |
8504 if (expr != NULL) | |
8505 { | |
8506 int delimiter = *cmd++; | |
8507 | |
8508 // There is a \=expr, find it in the substitute part. | |
8509 cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), | |
8510 NULL, NULL, NULL); | |
8511 if (cmd[0] == delimiter && cmd[1] == '\\' && cmd[2] == '=') | |
8512 { | |
8513 int instr_count = cctx->ctx_instr.ga_len; | |
8514 char_u *end; | |
8515 | |
8516 cmd += 3; | |
8517 end = skip_substitute(cmd, delimiter); | |
8518 | |
8519 compile_expr0(&cmd, cctx); | |
8520 if (end[-1] == NUL) | |
8521 end[-1] = delimiter; | |
8522 cmd = skipwhite(cmd); | |
8523 if (*cmd != delimiter && *cmd != NUL) | |
8524 { | |
8525 semsg(_(e_trailing_arg), cmd); | |
8526 return NULL; | |
8527 } | |
8528 | |
8529 if (generate_substitute(arg, instr_count, cctx) == FAIL) | |
8530 return NULL; | |
8531 | |
8532 // skip over flags | |
8533 if (*end == '&') | |
8534 ++end; | |
8535 while (ASCII_ISALPHA(*end) || *end == '#') | |
8536 ++end; | |
8537 return end; | |
8538 } | |
8539 } | |
8540 | |
8541 return compile_exec(arg, eap, cctx); | |
8542 } | |
8543 | |
8544 /* | |
8469 * Add a function to the list of :def functions. | 8545 * Add a function to the list of :def functions. |
8470 * This sets "ufunc->uf_dfunc_idx" but the function isn't compiled yet. | 8546 * This sets "ufunc->uf_dfunc_idx" but the function isn't compiled yet. |
8471 */ | 8547 */ |
8472 static int | 8548 static int |
8473 add_def_function(ufunc_T *ufunc) | 8549 add_def_function(ufunc_T *ufunc) |
8992 break; | 9068 break; |
8993 | 9069 |
8994 case CMD_put: | 9070 case CMD_put: |
8995 ea.cmd = cmd; | 9071 ea.cmd = cmd; |
8996 line = compile_put(p, &ea, &cctx); | 9072 line = compile_put(p, &ea, &cctx); |
9073 break; | |
9074 | |
9075 case CMD_substitute: | |
9076 if (cctx.ctx_skip == SKIP_YES) | |
9077 line = (char_u *)""; | |
9078 else | |
9079 { | |
9080 ea.arg = p; | |
9081 line = compile_substitute(line, &ea, &cctx); | |
9082 } | |
8997 break; | 9083 break; |
8998 | 9084 |
8999 // TODO: any other commands with an expression argument? | 9085 // TODO: any other commands with an expression argument? |
9000 | 9086 |
9001 case CMD_append: | 9087 case CMD_append: |
9219 case ISN_STOREG: | 9305 case ISN_STOREG: |
9220 case ISN_STORET: | 9306 case ISN_STORET: |
9221 case ISN_STOREW: | 9307 case ISN_STOREW: |
9222 case ISN_STRINGMEMBER: | 9308 case ISN_STRINGMEMBER: |
9223 vim_free(isn->isn_arg.string); | 9309 vim_free(isn->isn_arg.string); |
9310 break; | |
9311 | |
9312 case ISN_SUBSTITUTE: | |
9313 vim_free(isn->isn_arg.subs.subs_cmd); | |
9314 vim_free(isn->isn_arg.subs.subs_instr); | |
9224 break; | 9315 break; |
9225 | 9316 |
9226 case ISN_LOADS: | 9317 case ISN_LOADS: |
9227 case ISN_STORES: | 9318 case ISN_STORES: |
9228 vim_free(isn->isn_arg.loadstore.ls_name); | 9319 vim_free(isn->isn_arg.loadstore.ls_name); |
9398 case ISN_THROW: | 9489 case ISN_THROW: |
9399 case ISN_TRYCONT: | 9490 case ISN_TRYCONT: |
9400 case ISN_UNLETINDEX: | 9491 case ISN_UNLETINDEX: |
9401 case ISN_UNLETRANGE: | 9492 case ISN_UNLETRANGE: |
9402 case ISN_UNPACK: | 9493 case ISN_UNPACK: |
9494 case ISN_FINISH: | |
9403 // nothing allocated | 9495 // nothing allocated |
9404 break; | 9496 break; |
9405 } | 9497 } |
9406 } | 9498 } |
9407 | 9499 |