Patch 8.2.2124
Problem:    Vim9: a range cannot be computed at runtime.
Solution:   Add the ISN_RANGE instruction.
Files:      src/vim9.h, src/vim9compile.c, src/vim9execute.c,
            src/testdir/test_vim9_cmd.vim,
            src/testdir/test_vim9_disassemble.vim


*** ../vim-8.2.2123/src/vim9.h  2020-11-23 08:31:14.097789125 +0100
--- src/vim9.h  2020-12-09 19:36:11.914988439 +0100
***************
*** 18,23 ****
--- 18,24 ----
      ISN_EXECUTE,    // execute Ex commands isn_arg.number items on top of 
stack
      ISN_ECHOMSG,    // echo Ex commands isn_arg.number items on top of stack
      ISN_ECHOERR,    // echo Ex commands isn_arg.number items on top of stack
+     ISN_RANGE,            // compute range from isn_arg.string, push to stack
  
      // get and set variables
      ISN_LOAD,     // push local variable isn_arg.number
***************
*** 366,368 ****
--- 367,374 ----
  extern garray_T def_functions;
  #endif
  
+ // Used for "lnum" when a range is to be taken from the stack.
+ #define LNUM_VARIABLE_RANGE -999
+ 
+ // Used for "lnum" when a range is to be taken from the stack and "!" is used.
+ #define LNUM_VARIABLE_RANGE_ABOVE -888
*** ../vim-8.2.2123/src/vim9compile.c   2020-12-08 22:08:47.672125693 +0100
--- src/vim9compile.c   2020-12-10 19:42:52.365297164 +0100
***************
*** 1888,1893 ****
--- 1888,1913 ----
      return OK;
  }
  
+ /*
+  * Generate ISN_RANGE.  Consumes "range".  Return OK/FAIL.
+  */
+     static int
+ generate_RANGE(cctx_T *cctx, char_u *range)
+ {
+     isn_T     *isn;
+     garray_T  *stack = &cctx->ctx_type_stack;
+ 
+     if ((isn = generate_instr(cctx, ISN_RANGE)) == NULL)
+       return FAIL;
+     isn->isn_arg.string = range;
+ 
+     if (ga_grow(stack, 1) == FAIL)
+       return FAIL;
+     ((type_T **)stack->ga_data)[stack->ga_len] = &t_number;
+     ++stack->ga_len;
+     return OK;
+ }
+ 
      static int
  generate_UNPACK(cctx_T *cctx, int var_count, int semicolon)
  {
***************
*** 7099,7104 ****
--- 7119,7140 ----
  }
  
  /*
+  * If "eap" has a range that is not a contstant generate an ISN_RANGE
+  * instruction to compute it and return OK.
+  * Otherwise return FAIL, the caller must deal with any range.
+  */
+     static int
+ compile_variable_range(exarg_T *eap, cctx_T *cctx)
+ {
+     char_u *range_end = skip_range(eap->cmd, TRUE, NULL);
+     char_u *p = skipdigits(eap->cmd);
+ 
+     if (p == range_end)
+       return FAIL;
+     return generate_RANGE(cctx, vim_strnsave(eap->cmd, range_end - eap->cmd));
+ }
+ 
+ /*
   * :put r
   * :put ={expr}
   */
***************
*** 7123,7139 ****
      else if (eap->regname != NUL)
        ++line;
  
!     // "errormsg" will not be set because the range is ADDR_LINES.
!     // TODO: if the range contains something like "$" or "." need to evaluate
!     // at runtime
!     if (parse_cmd_address(eap, &errormsg, FALSE) == FAIL)
!       return NULL;
!     if (eap->addr_count == 0)
!       lnum = -1;
      else
!       lnum = eap->line2;
!     if (above)
!       --lnum;
  
      generate_PUT(cctx, eap->regname, lnum);
      return line;
--- 7159,7181 ----
      else if (eap->regname != NUL)
        ++line;
  
!     if (compile_variable_range(eap, cctx) == OK)
!     {
!       lnum = above ? LNUM_VARIABLE_RANGE_ABOVE : LNUM_VARIABLE_RANGE;
!     }
      else
!     {
!       // Either no range or a number.
!       // "errormsg" will not be set because the range is ADDR_LINES.
!       if (parse_cmd_address(eap, &errormsg, FALSE) == FAIL)
!           return NULL;
!       if (eap->addr_count == 0)
!           lnum = -1;
!       else
!           lnum = eap->line2;
!       if (above)
!           --lnum;
!     }
  
      generate_PUT(cctx, eap->regname, lnum);
      return line;
***************
*** 7960,7965 ****
--- 8002,8008 ----
        case ISN_PUSHEXC:
        case ISN_PUSHFUNC:
        case ISN_PUSHS:
+       case ISN_RANGE:
        case ISN_STOREB:
        case ISN_STOREENV:
        case ISN_STOREG:
*** ../vim-8.2.2123/src/vim9execute.c   2020-12-05 21:22:03.626811733 +0100
--- src/vim9execute.c   2020-12-09 21:47:43.623141586 +0100
***************
*** 2861,2866 ****
--- 2861,2886 ----
                }
                break;
  
