Patch 8.2.0987
Problem:    Vim9: cannot assign to [var; var].
Solution:   Assign rest of items to a list.
Files:      src/vim9.h, src/vim9compile.c, src/vim9execute.c, src/list.c,
            src/proto/list.pro, src/eval.c, src/testdir/test_vim9_script.vim


*** ../vim-8.2.0986/src/vim9.h  2020-06-14 23:05:06.368915209 +0200
--- src/vim9.h  2020-06-15 22:48:24.275377042 +0200
***************
*** 112,117 ****
--- 112,118 ----
      // expression operations
      ISN_CONCAT,
      ISN_INDEX,            // [expr] list index
+     ISN_SLICE,            // drop isn_arg.number items from start of list
      ISN_GETITEM,    // push list item, isn_arg.number is the index
      ISN_MEMBER,           // dict[member]
      ISN_STRINGMEMBER, // dict.member using isn_arg.string
***************
*** 121,126 ****
--- 122,128 ----
  
      ISN_CHECKNR,    // check value can be used as a number
      ISN_CHECKTYPE,  // check value type is isn_arg.type.tc_type
+     ISN_CHECKLEN,   // check list length is isn_arg.checklen.cl_min_len
  
      ISN_DROP      // pop stack and discard value
  } isntype_T;
***************
*** 229,234 ****
--- 231,242 ----
      int               fr_var_idx;     // variable to store partial
  } funcref_T;
  
+ // arguments to ISN_CHECKLEN
+ typedef struct {
+     int               cl_min_len;     // minimum length
+     int               cl_more_OK;     // longer is allowed
+ } checklen_T;
+ 
  /*
   * Instruction
   */
***************
*** 261,266 ****
--- 269,275 ----
        script_T            script;
        unlet_T             unlet;
        funcref_T           funcref;
+       checklen_T          checklen;
      } isn_arg;
  };
  
*** ../vim-8.2.0986/src/vim9compile.c   2020-06-14 23:05:06.368915209 +0200
--- src/vim9compile.c   2020-06-15 23:32:12.648856410 +0200
***************
*** 1086,1091 ****
--- 1086,1124 ----
  }
  
  /*
+  * Generate an ISN_SLICE instruction with "count".
+  */
+     static int
+ generate_SLICE(cctx_T *cctx, int count)
+ {
+     isn_T     *isn;
+ 
+     RETURN_OK_IF_SKIP(cctx);
+     if ((isn = generate_instr(cctx, ISN_SLICE)) == NULL)
+       return FAIL;
+     isn->isn_arg.number = count;
+     return OK;
+ }
+ 
+ /*
+  * Generate an ISN_CHECKLEN instruction with "min_len".
+  */
+     static int
+ generate_CHECKLEN(cctx_T *cctx, int min_len, int more_OK)
+ {
+     isn_T     *isn;
+ 
+     RETURN_OK_IF_SKIP(cctx);
+ 
+     if ((isn = generate_instr(cctx, ISN_CHECKLEN)) == NULL)
+       return FAIL;
+     isn->isn_arg.checklen.cl_min_len = min_len;
+     isn->isn_arg.checklen.cl_more_OK = more_OK;
+ 
+     return OK;
+ }
+ 
+ /*
   * Generate an ISN_STORE instruction.
   */
      static int
***************
*** 4708,4715 ****
            }
            if (need_type(stacktype, &t_list_any, -1, cctx) == FAIL)
                goto theend;
!           // TODO: check length of list to be var_count (or more if
!           // "semicolon" set)
        }
      }
  
--- 4741,4748 ----
            }
            if (need_type(stacktype, &t_list_any, -1, cctx) == FAIL)
                goto theend;
!           generate_CHECKLEN(cctx, semicolon ? var_count - 1 : var_count,
!                                                                   semicolon);
        }
      }
  
***************
*** 5066,5071 ****
--- 5099,5110 ----
                    if (r == FAIL)
                        goto theend;
                }
+               else if (semicolon && var_idx == var_count - 1)
+               {
+                   // For "[var; var] = expr" get the rest of the list
+                   if (generate_SLICE(cctx, var_count - 1) == FAIL)
+                       goto theend;
+               }
                else
                {
                    // For "[var, var] = expr" get the "var_idx" item from the
***************
*** 5373,5380 ****
      }
  
      // for "[var, var] = expr" drop the "expr" value
!     if (var_count > 0 && generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
!       goto theend;
  
      ret = end;
  
--- 5412,5422 ----
      }
  
      // for "[var, var] = expr" drop the "expr" value
!     if (var_count > 0 && !semicolon)
!     {
!           if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
!           goto theend;
!     }
  
      ret = end;
  
***************
*** 7073,7078 ****
--- 7115,7121 ----
        case ISN_CATCH:
        case ISN_CHECKNR:
        case ISN_CHECKTYPE:
+       case ISN_CHECKLEN:
        case ISN_COMPAREANY:
        case ISN_COMPAREBLOB:
        case ISN_COMPAREBOOL:
***************
*** 7095,7100 ****
--- 7138,7144 ----
        case ISN_FOR:
        case ISN_INDEX:
        case ISN_GETITEM:
+       case ISN_SLICE:
        case ISN_MEMBER:
        case ISN_JUMP:
        case ISN_LOAD:
*** ../vim-8.2.0986/src/vim9execute.c   2020-06-14 23:05:06.368915209 +0200
--- src/vim9execute.c   2020-06-15 23:11:27.334195540 +0200
***************
*** 2114,2119 ****
--- 2114,2148 ----
                }
                break;
  
+           case ISN_SLICE:
+               {
+                   list_T      *list;
+                   int         count = iptr->isn_arg.number;
+ 
+                   tv = STACK_TV_BOT(-1);
+                   if (tv->v_type != VAR_LIST)
+                   {
+                       emsg(_(e_listreq));
+                       goto failed;
+                   }
+                   list = tv->vval.v_list;
+ 
+                   // no error for short list, expect it to be checked earlier
+                   if (list != NULL && list->lv_len >= count)
+                   {
+                       list_T  *newlist = list_slice(list,
+                                                     count, list->lv_len - 1);
+ 
+                       if (newlist != NULL)
+                       {
+                           list_unref(list);
+                           tv->vval.v_list = newlist;
+                           ++newlist->lv_refcount;
+                       }
+                   }
+               }
+               break;
+ 
            case ISN_GETITEM:
                {
                    listitem_T  *li;
***************
*** 2243,2248 ****
--- 2272,2296 ----
                }
                break;
  
+           case ISN_CHECKLEN:
+               {
+                   int     min_len = iptr->isn_arg.checklen.cl_min_len;
+                   list_T  *list = NULL;
+ 
+                   tv = STACK_TV_BOT(-1);
+                   if (tv->v_type == VAR_LIST)
+                           list = tv->vval.v_list;
+                   if (list == NULL || list->lv_len < min_len
+                           || (list->lv_len > min_len
+                                       && !iptr->isn_arg.checklen.cl_more_OK))
+                   {
+                       semsg(_("E1093: Expected %d items but got %d"),
+                                    min_len, list == NULL ? 0 : list->lv_len);
+                       goto failed;
+                   }
+               }
+               break;
+ 
            case ISN_2BOOL:
                {
                    int n;
***************
*** 2814,2819 ****
--- 2862,2869 ----
            // expression operations
            case ISN_CONCAT: smsg("%4d CONCAT", current); break;
            case ISN_INDEX: smsg("%4d INDEX", current); break;
+           case ISN_SLICE: smsg("%4d SLICE %lld",
+                                        current, iptr->isn_arg.number); break;
            case ISN_GETITEM: smsg("%4d ITEM %lld",
                                         current, iptr->isn_arg.number); break;
            case ISN_MEMBER: smsg("%4d MEMBER", current); break;
***************
*** 2826,2831 ****
--- 2876,2885 ----
                                      vartype_name(iptr->isn_arg.type.ct_type),
                                      iptr->isn_arg.type.ct_off);
                                break;
+           case ISN_CHECKLEN: smsg("%4d CHECKLEN %s%d", current,
+                               iptr->isn_arg.checklen.cl_more_OK ? ">= " : "",
+                               iptr->isn_arg.checklen.cl_min_len);
+                              break;
            case ISN_2BOOL: if (iptr->isn_arg.number)
                                smsg("%4d INVERT (!val)", current);
                            else
*** ../vim-8.2.0986/src/list.c  2020-06-09 17:30:00.515654723 +0200
--- src/list.c  2020-06-15 22:59:51.748896684 +0200
***************
*** 868,873 ****
--- 868,893 ----
      return list_extend(l, l2, NULL);
  }
  
