mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
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 #7345)
This commit is contained in:
parent
6abdcf8285
commit
792f786aad
@ -21,6 +21,10 @@ EXTERN char e_invalid_command[]
|
|||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
EXTERN char e_invalid_command_str[]
|
EXTERN char e_invalid_command_str[]
|
||||||
INIT(= N_("E476: Invalid command: %s"));
|
INIT(= N_("E476: Invalid command: %s"));
|
||||||
|
EXTERN char e_list_value_has_more_items_than_targets[]
|
||||||
|
INIT(= N_("E710: List value has more items than targets"));
|
||||||
|
EXTERN char e_list_value_does_not_have_enough_items[]
|
||||||
|
INIT(= N_("E711: List value does not have enough items"));
|
||||||
EXTERN char e_cannot_slice_dictionary[]
|
EXTERN char e_cannot_slice_dictionary[]
|
||||||
INIT(= N_("E719: Cannot slice a Dictionary"));
|
INIT(= N_("E719: Cannot slice a Dictionary"));
|
||||||
EXTERN char e_assert_fails_second_arg[]
|
EXTERN char e_assert_fails_second_arg[]
|
||||||
@ -305,3 +309,5 @@ EXTERN char e_using_bool_as_number[]
|
|||||||
INIT(= N_("E1138: Using a Bool as a Number"));
|
INIT(= N_("E1138: Using a Bool as a Number"));
|
||||||
EXTERN char e_missing_matching_bracket_after_dict_key[]
|
EXTERN char e_missing_matching_bracket_after_dict_key[]
|
||||||
INIT(= N_("E1139: Missing matching bracket after dict key"));
|
INIT(= N_("E1139: Missing matching bracket after dict key"));
|
||||||
|
EXTERN char e_for_argument_must_be_sequence_of_lists[]
|
||||||
|
INIT(= N_("E1140: For argument must be a sequence of lists"));
|
||||||
|
@ -1397,11 +1397,11 @@ set_var_lval(
|
|||||||
++lp->ll_n1;
|
++lp->ll_n1;
|
||||||
}
|
}
|
||||||
if (ri != NULL)
|
if (ri != NULL)
|
||||||
emsg(_("E710: List value has more items than target"));
|
emsg(_(e_list_value_has_more_items_than_targets));
|
||||||
else if (lp->ll_empty2
|
else if (lp->ll_empty2
|
||||||
? (lp->ll_li != NULL && lp->ll_li->li_next != NULL)
|
? (lp->ll_li != NULL && lp->ll_li->li_next != NULL)
|
||||||
: lp->ll_n1 != lp->ll_n2)
|
: lp->ll_n1 != lp->ll_n2)
|
||||||
emsg(_("E711: List value has not enough items"));
|
emsg(_(e_list_value_does_not_have_enough_items));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1026,6 +1026,40 @@ def Test_disassemble_for_loop_eval()
|
|||||||
instr)
|
instr)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def ForLoopUnpack()
|
||||||
|
for [x1, x2] in [[1, 2], [3, 4]]
|
||||||
|
echo x1 x2
|
||||||
|
endfor
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Test_disassemble_for_loop_unpack()
|
||||||
|
var instr = execute('disassemble ForLoopUnpack')
|
||||||
|
assert_match('ForLoopUnpack\_s*' ..
|
||||||
|
'for \[x1, x2\] in \[\[1, 2\], \[3, 4\]\]\_s*' ..
|
||||||
|
'\d\+ STORE -1 in $0\_s*' ..
|
||||||
|
'\d\+ PUSHNR 1\_s*' ..
|
||||||
|
'\d\+ PUSHNR 2\_s*' ..
|
||||||
|
'\d\+ NEWLIST size 2\_s*' ..
|
||||||
|
'\d\+ PUSHNR 3\_s*' ..
|
||||||
|
'\d\+ PUSHNR 4\_s*' ..
|
||||||
|
'\d\+ NEWLIST size 2\_s*' ..
|
||||||
|
'\d\+ NEWLIST size 2\_s*' ..
|
||||||
|
'\d\+ FOR $0 -> 16\_s*' ..
|
||||||
|
'\d\+ UNPACK 2\_s*' ..
|
||||||
|
'\d\+ STORE $1\_s*' ..
|
||||||
|
'\d\+ STORE $2\_s*' ..
|
||||||
|
'echo x1 x2\_s*' ..
|
||||||
|
'\d\+ LOAD $1\_s*' ..
|
||||||
|
'\d\+ LOAD $2\_s*' ..
|
||||||
|
'\d\+ ECHO 2\_s*' ..
|
||||||
|
'endfor\_s*' ..
|
||||||
|
'\d\+ JUMP -> 8\_s*' ..
|
||||||
|
'\d\+ DROP\_s*' ..
|
||||||
|
'\d\+ PUSHNR 0\_s*' ..
|
||||||
|
'\d\+ RETURN',
|
||||||
|
instr)
|
||||||
|
enddef
|
||||||
|
|
||||||
let g:number = 42
|
let g:number = 42
|
||||||
|
|
||||||
def TypeCast()
|
def TypeCast()
|
||||||
|
@ -1862,6 +1862,44 @@ def Test_for_loop_fails()
|
|||||||
CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:')
|
CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_for_loop_unpack()
|
||||||
|
var result = []
|
||||||
|
for [v1, v2] in [[1, 2], [3, 4]]
|
||||||
|
result->add(v1)
|
||||||
|
result->add(v2)
|
||||||
|
endfor
|
||||||
|
assert_equal([1, 2, 3, 4], result)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]]
|
||||||
|
result->add(v1)
|
||||||
|
result->add(v2)
|
||||||
|
result->add(v3)
|
||||||
|
endfor
|
||||||
|
assert_equal([1, 2, [], 3, 4, [5, 6]], result)
|
||||||
|
|
||||||
|
var lines =<< trim END
|
||||||
|
for [v1, v2] in [[1, 2, 3], [3, 4]]
|
||||||
|
echo v1 v2
|
||||||
|
endfor
|
||||||
|
END
|
||||||
|
CheckDefExecFailure(lines, 'E710:', 1)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
for [v1, v2] in [[1], [3, 4]]
|
||||||
|
echo v1 v2
|
||||||
|
endfor
|
||||||
|
END
|
||||||
|
CheckDefExecFailure(lines, 'E711:', 1)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
for [v1, v1] in [[1, 2], [3, 4]]
|
||||||
|
echo v1
|
||||||
|
endfor
|
||||||
|
END
|
||||||
|
CheckDefExecFailure(lines, 'E1017:', 1)
|
||||||
|
enddef
|
||||||
|
|
||||||
def Test_while_loop()
|
def Test_while_loop()
|
||||||
var result = ''
|
var result = ''
|
||||||
var cnt = 0
|
var cnt = 0
|
||||||
|
@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2034,
|
||||||
/**/
|
/**/
|
||||||
2033,
|
2033,
|
||||||
/**/
|
/**/
|
||||||
|
@ -146,6 +146,7 @@ typedef enum {
|
|||||||
ISN_CMDMOD, // set cmdmod
|
ISN_CMDMOD, // set cmdmod
|
||||||
ISN_CMDMOD_REV, // undo ISN_CMDMOD
|
ISN_CMDMOD_REV, // undo ISN_CMDMOD
|
||||||
|
|
||||||
|
ISN_UNPACK, // unpack list into items, uses isn_arg.unpack
|
||||||
ISN_SHUFFLE, // move item on stack up or down
|
ISN_SHUFFLE, // move item on stack up or down
|
||||||
ISN_DROP // pop stack and discard value
|
ISN_DROP // pop stack and discard value
|
||||||
} isntype_T;
|
} isntype_T;
|
||||||
@ -284,6 +285,12 @@ typedef struct {
|
|||||||
cmdmod_T *cf_cmdmod; // allocated
|
cmdmod_T *cf_cmdmod; // allocated
|
||||||
} cmod_T;
|
} cmod_T;
|
||||||
|
|
||||||
|
// arguments to ISN_UNPACK
|
||||||
|
typedef struct {
|
||||||
|
int unp_count; // number of items to produce
|
||||||
|
int unp_semicolon; // last item gets list of remainder
|
||||||
|
} unpack_T;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Instruction
|
* Instruction
|
||||||
*/
|
*/
|
||||||
@ -321,6 +328,7 @@ struct isn_S {
|
|||||||
shuffle_T shuffle;
|
shuffle_T shuffle;
|
||||||
put_T put;
|
put_T put;
|
||||||
cmod_T cmdmod;
|
cmod_T cmdmod;
|
||||||
|
unpack_T unpack;
|
||||||
} isn_arg;
|
} isn_arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1888,6 +1888,19 @@ generate_EXECCONCAT(cctx_T *cctx, int count)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
generate_UNPACK(cctx_T *cctx, int var_count, int semicolon)
|
||||||
|
{
|
||||||
|
isn_T *isn;
|
||||||
|
|
||||||
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
|
if ((isn = generate_instr(cctx, ISN_UNPACK)) == NULL)
|
||||||
|
return FAIL;
|
||||||
|
isn->isn_arg.unpack.unp_count = var_count;
|
||||||
|
isn->isn_arg.unpack.unp_semicolon = semicolon;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate an instruction for any command modifiers.
|
* Generate an instruction for any command modifiers.
|
||||||
*/
|
*/
|
||||||
@ -6323,12 +6336,12 @@ compile_endif(char_u *arg, cctx_T *cctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* compile "for var in expr"
|
* Compile "for var in expr":
|
||||||
*
|
*
|
||||||
* Produces instructions:
|
* Produces instructions:
|
||||||
* PUSHNR -1
|
* PUSHNR -1
|
||||||
* STORE loop-idx Set index to -1
|
* STORE loop-idx Set index to -1
|
||||||
* EVAL expr Push result of "expr"
|
* EVAL expr result of "expr" on top of stack
|
||||||
* top: FOR loop-idx, end Increment index, use list on bottom of stack
|
* top: FOR loop-idx, end Increment index, use list on bottom of stack
|
||||||
* - if beyond end, jump to "end"
|
* - if beyond end, jump to "end"
|
||||||
* - otherwise get item from list and push it
|
* - otherwise get item from list and push it
|
||||||
@ -6337,11 +6350,19 @@ compile_endif(char_u *arg, cctx_T *cctx)
|
|||||||
* JUMP top Jump back to repeat
|
* JUMP top Jump back to repeat
|
||||||
* end: DROP Drop the result of "expr"
|
* end: DROP Drop the result of "expr"
|
||||||
*
|
*
|
||||||
|
* Compile "for [var1, var2] in expr" - as above, but instead of "STORE var":
|
||||||
|
* UNPACK 2 Split item in 2
|
||||||
|
* STORE var1 Store item in "var1"
|
||||||
|
* STORE var2 Store item in "var2"
|
||||||
*/
|
*/
|
||||||
static char_u *
|
static char_u *
|
||||||
compile_for(char_u *arg, cctx_T *cctx)
|
compile_for(char_u *arg_start, cctx_T *cctx)
|
||||||
{
|
{
|
||||||
|
char_u *arg;
|
||||||
|
char_u *arg_end;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
int var_count = 0;
|
||||||
|
int semicolon = FALSE;
|
||||||
size_t varlen;
|
size_t varlen;
|
||||||
garray_T *instr = &cctx->ctx_instr;
|
garray_T *instr = &cctx->ctx_instr;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
@ -6349,18 +6370,12 @@ compile_for(char_u *arg, cctx_T *cctx)
|
|||||||
lvar_T *loop_lvar; // loop iteration variable
|
lvar_T *loop_lvar; // loop iteration variable
|
||||||
lvar_T *var_lvar; // variable for "var"
|
lvar_T *var_lvar; // variable for "var"
|
||||||
type_T *vartype;
|
type_T *vartype;
|
||||||
|
type_T *item_type = &t_any;
|
||||||
|
int idx;
|
||||||
|
|
||||||
// TODO: list of variables: "for [key, value] in dict"
|
p = skip_var_list(arg_start, TRUE, &var_count, &semicolon, FALSE);
|
||||||
// parse "var"
|
if (var_count == 0)
|
||||||
for (p = arg; eval_isnamec1(*p); ++p)
|
var_count = 1;
|
||||||
;
|
|
||||||
varlen = p - arg;
|
|
||||||
var_lvar = lookup_local(arg, varlen, cctx);
|
|
||||||
if (var_lvar != NULL)
|
|
||||||
{
|
|
||||||
semsg(_(e_variable_already_declared), arg);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// consume "in"
|
// consume "in"
|
||||||
p = skipwhite(p);
|
p = skipwhite(p);
|
||||||
@ -6371,12 +6386,12 @@ compile_for(char_u *arg, cctx_T *cctx)
|
|||||||
}
|
}
|
||||||
p = skipwhite(p + 2);
|
p = skipwhite(p + 2);
|
||||||
|
|
||||||
|
|
||||||
scope = new_scope(cctx, FOR_SCOPE);
|
scope = new_scope(cctx, FOR_SCOPE);
|
||||||
if (scope == NULL)
|
if (scope == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// Reserve a variable to store the loop iteration counter.
|
// Reserve a variable to store the loop iteration counter and initialize it
|
||||||
|
// to -1.
|
||||||
loop_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number);
|
loop_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number);
|
||||||
if (loop_lvar == NULL)
|
if (loop_lvar == NULL)
|
||||||
{
|
{
|
||||||
@ -6384,16 +6399,6 @@ compile_for(char_u *arg, cctx_T *cctx)
|
|||||||
drop_scope(cctx);
|
drop_scope(cctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reserve a variable to store "var"
|
|
||||||
var_lvar = reserve_local(cctx, arg, varlen, FALSE, &t_any);
|
|
||||||
if (var_lvar == NULL)
|
|
||||||
{
|
|
||||||
// out of memory or used as an argument
|
|
||||||
drop_scope(cctx);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
generate_STORENR(cctx, loop_lvar->lv_idx, -1);
|
generate_STORENR(cctx, loop_lvar->lv_idx, -1);
|
||||||
|
|
||||||
// compile "expr", it remains on the stack until "endfor"
|
// compile "expr", it remains on the stack until "endfor"
|
||||||
@ -6403,6 +6408,7 @@ compile_for(char_u *arg, cctx_T *cctx)
|
|||||||
drop_scope(cctx);
|
drop_scope(cctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
arg_end = arg;
|
||||||
|
|
||||||
// Now that we know the type of "var", check that it is a list, now or at
|
// Now that we know the type of "var", check that it is a list, now or at
|
||||||
// runtime.
|
// runtime.
|
||||||
@ -6412,16 +6418,78 @@ compile_for(char_u *arg, cctx_T *cctx)
|
|||||||
drop_scope(cctx);
|
drop_scope(cctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vartype->tt_type == VAR_LIST && vartype->tt_member->tt_type != VAR_ANY)
|
if (vartype->tt_type == VAR_LIST && vartype->tt_member->tt_type != VAR_ANY)
|
||||||
var_lvar->lv_type = vartype->tt_member;
|
{
|
||||||
|
if (var_count == 1)
|
||||||
|
item_type = vartype->tt_member;
|
||||||
|
else if (vartype->tt_member->tt_type == VAR_LIST
|
||||||
|
&& vartype->tt_member->tt_member->tt_type != VAR_ANY)
|
||||||
|
item_type = vartype->tt_member->tt_member;
|
||||||
|
}
|
||||||
|
|
||||||
// "for_end" is set when ":endfor" is found
|
// "for_end" is set when ":endfor" is found
|
||||||
scope->se_u.se_for.fs_top_label = instr->ga_len;
|
scope->se_u.se_for.fs_top_label = instr->ga_len;
|
||||||
|
|
||||||
generate_FOR(cctx, loop_lvar->lv_idx);
|
generate_FOR(cctx, loop_lvar->lv_idx);
|
||||||
|
|
||||||
|
arg = arg_start;
|
||||||
|
if (var_count > 1)
|
||||||
|
{
|
||||||
|
generate_UNPACK(cctx, var_count, semicolon);
|
||||||
|
arg = skipwhite(arg + 1); // skip white after '['
|
||||||
|
|
||||||
|
// the list item is replaced by a number of items
|
||||||
|
if (ga_grow(stack, var_count - 1) == FAIL)
|
||||||
|
{
|
||||||
|
drop_scope(cctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
--stack->ga_len;
|
||||||
|
for (idx = 0; idx < var_count; ++idx)
|
||||||
|
{
|
||||||
|
((type_T **)stack->ga_data)[stack->ga_len] =
|
||||||
|
(semicolon && idx == 0) ? vartype : item_type;
|
||||||
|
++stack->ga_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx = 0; idx < var_count; ++idx)
|
||||||
|
{
|
||||||
|
// TODO: use skip_var_one, also assign to @r, $VAR, etc.
|
||||||
|
p = arg;
|
||||||
|
while (eval_isnamec(*p))
|
||||||
|
++p;
|
||||||
|
varlen = p - arg;
|
||||||
|
var_lvar = lookup_local(arg, varlen, cctx);
|
||||||
|
if (var_lvar != NULL)
|
||||||
|
{
|
||||||
|
semsg(_(e_variable_already_declared), arg);
|
||||||
|
drop_scope(cctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserve a variable to store "var".
|
||||||
|
// TODO: check for type
|
||||||
|
var_lvar = reserve_local(cctx, arg, varlen, FALSE, &t_any);
|
||||||
|
if (var_lvar == NULL)
|
||||||
|
{
|
||||||
|
// out of memory or used as an argument
|
||||||
|
drop_scope(cctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (semicolon && idx == var_count - 1)
|
||||||
|
var_lvar->lv_type = vartype;
|
||||||
|
else
|
||||||
|
var_lvar->lv_type = item_type;
|
||||||
generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL);
|
generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL);
|
||||||
|
|
||||||
return arg;
|
if (*p == ',' || *p == ';')
|
||||||
|
++p;
|
||||||
|
arg = skipwhite(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return arg_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -7957,6 +8025,7 @@ delete_instr(isn_T *isn)
|
|||||||
case ISN_STRSLICE:
|
case ISN_STRSLICE:
|
||||||
case ISN_THROW:
|
case ISN_THROW:
|
||||||
case ISN_TRY:
|
case ISN_TRY:
|
||||||
|
case ISN_UNPACK:
|
||||||
// nothing allocated
|
// nothing allocated
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2877,6 +2877,79 @@ call_def_function(
|
|||||||
restore_cmdmod = FALSE;
|
restore_cmdmod = FALSE;
|
||||||
break;
|
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:
|
case ISN_SHUFFLE:
|
||||||
{
|
{
|
||||||
typval_T tmp_tv;
|
typval_T tmp_tv;
|
||||||
@ -3606,6 +3679,10 @@ ex_disassemble(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
case ISN_CMDMOD_REV: smsg("%4d CMDMOD_REV", current); break;
|
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,
|
case ISN_SHUFFLE: smsg("%4d SHUFFLE %d up %d", current,
|
||||||
iptr->isn_arg.shuffle.shfl_item,
|
iptr->isn_arg.shuffle.shfl_item,
|
||||||
iptr->isn_arg.shuffle.shfl_up);
|
iptr->isn_arg.shuffle.shfl_up);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user