Patch 8.2.2789
Problem:    Vim9: using \=expr in :substitute does not handle jumps.
Solution:   Start with instruction count zero. (closes #8128)
Files:      src/vim9compile.c, src/testdir/test_vim9_cmd.vim


*** ../vim-8.2.2788/src/vim9compile.c   2021-04-19 21:06:27.454353644 +0200
--- src/vim9compile.c   2021-04-20 21:09:32.038843810 +0200
***************
*** 2179,2211 ****
      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.
   */
--- 2179,2184 ----
***************
*** 8522,8527 ****
--- 8495,8511 ----
      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/
   */
***************
*** 8536,8563 ****
        int delimiter = *cmd++;
  
        // There is a \=expr, find it in the substitute part.
!       cmd = skip_regexp_ex(cmd, delimiter, magic_isset(),
!                                                            NULL, NULL, NULL);
        if (cmd[0] == delimiter && cmd[1] == '\\' && cmd[2] == '=')
        {
!           int     instr_count = cctx->ctx_instr.ga_len;
!           char_u  *end;
  
            cmd += 3;
            end = skip_substitute(cmd, delimiter);
  
            compile_expr0(&cmd, cctx);
            if (end[-1] == NUL)
                end[-1] = delimiter;
            cmd = skipwhite(cmd);
!           if (*cmd != delimiter && *cmd != NUL)
!           {
!               semsg(_(e_trailing_arg), cmd);
                return NULL;
            }
  
!           if (generate_substitute(arg, instr_count, cctx) == FAIL)
                return NULL;
  
            // skip over flags
            if (*end == '&')
--- 8520,8580 ----
        int delimiter = *cmd++;
  
        // There is a \=expr, find it in the substitute part.
!       cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), NULL, NULL, NULL);
        if (cmd[0] == delimiter && cmd[1] == '\\' && cmd[2] == '=')
        {
!           garray_T    save_ga = cctx->ctx_instr;
!           char_u      *end;
!           int         trailing_error;
!           int         instr_count;
!           isn_T       *instr = NULL;
!           isn_T       *isn;
  
            cmd += 3;
            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);
            if (end[-1] == NUL)
                end[-1] = delimiter;
            cmd = skipwhite(cmd);
!           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)
!           {
!               if (trailing_error)
!                   semsg(_(e_trailing_arg), cmd);
!               clear_instr_ga(&cctx->ctx_instr);
!               cctx->ctx_instr = save_ga;
!               vim_free(instr);
                return NULL;
            }
  
!           // 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;
+           }
+           isn->isn_arg.subs.subs_cmd = vim_strsave(arg);
+           isn->isn_arg.subs.subs_instr = instr;
  
            // skip over flags
            if (*end == '&')
***************
*** 9285,9297 ****
  erret:
      if (ufunc->uf_def_status == UF_COMPILING)
      {
-       int idx;
        dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                         + ufunc->uf_dfunc_idx;
  
!       for (idx = 0; idx < instr->ga_len; ++idx)
!           delete_instr(((isn_T *)instr->ga_data) + idx);
!       ga_clear(instr);
        VIM_CLEAR(dfunc->df_name);
  
        // If using the last entry in the table and it was added above, we
--- 9302,9311 ----
  erret:
      if (ufunc->uf_def_status == UF_COMPILING)
      {
        dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                         + ufunc->uf_dfunc_idx;
  
!       clear_instr_ga(instr);
        VIM_CLEAR(dfunc->df_name);
  
        // If using the last entry in the table and it was added above, we
*** ../vim-8.2.2788/src/testdir/test_vim9_cmd.vim       2021-04-19 
20:49:58.156857538 +0200
--- src/testdir/test_vim9_cmd.vim       2021-04-20 21:05:13.535665815 +0200
***************
*** 1188,1193 ****
--- 1188,1199 ----
    s/from/\=to .. '_' .. also/g#e
    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"/9'], 'E488:')
  
*** ../vim-8.2.2788/src/version.c       2021-04-20 20:21:19.763851843 +0200
--- src/version.c       2021-04-20 21:10:16.838702338 +0200
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2789,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
131. You challenge authority and society by portnuking people

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202104201911.13KJBVl1915480%40masaka.moolenaar.net.

Raspunde prin e-mail lui