Patch 8.2.2834
Problem:    Vim9: :cexpr does not work with local variables.
Solution:   Compile :cexpr.
Files:      src/vim9compile.c, src/vim9.h, src/vim9execute.c, src/quickfix.c,
            src/proto/quickfix.pro, src/testdir/test_quickfix.vim,
            src/testdir/test_vim9_disassemble.vim


*** ../vim-8.2.2833/src/vim9compile.c   2021-04-25 13:54:38.988836743 +0200
--- src/vim9compile.c   2021-05-05 21:22:00.713708961 +0200
***************
*** 8704,8709 ****
--- 8704,8737 ----
      return compile_exec(line, eap, cctx);
  }
  
+     static char_u *
+ compile_cexpr(char_u *line, exarg_T *eap, cctx_T *cctx)
+ {
+     isn_T     *isn;
+     char_u    *p;
+ 
+     isn = generate_instr(cctx, ISN_CEXPR_AUCMD);
+     if (isn == NULL)
+       return NULL;
+     isn->isn_arg.number = eap->cmdidx;
+ 
+     p = eap->arg;
+     if (compile_expr0(&p, cctx) == FAIL)
+       return NULL;
+ 
+     isn = generate_instr(cctx, ISN_CEXPR_CORE);
+     if (isn == NULL)
+       return NULL;
+     isn->isn_arg.cexpr.cexpr_ref = ALLOC_ONE(cexprref_T);
+     if (isn->isn_arg.cexpr.cexpr_ref == NULL)
+       return NULL;
+     isn->isn_arg.cexpr.cexpr_ref->cer_cmdidx = eap->cmdidx;
+     isn->isn_arg.cexpr.cexpr_ref->cer_forceit = eap->forceit;
+     isn->isn_arg.cexpr.cexpr_ref->cer_cmdline = vim_strsave(skipwhite(line));
+ 
+     return p;
+ }
+ 
  /*
   * Add a function to the list of :def functions.
   * This sets "ufunc->uf_dfunc_idx" but the function isn't compiled yet.
***************
*** 9262,9267 ****
--- 9290,9305 ----
                    line = compile_redir(line, &ea, &cctx);
                    break;
  
+           case CMD_cexpr:
+           case CMD_lexpr:
+           case CMD_caddexpr:
+           case CMD_laddexpr:
+           case CMD_cgetexpr:
+           case CMD_lgetexpr:
+                   ea.arg = p;
+                   line = compile_cexpr(line, &ea, &cctx);
+                   break;
+ 
            // TODO: any other commands with an expression argument?
  
            case CMD_append:
***************
*** 9602,9607 ****
--- 9640,9649 ----
            vim_free(isn->isn_arg.try.try_ref);
            break;
  
+       case ISN_CEXPR_CORE:
+           vim_free(isn->isn_arg.cexpr.cexpr_ref);
+           break;
+ 
        case ISN_2BOOL:
        case ISN_2STRING:
        case ISN_2STRING_ANY:
***************
*** 9614,9619 ****
--- 9656,9662 ----
        case ISN_BLOBINDEX:
        case ISN_BLOBSLICE:
        case ISN_CATCH:
+       case ISN_CEXPR_AUCMD:
        case ISN_CHECKLEN:
        case ISN_CHECKNR:
        case ISN_CMDMOD_REV:
*** ../vim-8.2.2833/src/vim9.h  2021-04-26 20:32:54.918399234 +0200
--- src/vim9.h  2021-05-05 21:08:23.319561182 +0200
***************
*** 172,177 ****
--- 172,180 ----
      ISN_REDIRSTART, // :redir =>
      ISN_REDIREND,   // :redir END, isn_arg.number == 1 for append
  
+     ISN_CEXPR_AUCMD, // first part of :cexpr  isn_arg.number is cmdidx
+     ISN_CEXPR_CORE,  // second part of :cexpr, uses isn_arg.cexpr
+ 
      ISN_FINISH            // end marker in list of instructions
  } isntype_T;
  
***************
*** 352,357 ****
--- 355,372 ----
      isn_T     *subs_instr;    // sequence of instructions
  } subs_T;
  
+ // indirect arguments to ISN_TRY
+ typedef struct {
+     int               cer_cmdidx;
+     char_u    *cer_cmdline;
+     int               cer_forceit;
+ } cexprref_T;
+ 
+ // arguments to ISN_CEXPR_CORE
+ typedef struct {
+     cexprref_T *cexpr_ref;
+ } cexpr_T;
+ 
  /*
   * Instruction
   */
