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