Patch 8.2.1463
Problem:    Vim9: list slice not supported yet.
Solution:   Add support for list slicing.
Files:      src/vim9compile.c, src/vim9.h, src/vim9execute.c, src/eval.c,
            src/list.c, src/proto/list.pro, src/testdir/test_vim9_expr.vim,
            src/testdir/test_vim9_disassemble.vim


*** ../vim-8.2.1462/src/vim9compile.c   2020-08-15 21:09:03.281675788 +0200
--- src/vim9compile.c   2020-08-15 21:30:07.177766759 +0200
***************
*** 3171,3183 ****
            {
                if (is_slice)
                {
!                   emsg("Sorry, list slice not implemented yet");
!                   return FAIL;
                }
-               if ((*typep)->tt_type == VAR_LIST)
-                   *typep = (*typep)->tt_member;
-               if (generate_instr_drop(cctx, ISN_LISTINDEX, 1) == FAIL)
-                   return FAIL;
            }
            else
            {
--- 3171,3186 ----
            {
                if (is_slice)
                {
!                   if (generate_instr_drop(cctx, ISN_LISTSLICE, 2) == FAIL)
!                       return FAIL;
!               }
!               else
!               {
!                   if ((*typep)->tt_type == VAR_LIST)
!                       *typep = (*typep)->tt_member;
!                   if (generate_instr_drop(cctx, ISN_LISTINDEX, 1) == FAIL)
!                       return FAIL;
                }
            }
            else
            {
***************
*** 7095,7100 ****
--- 7098,7104 ----
        case ISN_EXECUTE:
        case ISN_FOR:
        case ISN_LISTINDEX:
+       case ISN_LISTSLICE:
        case ISN_STRINDEX:
        case ISN_STRSLICE:
        case ISN_GETITEM:
*** ../vim-8.2.1462/src/vim9.h  2020-08-15 21:09:03.281675788 +0200
--- src/vim9.h  2020-08-15 21:29:53.329859397 +0200
***************
*** 119,124 ****
--- 119,125 ----
      ISN_STRINDEX,   // [expr] string index
      ISN_STRSLICE,   // [expr:expr] string slice
      ISN_LISTINDEX,  // [expr] list index
+     ISN_LISTSLICE,  // [expr:expr] list slice
      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]
*** ../vim-8.2.1462/src/vim9execute.c   2020-08-15 21:09:03.281675788 +0200
--- src/vim9execute.c   2020-08-15 22:02:02.665053762 +0200
***************
*** 2286,2299 ****
                break;
  
            case ISN_LISTINDEX:
                {
                    list_T      *list;
!                   varnumber_T n;
                    listitem_T  *li;
-                   typval_T    temp_tv;
  
                    // list index: list is at stack-2, index at stack-1
!                   tv = STACK_TV_BOT(-2);
                    if (tv->v_type != VAR_LIST)
                    {
                        SOURCING_LNUM = iptr->isn_lnum;
--- 2286,2302 ----
                break;
  
            case ISN_LISTINDEX:
+           case ISN_LISTSLICE:
                {
+                   int         is_slice = iptr->isn_type == ISN_LISTSLICE;
                    list_T      *list;
!                   varnumber_T n1, n2;
                    listitem_T  *li;
  
                    // list index: list is at stack-2, index at stack-1
!                   // list slice: list is at stack-3, indexes at stack-2 and
!                   // stack-1
!                   tv = is_slice ? STACK_TV_BOT(-3) : STACK_TV_BOT(-2);
                    if (tv->v_type != VAR_LIST)
                    {
                        SOURCING_LNUM = iptr->isn_lnum;
***************
*** 2309,2329 ****
                        emsg(_(e_number_exp));
                        goto on_error;
                    }
!                   n = tv->vval.v_number;
                    clear_tv(tv);
!                   if ((li = list_find(list, n)) == NULL)
                    {
!                       SOURCING_LNUM = iptr->isn_lnum;
!                       semsg(_(e_listidx), n);
!                       goto on_error;
                    }
!                   --ectx.ec_stack.ga_len;
!                   // Clear the list after getting the item, to avoid that it
!                   // makes the item invalid.
                    tv = STACK_TV_BOT(-1);
!                   temp_tv = *tv;
!                   copy_tv(&li->li_tv, tv);
!                   clear_tv(&temp_tv);
                }
                break;
  
--- 2312,2338 ----
                        emsg(_(e_number_exp));
                        goto on_error;
                    }
!                   n1 = n2 = tv->vval.v_number;
                    clear_tv(tv);
! 
!                   if (is_slice)
                    {
!                       tv = STACK_TV_BOT(-2);
!                       if (tv->v_type != VAR_NUMBER)
!                       {
!                           SOURCING_LNUM = iptr->isn_lnum;
!                           emsg(_(e_number_exp));
!                           goto on_error;
!                       }
!                       n1 = tv->vval.v_number;
!                       clear_tv(tv);
                    }
! 
!                   ectx.ec_stack.ga_len -= is_slice ? 2 : 1;
                    tv = STACK_TV_BOT(-1);
!                   if (list_slice_or_index(list, is_slice, n1, n2, tv, TRUE)
!                                                                      == FAIL)
!                       goto on_error;
                }
                break;
  
***************
*** 3162,3167 ****
--- 3171,3177 ----
            case ISN_STRINDEX: smsg("%4d STRINDEX", current); break;
            case ISN_STRSLICE: smsg("%4d STRSLICE", current); break;
            case ISN_LISTINDEX: smsg("%4d LISTINDEX", current); break;
+           case ISN_LISTSLICE: smsg("%4d LISTSLICE", current); break;
            case ISN_SLICE: smsg("%4d SLICE %lld",
                                         current, iptr->isn_arg.number); break;
            case ISN_GETITEM: smsg("%4d ITEM %lld",
*** ../vim-8.2.1462/src/eval.c  2020-08-15 21:09:03.281675788 +0200
--- src/eval.c  2020-08-15 22:03:24.532503636 +0200
***************
*** 3803,3845 ****
                break;
  
            case VAR_LIST:
!               len = list_len(rettv->vval.v_list);
!               if (n1 < 0)
!                   n1 = len + n1;
!               if (!empty1 && (n1 < 0 || n1 >= len))
!               {
!                   // For a range we allow invalid values and return an empty
!                   // list.  A list index out of range is an error.
!                   if (!range)
!                   {
!                       if (verbose)
!                           semsg(_(e_listidx), n1);
!                       return FAIL;
!                   }
!                   n1 = len;
!               }
!               if (range)
!               {
!                   list_T      *l;
! 
!                   if (n2 < 0)
!                       n2 = len + n2;
!                   else if (n2 >= len)
!                       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);
!               }
!               else
!               {
!                   copy_tv(&list_find(rettv->vval.v_list, n1)->li_tv, &var1);
!                   clear_tv(rettv);
!                   *rettv = var1;
!               }
                break;
  
            case VAR_DICT:
--- 3803,3815 ----
                break;
  
            case VAR_LIST:
!               if (empty1)
!                   n1 = 0;
!               if (empty2)
!                   n2 = -1;
!               if (list_slice_or_index(rettv->vval.v_list,
!                                       range, n1, n2, rettv, verbose) == FAIL)
!                   return FAIL;
                break;
  
            case VAR_DICT:
*** ../vim-8.2.1462/src/list.c  2020-08-13 22:47:20.373992741 +0200
--- src/list.c  2020-08-15 22:03:57.304283278 +0200
***************
*** 888,893 ****
--- 888,948 ----
      return l;
  }
  