+           case ISN_RANGE:
+               {
+                   exarg_T     ea;
+                   char        *errormsg;
+ 
+                   if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
+                       goto failed;
+                   ++ectx.ec_stack.ga_len;
+                   tv = STACK_TV_BOT(-1);
+                   ea.addr_type = ADDR_LINES;
+                   ea.cmd = iptr->isn_arg.string;
+                   if (parse_cmd_address(&ea, &errormsg, FALSE) == FAIL)
+                       goto failed;
+                   if (ea.addr_count == 0)
+                       tv->vval.v_number = curwin->w_cursor.lnum;
+                   else
+                       tv->vval.v_number = ea.line2;
+               }
+               break;
+ 
            case ISN_PUT:
                {
                    int         regname = iptr->isn_arg.put.put_regname;
***************
*** 2880,2886 ****
                        }
                        --ectx.ec_stack.ga_len;
                    }
!                   if (lnum == -2)
                        // :put! above cursor
                        dir = BACKWARD;
                    else if (lnum >= 0)
--- 2900,2915 ----
                        }
                        --ectx.ec_stack.ga_len;
                    }
!                   if (lnum < -2)
!                   {
!                       // line number was put on the stack by ISN_RANGE
!                       tv = STACK_TV_BOT(-1);
!                       curwin->w_cursor.lnum = tv->vval.v_number;
!                       if (lnum == LNUM_VARIABLE_RANGE_ABOVE)
!                           dir = BACKWARD;
!                       --ectx.ec_stack.ga_len;
!                   }
!                   else if (lnum == -2)
                        // :put! above cursor
                        dir = BACKWARD;
                    else if (lnum >= 0)
***************
*** 3690,3697 ****
            case ISN_2STRING_ANY: smsg("%4d 2STRING_ANY stack[%lld]", current,
                                         (long long)(iptr->isn_arg.number));
                              break;
            case ISN_PUT:
!               smsg("%4d PUT %c %ld", current, iptr->isn_arg.put.put_regname,
                                             (long)iptr->isn_arg.put.put_lnum);
                break;
  
--- 3719,3736 ----
            case ISN_2STRING_ANY: smsg("%4d 2STRING_ANY stack[%lld]", current,
                                         (long long)(iptr->isn_arg.number));
                              break;
+           case ISN_RANGE: smsg("%4d RANGE %s", current, iptr->isn_arg.string);
+                           break;
            case ISN_PUT:
!               if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE_ABOVE)
!                   smsg("%4d PUT %c above range",
!                                      current, iptr->isn_arg.put.put_regname);
!               else if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE)
!                   smsg("%4d PUT %c range",
!                                      current, iptr->isn_arg.put.put_regname);
!               else
!                   smsg("%4d PUT %c %ld", current,
!                                                iptr->isn_arg.put.put_regname,
                                             (long)iptr->isn_arg.put.put_lnum);
                break;
  
*** ../vim-8.2.2123/src/testdir/test_vim9_cmd.vim       2020-12-05 
17:11:09.241679401 +0100
--- src/testdir/test_vim9_cmd.vim       2020-12-09 22:02:08.095304957 +0100
***************
*** 614,619 ****
--- 614,630 ----
    assert_equal('above', getline(3))
    assert_equal('below', getline(4))
  
+   # compute range at runtime
+   setline(1, range(1, 8))
+   @a = 'aaa'
+   :$-2put a
+   assert_equal('aaa', getline(7))
+ 
+   setline(1, range(1, 8))
+   :2
+   :+2put! a
+   assert_equal('aaa', getline(4))
+ 
    bwipe!
  enddef
  
*** ../vim-8.2.2123/src/testdir/test_vim9_disassemble.vim       2020-12-02 
17:36:49.173409740 +0100
--- src/testdir/test_vim9_disassemble.vim       2020-12-09 21:57:08.792637746 
+0100
***************
*** 133,138 ****
--- 133,153 ----
          res)
  enddef
  
+ def s:PutRange()
+   :$-2put a
+ enddef
+ 
+ def Test_disassemble_put_range()
+   var res = execute('disass s:PutRange')
+   assert_match('<SNR>\d*_PutRange.*' ..
+         ' :$-2put a\_s*' ..
+         '\d RANGE $-2\_s*' ..
+         '\d PUT a range\_s*' ..
+         '\d PUSHNR 0\_s*' ..
+         '\d RETURN',
+         res)
+ enddef
+ 
  def s:ScriptFuncPush()
    var localbool = true
    var localspec = v:none
*** ../vim-8.2.2123/src/version.c       2020-12-09 18:13:40.713680179 +0100
--- src/version.c       2020-12-10 19:40:03.325837051 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2124,
  /**/

-- 
Behold the warranty!  The bold print giveth and the fine print taketh.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            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/202012101844.0BAIiM7q2270698%40masaka.moolenaar.net.

Raspunde prin e-mail lui