Patch 8.2.4198
Problem:    Vim9: the switch for executing instructions is too long.
Solution:   Move some code to separate functions.
Files:      src/vim9execute.c


*** ../vim-8.2.4197/src/vim9execute.c   2022-01-18 17:43:01.061598437 +0000
--- src/vim9execute.c   2022-01-23 19:57:34.023716035 +0000
***************
*** 1694,1699 ****
--- 1694,2265 ----
  }
  
  /*
+  * Store a value in a list or dict variable.
+  * Returns OK, FAIL or NOTDONE (uncatchable error).
+  */
+     static int
+ execute_storeindex(isn_T *iptr, ectx_T *ectx)
+ {
+     vartype_T dest_type = iptr->isn_arg.vartype;
+     typval_T  *tv;
+     typval_T  *tv_idx = STACK_TV_BOT(-2);
+     typval_T  *tv_dest = STACK_TV_BOT(-1);
+     int               status = OK;
+ 
+     // Stack contains:
+     // -3 value to be stored
+     // -2 index
+     // -1 dict or list
+     tv = STACK_TV_BOT(-3);
+     SOURCING_LNUM = iptr->isn_lnum;
+     if (dest_type == VAR_ANY)
+     {
+       dest_type = tv_dest->v_type;
+       if (dest_type == VAR_DICT)
+           status = do_2string(tv_idx, TRUE, FALSE);
+       else if (dest_type == VAR_LIST && tv_idx->v_type != VAR_NUMBER)
+       {
+           emsg(_(e_number_expected));
+           status = FAIL;
+       }
+     }
+     else if (dest_type != tv_dest->v_type)
+     {
+       // just in case, should be OK
+       semsg(_(e_expected_str_but_got_str),
+                   vartype_name(dest_type),
+                   vartype_name(tv_dest->v_type));
+       status = FAIL;
+     }
+ 
+     if (status == OK && dest_type == VAR_LIST)
+     {
+       long        lidx = (long)tv_idx->vval.v_number;
+       list_T      *list = tv_dest->vval.v_list;
+ 
+       if (list == NULL)
+       {
+           emsg(_(e_list_not_set));
+           return FAIL;
+       }
+       if (lidx < 0 && list->lv_len + lidx >= 0)
+           // negative index is relative to the end
+           lidx = list->lv_len + lidx;
+       if (lidx < 0 || lidx > list->lv_len)
+       {
+           semsg(_(e_list_index_out_of_range_nr), lidx);
+           return FAIL;
+       }
+       if (lidx < list->lv_len)
+       {
+           listitem_T *li = list_find(list, lidx);
+ 
+           if (error_if_locked(li->li_tv.v_lock, e_cannot_change_list_item))
+               return FAIL;
+           // overwrite existing list item
+           clear_tv(&li->li_tv);
+           li->li_tv = *tv;
+       }
+       else
+       {
+           if (error_if_locked(list->lv_lock, e_cannot_change_list))
+               return FAIL;
+           // append to list, only fails when out of memory
+           if (list_append_tv(list, tv) == FAIL)
+               return NOTDONE;
+           clear_tv(tv);
+       }
+     }
+     else if (status == OK && dest_type == VAR_DICT)
+     {
+       char_u          *key = tv_idx->vval.v_string;
+       dict_T          *dict = tv_dest->vval.v_dict;
+       dictitem_T      *di;
+ 
+       SOURCING_LNUM = iptr->isn_lnum;
+       if (dict == NULL)
+       {
+           emsg(_(e_dictionary_not_set));
+           return FAIL;
+       }
+       if (key == NULL)
+           key = (char_u *)"";
+       di = dict_find(dict, key, -1);
+       if (di != NULL)
+       {
+           if (error_if_locked(di->di_tv.v_lock, e_cannot_change_dict_item))
+               return FAIL;
+           // overwrite existing value
+           clear_tv(&di->di_tv);
+           di->di_tv = *tv;
+       }
+       else
+       {
+           if (error_if_locked(dict->dv_lock, e_cannot_change_dict))
+               return FAIL;
+           // add to dict, only fails when out of memory
+           if (dict_add_tv(dict, (char *)key, tv) == FAIL)
+               return NOTDONE;
+           clear_tv(tv);
+       }
+     }
+     else if (status == OK && dest_type == VAR_BLOB)
+     {
+       long        lidx = (long)tv_idx->vval.v_number;
+       blob_T      *blob = tv_dest->vval.v_blob;
+       varnumber_T nr;
+       int         error = FALSE;
+       int         len;
+ 
+       if (blob == NULL)
+       {
+           emsg(_(e_blob_not_set));
+           return FAIL;
+       }
+       len = blob_len(blob);
+       if (lidx < 0 && len + lidx >= 0)
+           // negative index is relative to the end
+           lidx = len + lidx;
+ 
+       // Can add one byte at the end.
+       if (lidx < 0 || lidx > len)
+       {
+           semsg(_(e_blob_index_out_of_range_nr), lidx);
+           return FAIL;
+       }
+       if (value_check_lock(blob->bv_lock, (char_u *)"blob", FALSE))
+           return FAIL;
+       nr = tv_get_number_chk(tv, &error);
+       if (error)
+           return FAIL;
+       blob_set_append(blob, lidx, nr);
+     }
+     else
+     {
+       status = FAIL;
+       semsg(_(e_cannot_index_str), vartype_name(dest_type));
+     }
+ 
+     clear_tv(tv_idx);
+     clear_tv(tv_dest);
+     ectx->ec_stack.ga_len -= 3;
+     if (status == FAIL)
+     {
+       clear_tv(tv);
+       return FAIL;
+     }
+     return OK;
+ }
+ 
+ /*
+  * Store a value in a blob range.
+  */
+     static int
+ execute_storerange(isn_T *iptr, ectx_T *ectx)
+ {
+     typval_T  *tv;
+     typval_T  *tv_idx1 = STACK_TV_BOT(-3);
+     typval_T  *tv_idx2 = STACK_TV_BOT(-2);
+     typval_T  *tv_dest = STACK_TV_BOT(-1);
+     int               status = OK;
+ 
+     // Stack contains:
+     // -4 value to be stored
+     // -3 first index or "none"
+     // -2 second index or "none"
+     // -1 destination list or blob
+     tv = STACK_TV_BOT(-4);
+     if (tv_dest->v_type == VAR_LIST)
+     {
+       long    n1;
+       long    n2;
+       int     error = FALSE;
+ 
+       SOURCING_LNUM = iptr->isn_lnum;
+       n1 = (long)tv_get_number_chk(tv_idx1, &error);
+       if (error)
+           status = FAIL;
+       else
+       {
+           if (tv_idx2->v_type == VAR_SPECIAL
+                       && tv_idx2->vval.v_number == VVAL_NONE)
+               n2 = list_len(tv_dest->vval.v_list) - 1;
+           else
+               n2 = (long)tv_get_number_chk(tv_idx2, &error);
+           if (error)
+               status = FAIL;
+           else
+           {
+               listitem_T *li1 = check_range_index_one(
+                       tv_dest->vval.v_list, &n1, FALSE);
+ 
+               if (li1 == NULL)
+                   status = FAIL;
+               else
+               {
+                   status = check_range_index_two(
+                           tv_dest->vval.v_list,
+                           &n1, li1, &n2, FALSE);
+                   if (status != FAIL)
+                       status = list_assign_range(
+                               tv_dest->vval.v_list,
+                               tv->vval.v_list,
+                               n1,
+                               n2,
+                               tv_idx2->v_type == VAR_SPECIAL,
+                               (char_u *)"=",
+                               (char_u *)"[unknown]");
+               }
+           }
+       }
+     }
+     else if (tv_dest->v_type == VAR_BLOB)
+     {
+       varnumber_T n1;
+       varnumber_T n2;
+       int         error = FALSE;
+ 
+       n1 = tv_get_number_chk(tv_idx1, &error);
+       if (error)
+           status = FAIL;
+       else
+       {
+           if (tv_idx2->v_type == VAR_SPECIAL
+                       && tv_idx2->vval.v_number == VVAL_NONE)
+               n2 = blob_len(tv_dest->vval.v_blob) - 1;
+           else
+               n2 = tv_get_number_chk(tv_idx2, &error);
+           if (error)
+               status = FAIL;
+           else
+           {
+               long  bloblen = blob_len(tv_dest->vval.v_blob);
+ 
+               if (check_blob_index(bloblen,
+                                            n1, FALSE) == FAIL
+                       || check_blob_range(bloblen,
+                                       n1, n2, FALSE) == FAIL)
+                   status = FAIL;
+               else
+                   status = blob_set_range(
+                            tv_dest->vval.v_blob, n1, n2, tv);
+           }
+       }
+     }
+     else
+     {
+       status = FAIL;
+       emsg(_(e_blob_required));
+     }
+ 
+     clear_tv(tv_idx1);
+     clear_tv(tv_idx2);
+     clear_tv(tv_dest);
+     ectx->ec_stack.ga_len -= 4;
+     clear_tv(tv);
+ 
+     return status;
+ }
+ 
+ /*
+  * Unlet item in list or dict variable.
+  */
+     static int
+ execute_unletindex(isn_T *iptr, ectx_T *ectx)
+ {
+     typval_T  *tv_idx = STACK_TV_BOT(-2);
+     typval_T  *tv_dest = STACK_TV_BOT(-1);
+     int               status = OK;
+ 
+     // Stack contains:
+     // -2 index
+     // -1 dict or list
+     if (tv_dest->v_type == VAR_DICT)
+     {
+       // unlet a dict item, index must be a string
+       if (tv_idx->v_type != VAR_STRING)
+       {
+           SOURCING_LNUM = iptr->isn_lnum;
+           semsg(_(e_expected_str_but_got_str),
+                       vartype_name(VAR_STRING),
+                       vartype_name(tv_idx->v_type));
+           status = FAIL;
+       }
+       else
+       {
+           dict_T      *d = tv_dest->vval.v_dict;
+           char_u      *key = tv_idx->vval.v_string;
+           dictitem_T  *di = NULL;
+ 
+           if (d != NULL && value_check_lock(
+                                     d->dv_lock, NULL, FALSE))
+               status = FAIL;
+           else
+           {
+               SOURCING_LNUM = iptr->isn_lnum;
+               if (key == NULL)
+                   key = (char_u *)"";
+               if (d != NULL)
+                   di = dict_find(d, key, (int)STRLEN(key));
+               if (di == NULL)
+               {
+                   // NULL dict is equivalent to empty dict
+                   semsg(_(e_key_not_present_in_dictionary),
+                                                         key);
+                   status = FAIL;
+               }
+               else if (var_check_fixed(di->di_flags,
+                                                  NULL, FALSE)
+                       || var_check_ro(di->di_flags,
+                                                 NULL, FALSE))
+                   status = FAIL;
+               else
+                   dictitem_remove(d, di);
+           }
+       }
+     }
+     else if (tv_dest->v_type == VAR_LIST)
+     {
+       // unlet a List item, index must be a number
+       SOURCING_LNUM = iptr->isn_lnum;
+       if (check_for_number(tv_idx) == FAIL)
+       {
+           status = FAIL;
+       }
+       else
+       {
+           list_T      *l = tv_dest->vval.v_list;
+           long        n = (long)tv_idx->vval.v_number;
+ 
+           if (l != NULL && value_check_lock(
+                                     l->lv_lock, NULL, FALSE))
+               status = FAIL;
+           else
+           {
+               listitem_T      *li = list_find(l, n);
+ 
+               if (li == NULL)
+               {
+                   SOURCING_LNUM = iptr->isn_lnum;
+                   semsg(_(e_list_index_out_of_range_nr), n);
+                   status = FAIL;
+               }
+               else if (value_check_lock(li->li_tv.v_lock,
+                                                 NULL, FALSE))
+                   status = FAIL;
+               else
+                   listitem_remove(l, li);
+           }
+       }
+     }
+     else
+     {
+       status = FAIL;
+       semsg(_(e_cannot_index_str),
+                               vartype_name(tv_dest->v_type));
+     }
+ 
+     clear_tv(tv_idx);
+     clear_tv(tv_dest);
+     ectx->ec_stack.ga_len -= 2;
+ 
+     return status;
+ }
+ 
+ /*
+  * Unlet a range of items in a list variable.
+  */
+     static int
+ execute_unletrange(isn_T *iptr, ectx_T *ectx)
+ {
+     // Stack contains:
+     // -3 index1
+     // -2 index2
+     // -1 dict or list
+     typval_T  *tv_idx1 = STACK_TV_BOT(-3);
+     typval_T  *tv_idx2 = STACK_TV_BOT(-2);
+     typval_T  *tv_dest = STACK_TV_BOT(-1);
+     int               status = OK;
+ 
+     if (tv_dest->v_type == VAR_LIST)
+     {
+       // indexes must be a number
+       SOURCING_LNUM = iptr->isn_lnum;
+       if (check_for_number(tv_idx1) == FAIL
+               || (tv_idx2->v_type != VAR_SPECIAL
+                        && check_for_number(tv_idx2) == FAIL))
+       {
+           status = FAIL;
+       }
+       else
+       {
+           list_T      *l = tv_dest->vval.v_list;
+           long        n1 = (long)tv_idx1->vval.v_number;
+           long        n2 = tv_idx2->v_type == VAR_SPECIAL
+                           ? 0 : (long)tv_idx2->vval.v_number;
+           listitem_T  *li;
+ 
+           li = list_find_index(l, &n1);
+           if (li == NULL)
+               status = FAIL;
+           else
+           {
+               if (n1 < 0)
+                   n1 = list_idx_of_item(l, li);
+               if (n2 < 0)
+               {
+                   listitem_T *li2 = list_find(l, n2);
+ 
+                   if (li2 == NULL)
+                       status = FAIL;
+                   else
+                       n2 = list_idx_of_item(l, li2);
+               }
+               if (status != FAIL
+                       && tv_idx2->v_type != VAR_SPECIAL
+                       && n2 < n1)
+               {
+                   semsg(_(e_list_index_out_of_range_nr), n2);
+                   status = FAIL;
+               }
+               if (status != FAIL
+                       && list_unlet_range(l, li, NULL, n1,
+                           tv_idx2->v_type != VAR_SPECIAL, n2)
+                                                      == FAIL)
+                   status = FAIL;
+           }
+       }
+     }
+     else
+     {
+       status = FAIL;
+       SOURCING_LNUM = iptr->isn_lnum;
+       semsg(_(e_cannot_index_str),
+                               vartype_name(tv_dest->v_type));
+     }
+ 
+     clear_tv(tv_idx1);
+     clear_tv(tv_idx2);
+     clear_tv(tv_dest);
+     ectx->ec_stack.ga_len -= 3;
+ 
+     return status;
+ }
+ 
+ /*
+  * Top of a for loop.
+  */
+     static int
+ execute_for(isn_T *iptr, ectx_T *ectx)
+ {
+     typval_T  *tv;
+     typval_T  *ltv = STACK_TV_BOT(-1);
+     typval_T  *idxtv =
+                  STACK_TV_VAR(iptr->isn_arg.forloop.for_idx);
+ 
+     if (GA_GROW_FAILS(&ectx->ec_stack, 1))
+       return FAIL;
+     if (ltv->v_type == VAR_LIST)
+     {
+       list_T *list = ltv->vval.v_list;
+ 
+       // push the next item from the list
+       ++idxtv->vval.v_number;
+       if (list == NULL
+                      || idxtv->vval.v_number >= list->lv_len)
+       {
+           // past the end of the list, jump to "endfor"
+           ectx->ec_iidx = iptr->isn_arg.forloop.for_end;
+           may_restore_cmdmod(&ectx->ec_funclocal);
+       }
+       else if (list->lv_first == &range_list_item)
+       {
+           // non-materialized range() list
+           tv = STACK_TV_BOT(0);
+           tv->v_type = VAR_NUMBER;
+           tv->v_lock = 0;
+           tv->vval.v_number = list_find_nr(
+                            list, idxtv->vval.v_number, NULL);
+           ++ectx->ec_stack.ga_len;
+       }
+       else
+       {
+           listitem_T *li = list_find(list,
+                                        idxtv->vval.v_number);
+ 
+           copy_tv(&li->li_tv, STACK_TV_BOT(0));
+           ++ectx->ec_stack.ga_len;
+       }
+     }
+     else if (ltv->v_type == VAR_STRING)
+     {
+       char_u  *str = ltv->vval.v_string;
+ 
+       // The index is for the last byte of the previous
+       // character.
+       ++idxtv->vval.v_number;
+       if (str == NULL || str[idxtv->vval.v_number] == NUL)
+       {
+           // past the end of the string, jump to "endfor"
+           ectx->ec_iidx = iptr->isn_arg.forloop.for_end;
+           may_restore_cmdmod(&ectx->ec_funclocal);
+       }
+       else
+       {
+           int clen = mb_ptr2len(str + idxtv->vval.v_number);
+ 
+           // Push the next character from the string.
+           tv = STACK_TV_BOT(0);
+           tv->v_type = VAR_STRING;
+           tv->vval.v_string = vim_strnsave(
+                            str + idxtv->vval.v_number, clen);
+           ++ectx->ec_stack.ga_len;
+           idxtv->vval.v_number += clen - 1;
+       }
+     }
+     else if (ltv->v_type == VAR_BLOB)
+     {
+       blob_T  *blob = ltv->vval.v_blob;
+ 
+       // When we get here the first time make a copy of the
+       // blob, so that the iteration still works when it is
+       // changed.
+       if (idxtv->vval.v_number == -1 && blob != NULL)
+       {
+           blob_copy(blob, ltv);
+           blob_unref(blob);
+           blob = ltv->vval.v_blob;
+       }
+ 
+       // The index is for the previous byte.
+       ++idxtv->vval.v_number;
+       if (blob == NULL
+                    || idxtv->vval.v_number >= blob_len(blob))
+       {
+           // past the end of the blob, jump to "endfor"
+           ectx->ec_iidx = iptr->isn_arg.forloop.for_end;
+           may_restore_cmdmod(&ectx->ec_funclocal);
+       }
+       else
+       {
+           // Push the next byte from the blob.
+           tv = STACK_TV_BOT(0);
+           tv->v_type = VAR_NUMBER;
+           tv->vval.v_number = blob_get(blob,
+                                        idxtv->vval.v_number);
+           ++ectx->ec_stack.ga_len;
+       }
+     }
+     else
+     {
+       semsg(_(e_for_loop_on_str_not_supported),
+                                   vartype_name(ltv->v_type));
+       return FAIL;
+     }
+     return OK;
+ }
+ 
+ /*
   * Execute instructions in execution context "ectx".
   * Return OK or FAIL;
   */