***************
*** 395,400 ****
--- 410,416 ----
        unpack_T            unpack;
        isn_outer_T         outer;
        subs_T              subs;
+       cexpr_T             cexpr;
      } isn_arg;
  };
  
*** ../vim-8.2.2833/src/vim9execute.c   2021-04-26 21:34:43.708519638 +0200
--- src/vim9execute.c   2021-05-05 21:19:31.250055070 +0200
***************
*** 1442,1447 ****
--- 1442,1470 ----
                }
                break;
  
+           case ISN_CEXPR_AUCMD:
+               if (trigger_cexpr_autocmd(iptr->isn_arg.number) == FAIL)
+                   goto on_error;
+               break;
+ 
+           case ISN_CEXPR_CORE:
+               {
+                   exarg_T ea;
+                   int     res;
+ 
+                   CLEAR_FIELD(ea);
+                   ea.cmdidx = iptr->isn_arg.cexpr.cexpr_ref->cer_cmdidx;
+                   ea.forceit = iptr->isn_arg.cexpr.cexpr_ref->cer_forceit;
+                   ea.cmdlinep = &iptr->isn_arg.cexpr.cexpr_ref->cer_cmdline;
+                   --ectx->ec_stack.ga_len;
+                   tv = STACK_TV_BOT(0);
+                   res = cexpr_core(&ea, tv);
+                   clear_tv(tv);
+                   if (res == FAIL)
+                       goto on_error;
+               }
+               break;
+ 
            // execute Ex command from pieces on the stack
            case ISN_EXECCONCAT:
                {
***************
*** 4391,4396 ****
--- 4414,4433 ----
                smsg("%s%4d REDIR END%s", pfx, current,
                                        iptr->isn_arg.number ? " append" : "");
                break;
+           case ISN_CEXPR_AUCMD:
+               smsg("%s%4d CEXPR pre %s", pfx, current,
+                                      cexpr_get_auname(iptr->isn_arg.number));
+               break;
+           case ISN_CEXPR_CORE:
+               {
+                   cexprref_T      *cer = iptr->isn_arg.cexpr.cexpr_ref;
+ 
+                   smsg("%s%4d CEXPR core %s%s \"%s\"", pfx, current,
+                                      cexpr_get_auname(cer->cer_cmdidx),
+                                      cer->cer_forceit ? "!" : "",
+                                      cer->cer_cmdline);
+               }
+               break;
            case ISN_SUBSTITUTE:
                {
                    subs_T *subs = &iptr->isn_arg.subs;
*** ../vim-8.2.2833/src/quickfix.c      2021-05-03 18:57:02.392070898 +0200
--- src/quickfix.c      2021-05-05 21:16:02.518534404 +0200
***************
*** 7864,7870 ****
  /*
   * Return the autocmd name for the :cexpr Ex commands.
   */
!     static char_u *
  cexpr_get_auname(cmdidx_T cmdidx)
  {
      switch (cmdidx)
--- 7864,7870 ----
  /*
   * Return the autocmd name for the :cexpr Ex commands.
   */
!     char_u *
  cexpr_get_auname(cmdidx_T cmdidx)
  {
      switch (cmdidx)
***************
*** 7879,7910 ****
      }
  }
  
! /*
!  * ":cexpr {expr}", ":cgetexpr {expr}", ":caddexpr {expr}" command.
!  * ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command.
!  */
!     void
! ex_cexpr(exarg_T *eap)
  {
!     typval_T  *tv;
!     qf_info_T *qi;
!     char_u    *au_name = NULL;
!     int               res;
!     int_u     save_qfid;
!     win_T     *wp = NULL;
  
-     au_name = cexpr_get_auname(eap->cmdidx);
      if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
                                               curbuf->b_fname, TRUE, curbuf))
      {
- #ifdef FEAT_EVAL
        if (aborting())
!           return;
! #endif
      }
  
      qi = qf_cmd_get_or_alloc_stack(eap, &wp);
      if (qi == NULL)
        return;
  
      // Evaluate the expression.  When the result is a string or a list we can
--- 7879,7961 ----
      }
  }
  
