diff src/vim9expr.c @ 28692:bfd8e25fa207 v8.2.4870

patch 8.2.4870: Vim9: expression in :substitute is not compiled Commit: https://github.com/vim/vim/commit/f3b4895f2727e3849ca10030b251cccd9d1383f3 Author: LemonBoy <thatlemon@gmail.com> Date: Thu May 5 13:53:03 2022 +0100 patch 8.2.4870: Vim9: expression in :substitute is not compiled Problem: Vim9: expression in :substitute is not compiled. Solution: Use an INSTR instruction if possible. (closes https://github.com/vim/vim/issues/10334)
author Bram Moolenaar <Bram@vim.org>
date Thu, 05 May 2022 15:00:04 +0200
parents d550054e1328
children 723c7d940cba
line wrap: on
line diff
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -567,12 +567,13 @@ theend:
 
 /*
  * Compile a string in a ISN_PUSHS instruction into an ISN_INSTR.
+ * "str_offset" is the number of leading bytes to skip from the string.
  * Returns FAIL if compilation fails.
  */
     static int
-compile_string(isn_T *isn, cctx_T *cctx)
+compile_string(isn_T *isn, cctx_T *cctx, int str_offset)
 {
-    char_u	*s = isn->isn_arg.string;
+    char_u	*s = isn->isn_arg.string + str_offset;
     garray_T	save_ga = cctx->ctx_instr;
     int		expr_res;
     int		trailing_error;
@@ -616,11 +617,24 @@ compile_string(isn_T *isn, cctx_T *cctx)
 }
 
 /*
+ * List of special functions for "compile_arguments".
+ */
+typedef enum {
+    CA_NOT_SPECIAL,
+    CA_SEARCHPAIR,	    // {skip} in searchpair() and searchpairpos()
+    CA_SUBSTITUTE,	    // {sub} in substitute(), when prefixed with \=
+} ca_special_T;
+
+/*
  * Compile the argument expressions.
  * "arg" points to just after the "(" and is advanced to after the ")"
  */
     static int
-compile_arguments(char_u **arg, cctx_T *cctx, int *argcount, int is_searchpair)
+compile_arguments(
+	char_u	     **arg,
+	cctx_T	     *cctx,
+	int	     *argcount,
+	ca_special_T special_fn)
 {
     char_u  *p = *arg;
     char_u  *whitep = *arg;
@@ -647,14 +661,25 @@ compile_arguments(char_u **arg, cctx_T *
 	    return FAIL;
 	++*argcount;
 
-	if (is_searchpair && *argcount == 5
+	if (special_fn == CA_SEARCHPAIR && *argcount == 5
 		&& cctx->ctx_instr.ga_len == instr_count + 1)
 	{
 	    isn_T *isn = ((isn_T *)cctx->ctx_instr.ga_data) + instr_count;
 
 	    // {skip} argument of searchpair() can be compiled if not empty
 	    if (isn->isn_type == ISN_PUSHS && *isn->isn_arg.string != NUL)
-		compile_string(isn, cctx);
+		compile_string(isn, cctx, 0);
+	}
+	else if (special_fn == CA_SUBSTITUTE && *argcount == 3
+		&& cctx->ctx_instr.ga_len == instr_count + 1)
+	{
+	    isn_T *isn = ((isn_T *)cctx->ctx_instr.ga_data) + instr_count;
+
+	    // {sub} argument of substitute() can be compiled if it starts
+	    // with \=
+	    if (isn->isn_type == ISN_PUSHS && isn->isn_arg.string[0] == '\\'
+		    && isn->isn_arg.string[1] == '=')
+		compile_string(isn, cctx, 2);
 	}
 
 	if (*p != ',' && *skipwhite(p) == ',')
@@ -706,7 +731,7 @@ compile_call(
     int		res = FAIL;
     int		is_autoload;
     int		has_g_namespace;
-    int		is_searchpair;
+    ca_special_T special_fn;
     imported_T	*import;
 
     if (varlen >= sizeof(namebuf))
@@ -776,13 +801,18 @@ compile_call(
 
     // We handle the "skip" argument of searchpair() and searchpairpos()
     // differently.
-    is_searchpair = (varlen == 6 && STRNCMP(*arg, "search", 6) == 0)
-	         || (varlen == 9 && STRNCMP(*arg, "searchpos", 9) == 0)
-	        || (varlen == 10 && STRNCMP(*arg, "searchpair", 10) == 0)
-	        || (varlen == 13 && STRNCMP(*arg, "searchpairpos", 13) == 0);
+    if ((varlen == 6 && STRNCMP(*arg, "search", 6) == 0)
+	    || (varlen == 9 && STRNCMP(*arg, "searchpos", 9) == 0)
+	    || (varlen == 10 && STRNCMP(*arg, "searchpair", 10) == 0)
+	    || (varlen == 13 && STRNCMP(*arg, "searchpairpos", 13) == 0))
+	special_fn = CA_SEARCHPAIR;
+    else if (varlen == 10 && STRNCMP(*arg, "substitute", 10) == 0)
+	special_fn = CA_SUBSTITUTE;
+    else
+	special_fn = CA_NOT_SPECIAL;
 
     *arg = skipwhite(*arg + varlen + 1);
-    if (compile_arguments(arg, cctx, &argcount, is_searchpair) == FAIL)
+    if (compile_arguments(arg, cctx, &argcount, special_fn) == FAIL)
 	goto theend;
 
     is_autoload = vim_strchr(name, AUTOLOAD_CHAR) != NULL;
@@ -1717,7 +1747,7 @@ compile_subscript(
 	    type = get_type_on_stack(cctx, 0);
 
 	    *arg = skipwhite(p + 1);
-	    if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL)
+	    if (compile_arguments(arg, cctx, &argcount, CA_NOT_SPECIAL) == FAIL)
 		return FAIL;
 	    if (generate_PCALL(cctx, argcount, name_start, type, TRUE) == FAIL)
 		return FAIL;
@@ -1848,7 +1878,8 @@ compile_subscript(
 		expr_isn_end = cctx->ctx_instr.ga_len;
 
 		*arg = skipwhite(*arg + 1);
-		if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL)
+		if (compile_arguments(arg, cctx, &argcount, CA_NOT_SPECIAL)
+								       == FAIL)
 		    return FAIL;
 
 		// Move the instructions for the arguments to before the