***************
*** 1798,1803 ****
--- 2364,2375 ----
            continue;
        }
  
+       /*
+        * Big switch on the instruction.  Most compilers will be turning this
+        * into an efficient lookup table, since the "case" values are an enum
+        * with sequential numbers.  It may look ugly, but it should be the
+        * most efficient way.
+        */
        iptr = &ectx->ec_instr[ectx->ec_iidx++];
        switch (iptr->isn_type)
        {
***************
*** 2551,2818 ****
            // store value in list or dict variable
            case ISN_STOREINDEX:
                {
!                   vartype_T   dest_type = iptr->isn_arg.vartype;
!                   typval_T    *tv_idx = STACK_TV_BOT(-2);
!                   typval_T    *tv_dest = STACK_TV_BOT(-1);
!                   int         status = OK;
! 
!                   // Stack contains:
!                   // -3 value to be stored
!                   // -2 index
!                   // -1 dict or list
!                   tv = STACK_TV_BOT(-3);
!                   SOURCING_LNUM = iptr->isn_lnum;
!                   if (dest_type == VAR_ANY)
!                   {
!                       dest_type = tv_dest->v_type;
!                       if (dest_type == VAR_DICT)
!                           status = do_2string(tv_idx, TRUE, FALSE);
!                       else if (dest_type == VAR_LIST
!                                              && tv_idx->v_type != VAR_NUMBER)
!                       {
!                           emsg(_(e_number_expected));
!                           status = FAIL;
!                       }
!                   }
!                   else if (dest_type != tv_dest->v_type)
!                   {
!                       // just in case, should be OK
!                       semsg(_(e_expected_str_but_got_str),
!                                   vartype_name(dest_type),
!                                   vartype_name(tv_dest->v_type));
!                       status = FAIL;
!                   }
! 
!                   if (status == OK && dest_type == VAR_LIST)
!                   {
!                       long        lidx = (long)tv_idx->vval.v_number;
!                       list_T      *list = tv_dest->vval.v_list;
! 
!                       if (list == NULL)
!                       {
!                           emsg(_(e_list_not_set));
!                           goto on_error;
!                       }
!                       if (lidx < 0 && list->lv_len + lidx >= 0)
!                           // negative index is relative to the end
!                           lidx = list->lv_len + lidx;
!                       if (lidx < 0 || lidx > list->lv_len)
!                       {
!                           semsg(_(e_list_index_out_of_range_nr), lidx);
!                           goto on_error;
!                       }
!                       if (lidx < list->lv_len)
!                       {
!                           listitem_T *li = list_find(list, lidx);
! 
!                           if (error_if_locked(li->li_tv.v_lock,
!                                                   e_cannot_change_list_item))
!                               goto on_error;
!                           // overwrite existing list item
!                           clear_tv(&li->li_tv);
!                           li->li_tv = *tv;
!                       }
!                       else
!                       {
!                           if (error_if_locked(list->lv_lock,
!                                                        e_cannot_change_list))
!                               goto on_error;
!                           // append to list, only fails when out of memory
!                           if (list_append_tv(list, tv) == FAIL)
!                               goto theend;
!                           clear_tv(tv);
!                       }
!                   }
!                   else if (status == OK && dest_type == VAR_DICT)
!                   {
!                       char_u          *key = tv_idx->vval.v_string;
!                       dict_T          *dict = tv_dest->vval.v_dict;
!                       dictitem_T      *di;
! 
!                       SOURCING_LNUM = iptr->isn_lnum;
!                       if (dict == NULL)
!                       {
!                           emsg(_(e_dictionary_not_set));
!                           goto on_error;
!                       }
!                       if (key == NULL)
!                           key = (char_u *)"";
!                       di = dict_find(dict, key, -1);
!                       if (di != NULL)
!                       {
!                           if (error_if_locked(di->di_tv.v_lock,
!                                                   e_cannot_change_dict_item))
!                               goto on_error;
!                           // overwrite existing value
!                           clear_tv(&di->di_tv);
!                           di->di_tv = *tv;
!                       }
!                       else
!                       {
!                           if (error_if_locked(dict->dv_lock,
!                                                        e_cannot_change_dict))
!                               goto on_error;
!                           // add to dict, only fails when out of memory
!                           if (dict_add_tv(dict, (char *)key, tv) == FAIL)
!                               goto theend;
!                           clear_tv(tv);
!                       }
!                   }
!                   else if (status == OK && dest_type == VAR_BLOB)
!                   {
!                       long        lidx = (long)tv_idx->vval.v_number;
!                       blob_T      *blob = tv_dest->vval.v_blob;
!                       varnumber_T nr;
!                       int         error = FALSE;
!                       int         len;
! 
!                       if (blob == NULL)
!                       {
!                           emsg(_(e_blob_not_set));
!                           goto on_error;
!                       }
!                       len = blob_len(blob);
!                       if (lidx < 0 && len + lidx >= 0)
!                           // negative index is relative to the end
!                           lidx = len + lidx;
! 
!                       // Can add one byte at the end.
!                       if (lidx < 0 || lidx > len)
!                       {
!                           semsg(_(e_blob_index_out_of_range_nr), lidx);
!                           goto on_error;
!                       }
!                       if (value_check_lock(blob->bv_lock,
!                                                     (char_u *)"blob", FALSE))
!                           goto on_error;
!                       nr = tv_get_number_chk(tv, &error);
!                       if (error)
!                           goto on_error;
!                       blob_set_append(blob, lidx, nr);
!                   }
!                   else
!                   {
!                       status = FAIL;
!                       semsg(_(e_cannot_index_str), vartype_name(dest_type));
!                   }
  
!                   clear_tv(tv_idx);
!                   clear_tv(tv_dest);
!                   ectx->ec_stack.ga_len -= 3;
!                   if (status == FAIL)
!                   {
!                       clear_tv(tv);
                        goto on_error;
!                   }
                }
                break;
  
            // store value in blob range
            case ISN_STORERANGE:
!               {
!                   typval_T    *tv_idx1 = STACK_TV_BOT(-3);
!                   typval_T    *tv_idx2 = STACK_TV_BOT(-2);
!                   typval_T    *tv_dest = STACK_TV_BOT(-1);
!                   int         status = OK;
! 
!                   // Stack contains:
!                   // -4 value to be stored
!                   // -3 first index or "none"
!                   // -2 second index or "none"
!                   // -1 destination list or blob
!                   tv = STACK_TV_BOT(-4);
!                   if (tv_dest->v_type == VAR_LIST)
!                   {
!                       long    n1;
!                       long    n2;
!                       int     error = FALSE;
! 
!                       SOURCING_LNUM = iptr->isn_lnum;
!                       n1 = (long)tv_get_number_chk(tv_idx1, &error);
!                       if (error)
!                           status = FAIL;
!                       else
!                       {
!                           if (tv_idx2->v_type == VAR_SPECIAL
!                                       && tv_idx2->vval.v_number == VVAL_NONE)
!                               n2 = list_len(tv_dest->vval.v_list) - 1;
!                           else
!                               n2 = (long)tv_get_number_chk(tv_idx2, &error);
!                           if (error)
!                               status = FAIL;
!                           else
!                           {
!                               listitem_T *li1 = check_range_index_one(
!                                       tv_dest->vval.v_list, &n1, FALSE);
! 
!                               if (li1 == NULL)
!                                   status = FAIL;
!                               else
!                               {
!                                   status = check_range_index_two(
!                                           tv_dest->vval.v_list,
!                                           &n1, li1, &n2, FALSE);
!                                   if (status != FAIL)
!                                       status = list_assign_range(
!                                               tv_dest->vval.v_list,
!                                               tv->vval.v_list,
!                                               n1,
!                                               n2,
!                                               tv_idx2->v_type == VAR_SPECIAL,
!                                               (char_u *)"=",
!                                               (char_u *)"[unknown]");
!                               }
!                           }
!                       }
!                   }
!                   else if (tv_dest->v_type == VAR_BLOB)
!                   {
!                       varnumber_T n1;
!                       varnumber_T n2;
!                       int         error = FALSE;
! 
!                       n1 = tv_get_number_chk(tv_idx1, &error);
!                       if (error)
!                           status = FAIL;
!                       else
!                       {
!                           if (tv_idx2->v_type == VAR_SPECIAL
!                                       && tv_idx2->vval.v_number == VVAL_NONE)
!                               n2 = blob_len(tv_dest->vval.v_blob) - 1;
!                           else
!                               n2 = tv_get_number_chk(tv_idx2, &error);
!                           if (error)
!                               status = FAIL;
!                           else
!                           {
!                               long  bloblen = blob_len(tv_dest->vval.v_blob);
! 
!                               if (check_blob_index(bloblen,
!                                                            n1, FALSE) == FAIL
!                                       || check_blob_range(bloblen,
!                                                       n1, n2, FALSE) == FAIL)
!                                   status = FAIL;
!                               else
!                                   status = blob_set_range(
!                                            tv_dest->vval.v_blob, n1, n2, tv);
!                           }
!                       }
!                   }
!                   else
!                   {
!                       status = FAIL;
!                       emsg(_(e_blob_required));
!                   }
! 
!                   clear_tv(tv_idx1);
!                   clear_tv(tv_idx2);
!                   clear_tv(tv_dest);
!                   ectx->ec_stack.ga_len -= 4;
!                   clear_tv(tv);
! 
!                   if (status == FAIL)
!                       goto on_error;
!               }
                break;
  
            // load or store variable or argument from outer scope
--- 3123,3141 ----
            // store value in list or dict variable
            case ISN_STOREINDEX:
                {
!                   int res = execute_storeindex(iptr, ectx);
  
!                   if (res == FAIL)
                        goto on_error;
!                   if (res == NOTDONE)
!                       goto theend;
                }
                break;
  
            // store value in blob range
            case ISN_STORERANGE:
!               if (execute_storerange(iptr, ectx) == FAIL)
!                   goto on_error;
                break;
  
            // load or store variable or argument from outer scope
***************
*** 2861,3042 ****
  
            // unlet item in list or dict variable
            case ISN_UNLETINDEX:
!               {
!                   typval_T    *tv_idx = STACK_TV_BOT(-2);
!                   typval_T    *tv_dest = STACK_TV_BOT(-1);
!                   int         status = OK;
! 
!                   // Stack contains:
!                   // -2 index
!                   // -1 dict or list
!                   if (tv_dest->v_type == VAR_DICT)
!                   {
!                       // unlet a dict item, index must be a string
!                       if (tv_idx->v_type != VAR_STRING)
!                       {
!                           SOURCING_LNUM = iptr->isn_lnum;
!                           semsg(_(e_expected_str_but_got_str),
!                                       vartype_name(VAR_STRING),
!                                       vartype_name(tv_idx->v_type));
!                           status = FAIL;
!                       }
!                       else
!                       {
!                           dict_T      *d = tv_dest->vval.v_dict;
!                           char_u      *key = tv_idx->vval.v_string;
!                           dictitem_T  *di = NULL;
! 
!                           if (d != NULL && value_check_lock(
!                                                     d->dv_lock, NULL, FALSE))
!                               status = FAIL;
!                           else
!                           {
!                               SOURCING_LNUM = iptr->isn_lnum;
!                               if (key == NULL)
!                                   key = (char_u *)"";
!                               if (d != NULL)
!                                   di = dict_find(d, key, (int)STRLEN(key));
!                               if (di == NULL)
!                               {
!                                   // NULL dict is equivalent to empty dict
!                                   semsg(_(e_key_not_present_in_dictionary), 
key);
!                                   status = FAIL;
!                               }
!                               else if (var_check_fixed(di->di_flags,
!                                                                  NULL, FALSE)
!                                       || var_check_ro(di->di_flags,
!                                                                 NULL, FALSE))
!                                   status = FAIL;
!                               else
!                                   dictitem_remove(d, di);
!                           }
!                       }
!                   }
!                   else if (tv_dest->v_type == VAR_LIST)
!                   {
!                       // unlet a List item, index must be a number
!                       SOURCING_LNUM = iptr->isn_lnum;
!                       if (check_for_number(tv_idx) == FAIL)
!                       {
!                           status = FAIL;
!                       }
!                       else
!                       {
!                           list_T      *l = tv_dest->vval.v_list;
!                           long        n = (long)tv_idx->vval.v_number;
! 
!                           if (l != NULL && value_check_lock(
!                                                     l->lv_lock, NULL, FALSE))
!                               status = FAIL;
!                           else
!                           {
!                               listitem_T      *li = list_find(l, n);
! 
!                               if (li == NULL)
!                               {
!                                   SOURCING_LNUM = iptr->isn_lnum;
!                                   semsg(_(e_list_index_out_of_range_nr), n);
!                                   status = FAIL;
!                               }
!                               else if (value_check_lock(li->li_tv.v_lock,
!                                                                 NULL, FALSE))
!                                   status = FAIL;
!                               else
!                                   listitem_remove(l, li);
!                           }
!                       }
!                   }
!                   else
!                   {
!                       status = FAIL;
!                       semsg(_(e_cannot_index_str),
!                                               vartype_name(tv_dest->v_type));
!                   }
! 
!                   clear_tv(tv_idx);
!                   clear_tv(tv_dest);
!                   ectx->ec_stack.ga_len -= 2;
!                   if (status == FAIL)
!                       goto on_error;
!               }
                break;
  
            // unlet range of items in list variable
            case ISN_UNLETRANGE:
!               {
!                   // Stack contains:
!                   // -3 index1
!                   // -2 index2
!                   // -1 dict or list
!                   typval_T    *tv_idx1 = STACK_TV_BOT(-3);
!                   typval_T    *tv_idx2 = STACK_TV_BOT(-2);
!                   typval_T    *tv_dest = STACK_TV_BOT(-1);
!                   int         status = OK;
! 
!                   if (tv_dest->v_type == VAR_LIST)
!                   {
!                       // indexes must be a number
!                       SOURCING_LNUM = iptr->isn_lnum;
!                       if (check_for_number(tv_idx1) == FAIL
!                               || (tv_idx2->v_type != VAR_SPECIAL
!                                        && check_for_number(tv_idx2) == FAIL))
!                       {
!                           status = FAIL;
!                       }
!                       else
!                       {
!                           list_T      *l = tv_dest->vval.v_list;
!                           long        n1 = (long)tv_idx1->vval.v_number;
!                           long        n2 = tv_idx2->v_type == VAR_SPECIAL
!                                           ? 0 : (long)tv_idx2->vval.v_number;
!                           listitem_T  *li;
! 
!                           li = list_find_index(l, &n1);
!                           if (li == NULL)
!                               status = FAIL;
!                           else
!                           {
!                               if (n1 < 0)
!                                   n1 = list_idx_of_item(l, li);
!                               if (n2 < 0)
!                               {
!                                   listitem_T *li2 = list_find(l, n2);
! 
!                                   if (li2 == NULL)
!                                       status = FAIL;
!                                   else
!                                       n2 = list_idx_of_item(l, li2);
!                               }
!                               if (status != FAIL
!                                       && tv_idx2->v_type != VAR_SPECIAL
!                                       && n2 < n1)
!                               {
!                                   semsg(_(e_list_index_out_of_range_nr), n2);
!                                   status = FAIL;
!                               }
!                               if (status != FAIL
!                                       && list_unlet_range(l, li, NULL, n1,
!                                           tv_idx2->v_type != VAR_SPECIAL, n2)
!                                                                      == FAIL)
!                                   status = FAIL;
!                           }
!                       }
!                   }
!                   else
!                   {
!                       status = FAIL;
!                       SOURCING_LNUM = iptr->isn_lnum;
!                       semsg(_(e_cannot_index_str),
!                                               vartype_name(tv_dest->v_type));
!                   }
! 
!                   clear_tv(tv_idx1);
!                   clear_tv(tv_idx2);
!                   clear_tv(tv_dest);
!                   ectx->ec_stack.ga_len -= 3;
!                   if (status == FAIL)
!                       goto on_error;
!               }
                break;
  
            // push constant
--- 3184,3197 ----
  
            // unlet item in list or dict variable
            case ISN_UNLETINDEX:
!               if (execute_unletindex(iptr, ectx) == FAIL)
!                   goto on_error;
                break;
  
            // unlet range of items in list variable
            case ISN_UNLETRANGE:
!               if (execute_unletrange(iptr, ectx) == FAIL)
!                   goto on_error;
                break;
  
            // push constant
***************
*** 3424,3534 ****
  
            // top of a for loop
            case ISN_FOR:
!               {
!                   typval_T    *ltv = STACK_TV_BOT(-1);
!                   typval_T    *idxtv =
!                                  STACK_TV_VAR(iptr->isn_arg.forloop.for_idx);
! 
!                   if (GA_GROW_FAILS(&ectx->ec_stack, 1))
!                       goto theend;
!                   if (ltv->v_type == VAR_LIST)
!                   {
!                       list_T *list = ltv->vval.v_list;
! 
!                       // push the next item from the list
!                       ++idxtv->vval.v_number;
!                       if (list == NULL
!                                      || idxtv->vval.v_number >= list->lv_len)
!                       {
!                           // past the end of the list, jump to "endfor"
!                           ectx->ec_iidx = iptr->isn_arg.forloop.for_end;
!                           may_restore_cmdmod(&ectx->ec_funclocal);
!                       }
!                       else if (list->lv_first == &range_list_item)
!                       {
!                           // non-materialized range() list
!                           tv = STACK_TV_BOT(0);
!                           tv->v_type = VAR_NUMBER;
!                           tv->v_lock = 0;
!                           tv->vval.v_number = list_find_nr(
!                                            list, idxtv->vval.v_number, NULL);
!                           ++ectx->ec_stack.ga_len;
!                       }
!                       else
!                       {
!                           listitem_T *li = list_find(list,
!                                                        idxtv->vval.v_number);
! 
!                           copy_tv(&li->li_tv, STACK_TV_BOT(0));
!                           ++ectx->ec_stack.ga_len;
!                       }
!                   }
!                   else if (ltv->v_type == VAR_STRING)
!                   {
!                       char_u  *str = ltv->vval.v_string;
! 
!                       // The index is for the last byte of the previous
!                       // character.
!                       ++idxtv->vval.v_number;
!                       if (str == NULL || str[idxtv->vval.v_number] == NUL)
!                       {
!                           // past the end of the string, jump to "endfor"
!                           ectx->ec_iidx = iptr->isn_arg.forloop.for_end;
!                           may_restore_cmdmod(&ectx->ec_funclocal);
!                       }
!                       else
!                       {
!                           int clen = mb_ptr2len(str + idxtv->vval.v_number);
! 
!                           // Push the next character from the string.
!                           tv = STACK_TV_BOT(0);
!                           tv->v_type = VAR_STRING;
!                           tv->vval.v_string = vim_strnsave(
!                                            str + idxtv->vval.v_number, clen);
!                           ++ectx->ec_stack.ga_len;
!                           idxtv->vval.v_number += clen - 1;
!                       }
!                   }
!                   else if (ltv->v_type == VAR_BLOB)
!                   {
!                       blob_T  *blob = ltv->vval.v_blob;
! 
!                       // When we get here the first time make a copy of the
!                       // blob, so that the iteration still works when it is
!                       // changed.
!                       if (idxtv->vval.v_number == -1 && blob != NULL)
!                       {
!                           blob_copy(blob, ltv);
!                           blob_unref(blob);
!                           blob = ltv->vval.v_blob;
!                       }
! 
!                       // The index is for the previous byte.
!                       ++idxtv->vval.v_number;
!                       if (blob == NULL
!                                    || idxtv->vval.v_number >= blob_len(blob))
!                       {
!                           // past the end of the blob, jump to "endfor"
!                           ectx->ec_iidx = iptr->isn_arg.forloop.for_end;
!                           may_restore_cmdmod(&ectx->ec_funclocal);
!                       }
!                       else
!                       {
!                           // Push the next byte from the blob.
!                           tv = STACK_TV_BOT(0);
!                           tv->v_type = VAR_NUMBER;
!                           tv->vval.v_number = blob_get(blob,
!                                                        idxtv->vval.v_number);
!                           ++ectx->ec_stack.ga_len;
!                       }
!                   }
!                   else
!                   {
!                       semsg(_(e_for_loop_on_str_not_supported),
!                                                   vartype_name(ltv->v_type));
!                       goto theend;
!                   }
!               }
                break;
  
            // start of ":try" block
--- 3579,3586 ----
  
            // top of a for loop
            case ISN_FOR:
!               if (execute_for(iptr, ectx) == FAIL)
!                   goto theend;
                break;
  
            // start of ":try" block
*** ../vim-8.2.4197/src/version.c       2022-01-23 17:59:01.226173123 +0000
--- src/version.c       2022-01-23 19:50:55.675808046 +0000
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     4198,
  /**/

-- 
Q: What kind of stuff do you do?
A: I collect hobbies.

 /// 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/20220123200116.6B6961C44F7%40moolenaar.net.

Raspunde prin e-mail lui