!     int
! trigger_cexpr_autocmd(int cmdidx)
  {
!     char_u    *au_name = cexpr_get_auname(cmdidx);
  
      if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
                                               curbuf->b_fname, TRUE, curbuf))
      {
        if (aborting())
!           return FAIL;
      }
+     return OK;
+ }
+ 
+     int
+ cexpr_core(exarg_T *eap, typval_T *tv)
+ {
+     qf_info_T *qi;
+     win_T     *wp = NULL;
  
      qi = qf_cmd_get_or_alloc_stack(eap, &wp);
      if (qi == NULL)
+       return FAIL;
+ 
+     if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL)
+           || (tv->v_type == VAR_LIST && tv->vval.v_list != NULL))
+     {
+       int     res;
+       int_u   save_qfid;
+       char_u  *au_name = cexpr_get_auname(eap->cmdidx);
+ 
+       incr_quickfix_busy();
+       res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, tv, p_efm,
+                       (eap->cmdidx != CMD_caddexpr
+                        && eap->cmdidx != CMD_laddexpr),
+                            (linenr_T)0, (linenr_T)0,
+                            qf_cmdtitle(*eap->cmdlinep), NULL);
+       if (qf_stack_empty(qi))
+       {
+           decr_quickfix_busy();
+           return FAIL;
+       }
+       if (res >= 0)
+           qf_list_changed(qf_get_curlist(qi));
+ 
+       // Remember the current quickfix list identifier, so that we can
+       // check for autocommands changing the current quickfix list.
+       save_qfid = qf_get_curlist(qi)->qf_id;
+       if (au_name != NULL)
+           apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
+                                           curbuf->b_fname, TRUE, curbuf);
+ 
+       // Jump to the first error for a new list and if autocmds didn't
+       // free the list.
+       if (res > 0 && (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr)
+               && qflist_valid(wp, save_qfid))
+           // display the first error
+           qf_jump_first(qi, save_qfid, eap->forceit);
+       decr_quickfix_busy();
+       return OK;
+     }
+ 
+     emsg(_("E777: String or List expected"));
+     return FAIL;
+ }
+ 
+ /*
+  * ":cexpr {expr}", ":cgetexpr {expr}", ":caddexpr {expr}" command.
+  * ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command.
+  * Also: ":caddexpr", ":cgetexpr", "laddexpr" and "laddexpr".
+  */
+     void
+ ex_cexpr(exarg_T *eap)
+ {
+     typval_T  *tv;
+ 
+     if (trigger_cexpr_autocmd(eap->cmdidx) == FAIL)
        return;
  
      // Evaluate the expression.  When the result is a string or a list we can
***************
*** 7912,7953 ****
      tv = eval_expr(eap->arg, eap);
      if (tv != NULL)
      {
!       if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL)
!               || (tv->v_type == VAR_LIST && tv->vval.v_list != NULL))
!       {
!           incr_quickfix_busy();
!           res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, tv, p_efm,
!                           (eap->cmdidx != CMD_caddexpr
!                            && eap->cmdidx != CMD_laddexpr),
!                                (linenr_T)0, (linenr_T)0,
!                                qf_cmdtitle(*eap->cmdlinep), NULL);
!           if (qf_stack_empty(qi))
!           {
!               decr_quickfix_busy();
!               goto cleanup;
!           }
!           if (res >= 0)
!               qf_list_changed(qf_get_curlist(qi));
! 
!           // Remember the current quickfix list identifier, so that we can
!           // check for autocommands changing the current quickfix list.
!           save_qfid = qf_get_curlist(qi)->qf_id;
!           if (au_name != NULL)
!               apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
!                                               curbuf->b_fname, TRUE, curbuf);
! 
!           // Jump to the first error for a new list and if autocmds didn't
!           // free the list.
!           if (res > 0 && (eap->cmdidx == CMD_cexpr
!                                                  || eap->cmdidx == CMD_lexpr)
!                   && qflist_valid(wp, save_qfid))
!               // display the first error
!               qf_jump_first(qi, save_qfid, eap->forceit);
!           decr_quickfix_busy();
!       }
!       else
!           emsg(_("E777: String or List expected"));
! cleanup:
        free_tv(tv);
      }
  }
