Mercurial > vim
diff src/vim9execute.c @ 22975:a943b175586a v8.2.2034
patch 8.2.2034: Vim9: list unpack in for statement not compiled yet
Commit: https://github.com/vim/vim/commit/792f786aad8409ca9ab895392742643a5b6aed8f
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Nov 23 08:31:18 2020 +0100
patch 8.2.2034: Vim9: list unpack in for statement not compiled yet
Problem: Vim9: list unpack in for statement not compiled yet.
Solution: Compile list unpack. (closes https://github.com/vim/vim/issues/7345)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 23 Nov 2020 08:45:04 +0100 |
parents | 4c97c0747017 |
children | 1fa84623fc68 |
line wrap: on
line diff
--- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2877,11 +2877,84 @@ call_def_function( restore_cmdmod = FALSE; break; + case ISN_UNPACK: + { + int count = iptr->isn_arg.unpack.unp_count; + int semicolon = iptr->isn_arg.unpack.unp_semicolon; + list_T *l; + listitem_T *li; + int i; + + // Check there is a valid list to unpack. + tv = STACK_TV_BOT(-1); + if (tv->v_type != VAR_LIST) + { + SOURCING_LNUM = iptr->isn_lnum; + emsg(_(e_for_argument_must_be_sequence_of_lists)); + goto on_error; + } + l = tv->vval.v_list; + if (l == NULL + || l->lv_len < (semicolon ? count - 1 : count)) + { + SOURCING_LNUM = iptr->isn_lnum; + emsg(_(e_list_value_does_not_have_enough_items)); + goto on_error; + } + else if (!semicolon && l->lv_len > count) + { + SOURCING_LNUM = iptr->isn_lnum; + emsg(_(e_list_value_has_more_items_than_targets)); + goto on_error; + } + + CHECK_LIST_MATERIALIZE(l); + if (GA_GROW(&ectx.ec_stack, count - 1) == FAIL) + goto failed; + ectx.ec_stack.ga_len += count - 1; + + // Variable after semicolon gets a list with the remaining + // items. + if (semicolon) + { + list_T *rem_list = + list_alloc_with_items(l->lv_len - count + 1); + + if (rem_list == NULL) + goto failed; + tv = STACK_TV_BOT(-count); + tv->vval.v_list = rem_list; + ++rem_list->lv_refcount; + tv->v_lock = 0; + li = l->lv_first; + for (i = 0; i < count - 1; ++i) + li = li->li_next; + for (i = 0; li != NULL; ++i) + { + list_set_item(rem_list, i, &li->li_tv); + li = li->li_next; + } + --count; + } + + // Produce the values in reverse order, first item last. + li = l->lv_first; + for (i = 0; i < count; ++i) + { + tv = STACK_TV_BOT(-i - 1); + copy_tv(&li->li_tv, tv); + li = li->li_next; + } + + list_unref(l); + } + break; + case ISN_SHUFFLE: { - typval_T tmp_tv; - int item = iptr->isn_arg.shuffle.shfl_item; - int up = iptr->isn_arg.shuffle.shfl_up; + typval_T tmp_tv; + int item = iptr->isn_arg.shuffle.shfl_item; + int up = iptr->isn_arg.shuffle.shfl_up; tmp_tv = *STACK_TV_BOT(-item); for ( ; up > 0 && item > 1; --up) @@ -3606,6 +3679,10 @@ ex_disassemble(exarg_T *eap) } case ISN_CMDMOD_REV: smsg("%4d CMDMOD_REV", current); break; + case ISN_UNPACK: smsg("%4d UNPACK %d%s", current, + iptr->isn_arg.unpack.unp_count, + iptr->isn_arg.unpack.unp_semicolon ? " semicolon" : ""); + break; case ISN_SHUFFLE: smsg("%4d SHUFFLE %d up %d", current, iptr->isn_arg.shuffle.shfl_item, iptr->isn_arg.shuffle.shfl_up);