+     list_T *
+ list_slice(list_T *ol, long n1, long n2)
+ {
+     listitem_T        *item;
+     list_T    *l = list_alloc();
+ 
+     if (l == NULL)
+       return NULL;
+     for (item = list_find(ol, n1); n1 <= n2; ++n1)
+     {
+       if (list_append_tv(l, &item->li_tv) == FAIL)
+       {
+           list_free(l);
+           return NULL;
+       }
+       item = item->li_next;
+     }
+     return l;
+ }
+ 
  /*
   * Make a copy of list "orig".  Shallow if "deep" is FALSE.
   * The refcount of the new list is set to 1.
*** ../vim-8.2.0986/src/proto/list.pro  2020-06-08 20:50:23.432250668 +0200
--- src/proto/list.pro  2020-06-15 22:58:01.197315413 +0200
***************
*** 33,38 ****
--- 33,39 ----
  void f_flatten(typval_T *argvars, typval_T *rettv);
  int list_extend(list_T *l1, list_T *l2, listitem_T *bef);
  int list_concat(list_T *l1, list_T *l2, typval_T *tv);
+ list_T *list_slice(list_T *ol, long n1, long n2);
  list_T *list_copy(list_T *orig, int deep, int copyID);
  void vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2);
  char_u *list2string(typval_T *tv, int copyID, int restore_copyID);
*** ../vim-8.2.0986/src/eval.c  2020-06-14 23:05:06.368915209 +0200
--- src/eval.c  2020-06-15 22:56:59.417546807 +0200
***************
*** 3237,3243 ****
                if (range)
                {
                    list_T      *l;
-                   listitem_T  *item;
  
                    if (n2 < 0)
                        n2 = len + n2;
--- 3237,3242 ----
***************
*** 3245,3263 ****
                        n2 = len - 1;
                    if (!empty2 && (n2 < 0 || n2 + 1 < n1))
                        n2 = -1;
!                   l = list_alloc();
                    if (l == NULL)
                        return FAIL;
-                   for (item = list_find(rettv->vval.v_list, n1);
-                                                              n1 <= n2; ++n1)
-                   {
-                       if (list_append_tv(l, &item->li_tv) == FAIL)
-                       {
-                           list_free(l);
-                           return FAIL;
-                       }
-                       item = item->li_next;
-                   }
                    clear_tv(rettv);
                    rettv_list_set(rettv, l);
                }
--- 3244,3252 ----
                        n2 = len - 1;
                    if (!empty2 && (n2 < 0 || n2 + 1 < n1))
                        n2 = -1;
!                   l = list_slice(rettv->vval.v_list, n1, n2);
                    if (l == NULL)
                        return FAIL;
                    clear_tv(rettv);
                    rettv_list_set(rettv, l);
                }
*** ../vim-8.2.0986/src/testdir/test_vim9_script.vim    2020-06-14 
23:05:06.368915209 +0200
--- src/testdir/test_vim9_script.vim    2020-06-15 23:13:36.557686502 +0200
***************
*** 226,234 ****
--- 226,248 ----
  def Test_assignment_var_list()
    let v1: string
    let v2: string
+   let vrem: list<string>
+   [v1] = ['aaa']
+   assert_equal('aaa', v1)
+ 
    [v1, v2] = ['one', 'two']
    assert_equal('one', v1)
    assert_equal('two', v2)
+ 
+   [v1, v2; vrem] = ['one', 'two']
+   assert_equal('one', v1)
+   assert_equal('two', v2)
+   assert_equal([], vrem)
+ 
+   [v1, v2; vrem] = ['one', 'two', 'three']
+   assert_equal('one', v1)
+   assert_equal('two', v2)
+   assert_equal(['three'], vrem)
  enddef
  
  def Mess(): string
***************
*** 244,250 ****
    call CheckDefFailure(['let true = 1'], 'E1034:')
    call CheckDefFailure(['let false = 1'], 'E1034:')
  
!   call CheckDefFailure(['let [a; b; c] = g:list'], 'E452:')
  
    call CheckDefFailure(['let somevar'], "E1022:")
    call CheckDefFailure(['let &option'], 'E1052:')
--- 258,275 ----
    call CheckDefFailure(['let true = 1'], 'E1034:')
    call CheckDefFailure(['let false = 1'], 'E1034:')
  
!   call CheckDefFailure(['[a; b; c] = g:list'], 'E452:')
!   call CheckDefExecFailure(['let a: number',
!                             '[a] = test_null_list()'], 'E1093:')
!   call CheckDefExecFailure(['let a: number',
!                             '[a] = []'], 'E1093:')
!   call CheckDefExecFailure(['let x: number',
!                             'let y: number',
!                             '[x, y] = [1]'], 'E1093:')
!   call CheckDefExecFailure(['let x: number',
!                             'let y: number',
!                             'let z: list<number>',
!                             '[x, y; z] = [1]'], 'E1093:')
  
    call CheckDefFailure(['let somevar'], "E1022:")
    call CheckDefFailure(['let &option'], 'E1052:')
*** ../vim-8.2.0986/src/version.c       2020-06-15 23:18:08.924482716 +0200
--- src/version.c       2020-06-16 11:31:59.066790757 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     987,
  /**/

-- 
ARTHUR:  Bloody peasant!
DENNIS:  Oh, what a give away.  Did you hear that, did you hear that, eh?
         That's what I'm on about -- did you see him repressing me, you saw it
         didn't you?
                                  The Quest for the Holy Grail (Monty Python)

 /// Bram Moolenaar -- b...@moolenaar.net -- 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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202006160936.05G9a9T71312523%40masaka.moolenaar.net.

Raspunde prin e-mail lui