+     int
+ list_slice_or_index(
+           list_T      *list,
+           int         range,
+           long        n1_arg,
+           long        n2_arg,
+           typval_T    *rettv,
+           int         verbose)
+ {
+     long      len = list_len(list);
+     long      n1 = n1_arg;
+     long      n2 = n2_arg;
+     typval_T  var1;
+ 
+     if (n1 < 0)
+       n1 = len + n1;
+     if (n1 < 0 || n1 >= len)
+     {
+       // For a range we allow invalid values and return an empty
+       // list.  A list index out of range is an error.
+       if (!range)
+       {
+           if (verbose)
+               semsg(_(e_listidx), n1);
+           return FAIL;
+       }
+       n1 = len;
+     }
+     if (range)
+     {
+       list_T  *l;
+ 
+       if (n2 < 0)
+           n2 = len + n2;
+       else if (n2 >= len)
+           n2 = len - 1;
+       if (n2 < 0 || n2 + 1 < n1)
+           n2 = -1;
+       l = list_slice(list, n1, n2);
+       if (l == NULL)
+           return FAIL;
+       clear_tv(rettv);
+       rettv_list_set(rettv, l);
+     }
+     else
+     {
+       // copy the item to "var1" to avoid that freeing the list makes it
+       // invalid.
+       copy_tv(&list_find(list, n1)->li_tv, &var1);
+       clear_tv(rettv);
+       *rettv = var1;
+     }
+     return OK;
+ }
+ 
  /*
   * Make a copy of list "orig".  Shallow if "deep" is FALSE.
   * The refcount of the new list is set to 1.
*** ../vim-8.2.1462/src/proto/list.pro  2020-07-01 18:29:23.681143435 +0200
--- src/proto/list.pro  2020-08-15 22:01:50.973132279 +0200
***************
*** 34,39 ****
--- 34,40 ----
  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);
+ int list_slice_or_index(list_T *list, int range, long n1_arg, long n2_arg, 
typval_T *rettv, int verbose);
  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.1462/src/testdir/test_vim9_expr.vim      2020-08-15 
21:09:03.281675788 +0200
--- src/testdir/test_vim9_expr.vim      2020-08-15 22:07:14.246957600 +0200
***************
*** 2121,2126 ****
--- 2121,2154 ----
    CheckScriptSuccess(['vim9script'] + lines)
  enddef
  
+ def Test_expr7_list_subscript()
+   let lines =<< trim END
+     let list = [0, 1, 2, 3, 4]
+     assert_equal(0, list[0])
+     assert_equal(4, list[4])
+     assert_equal(4, list[-1])
+     assert_equal(0, list[-5])
+ 
+     assert_equal([0, 1, 2, 3, 4], list[0:4])
+     assert_equal([0, 1, 2, 3, 4], list[:])
+     assert_equal([1, 2, 3, 4], list[1:])
+     assert_equal([2, 3, 4], list[2:-1])
+     assert_equal([4], list[4:-1])
+     assert_equal([], list[5:-1])
+     assert_equal([], list[999:-1])
+ 
+     assert_equal([0, 1, 2, 3], list[0:3])
+     assert_equal([0], list[0:0])
+     assert_equal([0, 1, 2, 3, 4], list[0:-1])
+     assert_equal([0, 1, 2], list[0:-3])
+     assert_equal([0], list[0:-5])
+     assert_equal([], list[0:-6])
+     assert_equal([], list[0:-99])
+   END
+   CheckDefSuccess(lines)
+   CheckScriptSuccess(['vim9script'] + lines)
+ enddef
+ 
  def Test_expr7_subscript_linebreak()
    let range = range(
                3)
*** ../vim-8.2.1462/src/testdir/test_vim9_disassemble.vim       2020-08-15 
21:09:03.281675788 +0200
--- src/testdir/test_vim9_disassemble.vim       2020-08-15 22:11:37.917180026 
+0200
***************
*** 992,997 ****
--- 992,1019 ----
    assert_equal('b', StringIndex())
  enddef
  
+ def StringSlice(): string
+   let s = "abcd"
+   let res = s[1:8]
+   return res
+ enddef
+ 
+ def Test_disassemble_string_slice()
+   let instr = execute('disassemble StringSlice')
+   assert_match('StringSlice\_s*' ..
+         'let s = "abcd"\_s*' ..
+         '\d PUSHS "abcd"\_s*' ..
+         '\d STORE $0\_s*' ..
+         'let res = s\[1:8]\_s*' ..
+         '\d LOAD $0\_s*' ..
+         '\d PUSHNR 1\_s*' ..
+         '\d PUSHNR 8\_s*' ..
+         '\d STRSLICE\_s*' ..
+         '\d STORE $1\_s*',
+         instr)
+   assert_equal('bcd', StringSlice())
+ enddef
+ 
  def ListIndex(): number
    let l = [1, 2, 3]
    let res = l[1]
***************
*** 1016,1021 ****
--- 1038,1068 ----
    assert_equal(2, ListIndex())
  enddef
  
+ def ListSlice(): list<number>
+   let l = [1, 2, 3]
+   let res = l[1:8]
+   return res
+ enddef
+ 
+ def Test_disassemble_list_slice()
+   let instr = execute('disassemble ListSlice')
+   assert_match('ListSlice\_s*' ..
+         'let l = \[1, 2, 3]\_s*' ..
+         '\d PUSHNR 1\_s*' ..
+         '\d PUSHNR 2\_s*' ..
+         '\d PUSHNR 3\_s*' ..
+         '\d NEWLIST size 3\_s*' ..
+         '\d STORE $0\_s*' ..
+         'let res = l\[1:8]\_s*' ..
+         '\d LOAD $0\_s*' ..
+         '\d PUSHNR 1\_s*' ..
+         '\d PUSHNR 8\_s*' ..
+         '\d LISTSLICE\_s*' ..
+         '\d STORE $1\_s*',
+         instr)
+   assert_equal([2, 3], ListSlice())
+ enddef
+ 
  def DictMember(): number
    let d = #{item: 1}
    let res = d.item
*** ../vim-8.2.1462/src/version.c       2020-08-15 21:09:03.281675788 +0200
--- src/version.c       2020-08-15 21:29:27.942029098 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     1463,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
214. Your MCI "Circle of Friends" are all Hayes-compatible.

 /// 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/202008152015.07FKFIga386991%40masaka.moolenaar.net.

Raspunde prin e-mail lui