--- 7963,7969 ----
      tv = eval_expr(eap->arg, eap);
      if (tv != NULL)
      {
!       (void)cexpr_core(eap, tv);
        free_tv(tv);
      }
  }
*** ../vim-8.2.2833/src/proto/quickfix.pro      2020-07-20 21:31:01.268823457 
+0200
--- src/proto/quickfix.pro      2021-05-05 21:16:06.846524534 +0200
***************
*** 30,35 ****
--- 30,38 ----
  int set_errorlist(win_T *wp, list_T *list, int action, char_u *title, dict_T 
*what);
  int set_ref_in_quickfix(int copyID);
  void ex_cbuffer(exarg_T *eap);
+ char_u *cexpr_get_auname(cmdidx_T cmdidx);
+ int trigger_cexpr_autocmd(int cmdidx);
+ int cexpr_core(exarg_T *eap, typval_T *tv);
  void ex_cexpr(exarg_T *eap);
  void ex_helpgrep(exarg_T *eap);
  void f_getloclist(typval_T *argvars, typval_T *rettv);
*** ../vim-8.2.2833/src/testdir/test_quickfix.vim       2021-04-26 
21:14:12.713924760 +0200
--- src/testdir/test_quickfix.vim       2021-05-05 21:25:42.969191409 +0200
***************
*** 722,727 ****
--- 722,743 ----
    helpclose
  enddef
  
+ def Test_vim9_cexpr()
+   var text = 'somefile:95:error'
+   cexpr text
+   var l = getqflist()
+   assert_equal(1, l->len())
+   assert_equal(95, l[0].lnum)
+   assert_equal('error', l[0].text)
+ 
+   text = 'somefile:77:warning'
+   caddexpr text
+   l = getqflist()
+   assert_equal(2, l->len())
+   assert_equal(77, l[1].lnum)
+   assert_equal('warning', l[1].text)
+ enddef
+ 
  func Test_errortitle()
    augroup QfBufWinEnter
      au!
*** ../vim-8.2.2833/src/testdir/test_vim9_disassemble.vim       2021-04-20 
22:16:35.355248931 +0200
--- src/testdir/test_vim9_disassemble.vim       2021-05-05 21:29:49.304542273 
+0200
***************
*** 167,172 ****
--- 167,191 ----
          res)
  enddef
  
+ def s:Cexpr()
+   var errors = "list of errors"
+   cexpr errors
+ enddef
+ 
+ def Test_disassemble_cexpr()
+   var res = execute('disass s:Cexpr')
+   assert_match('<SNR>\d*_Cexpr.*' ..
+         ' var errors = "list of errors"\_s*' ..
+         '\d PUSHS "list of errors"\_s*' ..
+         '\d STORE $0\_s*' ..
+         ' cexpr errors\_s*' ..
+         '\d CEXPR pre cexpr\_s*' ..
+         '\d LOAD $0\_s*' ..
+         '\d CEXPR core cexpr "cexpr errors"\_s*' ..
+         '\d RETURN 0',
+         res)
+ enddef
+ 
  def s:YankRange()
    norm! m[jjm]
    :'[,']yank
*** ../vim-8.2.2833/src/version.c       2021-05-05 19:58:12.921605195 +0200
--- src/version.c       2021-05-05 21:30:47.388251203 +0200
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2834,
  /**/

-- 
The term "free software" is defined by Richard M. Stallman as
being software that isn't necessarily for free.  Confusing?
Let's call it "Stallman software" then!
                                -- Bram Moolenaar

 /// 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/202105051932.145JWDln885076%40masaka.moolenaar.net.

Raspunde prin e-mail lui