1
0
forked from aniani/vim

patch 8.2.0981: Vim9: cannot compile "[var, var] = list"

Problem:    Vim9: cannot compile "[var, var] = list".
Solution:   Implement list assignment.
This commit is contained in:
Bram Moolenaar
2020-06-14 23:05:10 +02:00
parent a65d8b5bb9
commit 47a519a933
8 changed files with 770 additions and 587 deletions

View File

@@ -1431,7 +1431,7 @@ eval_for_line(
if (fi == NULL)
return NULL;
expr = skip_var_list(arg, TRUE, &fi->fi_varcount, &fi->fi_semicolon);
expr = skip_var_list(arg, TRUE, &fi->fi_varcount, &fi->fi_semicolon, FALSE);
if (expr == NULL)
return fi;

View File

@@ -164,7 +164,6 @@ static dict_T vimvardict; // Dictionary with v: variables
// for VIM_VERSION_ defines
#include "version.h"
static char_u *skip_var_one(char_u *arg, int include_type);
static void list_glob_vars(int *first);
static void list_buf_vars(int *first);
static void list_win_vars(int *first);
@@ -709,7 +708,7 @@ ex_let(exarg_T *eap)
if (eap->arg == eap->cmd)
flags |= LET_NO_COMMAND;
argend = skip_var_list(arg, TRUE, &var_count, &semicolon);
argend = skip_var_list(arg, TRUE, &var_count, &semicolon, FALSE);
if (argend == NULL)
return;
if (argend > arg && argend[-1] == '.') // for var.='str'
@@ -916,7 +915,8 @@ ex_let_vars(
* Skip over assignable variable "var" or list of variables "[var, var]".
* Used for ":let varvar = expr" and ":for varvar in expr".
* For "[var, var]" increment "*var_count" for each variable.
* for "[var, var; var]" set "semicolon".
* for "[var, var; var]" set "semicolon" to 1.
* If "silent" is TRUE do not give an "invalid argument" error message.
* Return NULL for an error.
*/
char_u *
@@ -924,7 +924,8 @@ skip_var_list(
char_u *arg,
int include_type,
int *var_count,
int *semicolon)
int *semicolon,
int silent)
{
char_u *p, *s;
@@ -935,9 +936,10 @@ skip_var_list(
for (;;)
{
p = skipwhite(p + 1); // skip whites after '[', ';' or ','
s = skip_var_one(p, TRUE);
s = skip_var_one(p, FALSE);
if (s == p)
{
if (!silent)
semsg(_(e_invarg2), p);
return NULL;
}
@@ -957,6 +959,7 @@ skip_var_list(
}
else if (*p != ',')
{
if (!silent)
semsg(_(e_invarg2), p);
return NULL;
}
@@ -972,7 +975,7 @@ skip_var_list(
* l[idx].
* In Vim9 script also skip over ": type" if "include_type" is TRUE.
*/
static char_u *
char_u *
skip_var_one(char_u *arg, int include_type)
{
char_u *end;
@@ -981,9 +984,12 @@ skip_var_one(char_u *arg, int include_type)
return arg + 2;
end = find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
if (include_type && current_sctx.sc_version == SCRIPT_VERSION_VIM9
&& *end == ':')
if (include_type && current_sctx.sc_version == SCRIPT_VERSION_VIM9)
{
// "a: type" is declaring variable "a" with a type, not "a:".
if (end == arg + 2 && end[-1] == ':')
--end;
if (*end == ':')
end = skip_type(skipwhite(end + 1));
}
return end;

View File

@@ -16,7 +16,8 @@ void restore_vimvar(int idx, typval_T *save_tv);
list_T *heredoc_get(exarg_T *eap, char_u *cmd, int script_get);
void ex_let(exarg_T *eap);
int ex_let_vars(char_u *arg_start, typval_T *tv, int copy, int semicolon, int var_count, int flags, char_u *op);
char_u *skip_var_list(char_u *arg, int include_type, int *var_count, int *semicolon);
char_u *skip_var_list(char_u *arg, int include_type, int *var_count, int *semicolon, int silent);
char_u *skip_var_one(char_u *arg, int include_type);
void list_hashtable_vars(hashtab_T *ht, char *prefix, int empty, int *first);
void ex_unlet(exarg_T *eap);
void ex_lockvar(exarg_T *eap);

View File

@@ -223,6 +223,14 @@ def Test_assignment_default()
assert_equal(5678, nr)
enddef
def Test_assignment_var_list()
let v1: string
let v2: string
[v1, v2] = ['one', 'two']
assert_equal('one', v1)
assert_equal('two', v2)
enddef
def Mess(): string
v:foldstart = 123
return 'xxx'

View File

@@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
981,
/**/
980,
/**/

View File

@@ -112,6 +112,7 @@ typedef enum {
// expression operations
ISN_CONCAT,
ISN_INDEX, // [expr] list index
ISN_GETITEM, // push list item, isn_arg.number is the index
ISN_MEMBER, // dict[member]
ISN_STRINGMEMBER, // dict.member using isn_arg.string
ISN_2BOOL, // convert value to bool, invert if isn_arg.number != 0

View File

@@ -136,6 +136,7 @@ struct cctx_S {
static char e_var_notfound[] = N_("E1001: variable not found: %s");
static char e_syntax_at[] = N_("E1002: Syntax error at %s");
static char e_used_as_arg[] = N_("E1006: %s is used as an argument");
static char e_cannot_use_void[] = N_("E1031: Cannot use void value");
static void delete_def_function_contents(dfunc_T *dfunc);
static void arg_type_mismatch(type_T *expected, type_T *actual, int argidx);
@@ -1052,6 +1053,38 @@ generate_PUSHFUNC(cctx_T *cctx, char_u *name, type_T *type)
return OK;
}
/*
* Generate an ISN_GETITEM instruction with "index".
*/
static int
generate_GETITEM(cctx_T *cctx, int index)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
type_T *type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
type_T *item_type = &t_any;
RETURN_OK_IF_SKIP(cctx);
if (type->tt_type == VAR_LIST)
item_type = type->tt_member;
else if (type->tt_type != VAR_ANY)
{
emsg(_(e_listreq));
return FAIL;
}
if ((isn = generate_instr(cctx, ISN_GETITEM)) == NULL)
return FAIL;
isn->isn_arg.number = index;
// add the item type to the type stack
if (ga_grow(stack, 1) == FAIL)
return FAIL;
((type_T **)stack->ga_data)[stack->ga_len] = item_type;
++stack->ga_len;
return OK;
}
/*
* Generate an ISN_STORE instruction.
*/
@@ -4573,67 +4606,157 @@ generate_loadvar(
}
/*
* compile "let var [= expr]", "const var = expr" and "var = expr"
* Compile declaration and assignment:
* "let var", "let var = expr", "const var = expr" and "var = expr"
* "arg" points to "var".
* Return NULL for an error.
* Return "arg" if it does not look like a variable list.
*/
static char_u *
compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
{
char_u *var_end;
char_u *var_start;
char_u *p;
char_u *end = arg;
char_u *ret = NULL;
int var_count = 0;
int var_idx;
int semicolon = 0;
size_t varlen;
garray_T *instr = &cctx->ctx_instr;
garray_T *stack = &cctx->ctx_type_stack;
int new_local = FALSE;
char_u *op;
int opt_type;
assign_dest_T dest = dest_local;
int opt_flags = 0;
int vimvaridx = -1;
int oplen = 0;
int heredoc = FALSE;
type_T *type = &t_any;
type_T *member_type = &t_any;
lvar_T *lvar = NULL;
lvar_T arg_lvar;
char_u *name;
char_u *name = NULL;
char_u *sp;
int has_type = FALSE;
int has_index = FALSE;
int is_decl = cmdidx == CMD_let || cmdidx == CMD_const;
int instr_count = -1;
var_end = skip_var_list(arg, FALSE, &var_count, &semicolon);
if (var_end == NULL)
return NULL;
if (var_count > 0)
// Skip over the "var" or "[var, var]" to get to any "=".
p = skip_var_list(arg, TRUE, &var_count, &semicolon, TRUE);
if (p == NULL)
return *arg == '[' ? arg : NULL;
if (var_count > 0 && is_decl)
{
// TODO: let [var, var] = list
emsg("Cannot handle a list yet");
emsg(_("E1092: Cannot use a list for a declaration"));
return NULL;
}
p = (*arg == '&' || *arg == '$' || *arg == '@') ? arg + 1 : arg;
p = to_name_end(p, TRUE);
sp = p;
p = skipwhite(p);
op = p;
oplen = assignment_len(p, &heredoc);
// "a: type" is declaring variable "a" with a type, not "a:".
if (is_decl && var_end == arg + 2 && var_end[-1] == ':')
--var_end;
if (is_decl && p == arg + 2 && p[-1] == ':')
--p;
if (var_count > 0 && oplen == 0)
// can be something like "[1, 2]->func()"
return arg;
varlen = p - arg;
name = vim_strnsave(arg, varlen);
if (name == NULL)
if (oplen > 0 && (!VIM_ISWHITE(*sp) || !VIM_ISWHITE(op[oplen])))
{
char_u buf[4];
vim_strncpy(buf, op, oplen);
semsg(_(e_white_both), buf);
return NULL;
}
if (heredoc)
{
list_T *l;
listitem_T *li;
// [let] varname =<< [trim] {end}
eap->getline = exarg_getline;
eap->cookie = cctx;
l = heredoc_get(eap, op + 3, FALSE);
// Push each line and the create the list.
FOR_ALL_LIST_ITEMS(l, li)
{
generate_PUSHS(cctx, li->li_tv.vval.v_string);
li->li_tv.vval.v_string = NULL;
}
generate_NEWLIST(cctx, l->lv_len);
type = &t_list_string;
member_type = &t_list_string;
list_free(l);
p += STRLEN(p);
end = p;
}
else if (var_count > 0)
{
// for "[var, var] = expr" evaluate the expression here, loop over the
// list of variables below.
p = skipwhite(op + oplen);
if (compile_expr0(&p, cctx) == FAIL)
return NULL;
end = p;
if (cctx->ctx_skip != TRUE)
{
if (*arg == '&')
type_T *stacktype;
stacktype = stack->ga_len == 0 ? &t_void
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
if (stacktype->tt_type == VAR_VOID)
{
emsg(_(e_cannot_use_void));
goto theend;
}
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)
}
}
/*
* Loop over variables in "[var, var] = expr".
* For "var = expr" and "let var: type" this is done only once.
*/
if (var_count > 0)
var_start = skipwhite(arg + 1); // skip over the "["
else
var_start = arg;
for (var_idx = 0; var_idx == 0 || var_idx < var_count; var_idx++)
{
char_u *var_end = skip_var_one(var_start, FALSE);
size_t varlen;
int new_local = FALSE;
int opt_type;
int opt_flags = 0;
assign_dest_T dest = dest_local;
int vimvaridx = -1;
lvar_T *lvar = NULL;
lvar_T arg_lvar;
int has_type = FALSE;
int has_index = FALSE;
int instr_count = -1;
p = (*var_start == '&' || *var_start == '$'
|| *var_start == '@') ? var_start + 1 : var_start;
p = to_name_end(p, TRUE);
// "a: type" is declaring variable "a" with a type, not "a:".
if (is_decl && var_end == var_start + 2 && var_end[-1] == ':')
--var_end;
if (is_decl && p == var_start + 2 && p[-1] == ':')
--p;
varlen = p - var_start;
vim_free(name);
name = vim_strnsave(var_start, varlen);
if (name == NULL)
return NULL;
if (!heredoc)
type = &t_any;
if (cctx->ctx_skip != TRUE)
{
if (*var_start == '&')
{
int cc;
long numval;
@@ -4646,10 +4769,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
}
if (is_decl)
{
semsg(_("E1052: Cannot declare an option: %s"), arg);
semsg(_("E1052: Cannot declare an option: %s"), var_start);
goto theend;
}
p = arg;
p = var_start;
p = find_option_end(&p, &opt_flags);
if (p == NULL)
{
@@ -4659,11 +4782,12 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
}
cc = *p;
*p = NUL;
opt_type = get_option_value(arg + 1, &numval, NULL, opt_flags);
opt_type = get_option_value(var_start + 1, &numval,
NULL, opt_flags);
*p = cc;
if (opt_type == -3)
{
semsg(_(e_unknown_option), arg);
semsg(_(e_unknown_option), var_start);
goto theend;
}
if (opt_type == -2 || opt_type == 0)
@@ -4671,7 +4795,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
else
type = &t_number; // both number and boolean option
}
else if (*arg == '$')
else if (*var_start == '$')
{
dest = dest_env;
type = &t_string;
@@ -4682,11 +4806,11 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
}
else if (*arg == '@')
else if (*var_start == '@')
{
if (!valid_yank_reg(arg[1], TRUE))
if (!valid_yank_reg(var_start[1], TRUE))
{
emsg_invreg(arg[1]);
emsg_invreg(var_start[1]);
goto theend;
}
dest = dest_reg;
@@ -4697,34 +4821,37 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
}
else if (STRNCMP(arg, "g:", 2) == 0)
else if (STRNCMP(var_start, "g:", 2) == 0)
{
dest = dest_global;
if (is_decl)
{
semsg(_("E1016: Cannot declare a global variable: %s"), name);
semsg(_("E1016: Cannot declare a global variable: %s"),
name);
goto theend;
}
}
else if (STRNCMP(arg, "b:", 2) == 0)
else if (STRNCMP(var_start, "b:", 2) == 0)
{
dest = dest_buffer;
if (is_decl)
{
semsg(_("E1078: Cannot declare a buffer variable: %s"), name);
semsg(_("E1078: Cannot declare a buffer variable: %s"),
name);
goto theend;
}
}
else if (STRNCMP(arg, "w:", 2) == 0)
else if (STRNCMP(var_start, "w:", 2) == 0)
{
dest = dest_window;
if (is_decl)
{
semsg(_("E1079: Cannot declare a window variable: %s"), name);
semsg(_("E1079: Cannot declare a window variable: %s"),
name);
goto theend;
}
}
else if (STRNCMP(arg, "t:", 2) == 0)
else if (STRNCMP(var_start, "t:", 2) == 0)
{
dest = dest_tab;
if (is_decl)
@@ -4733,7 +4860,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
}
else if (STRNCMP(arg, "v:", 2) == 0)
else if (STRNCMP(var_start, "v:", 2) == 0)
{
typval_T *vtv;
int di_flags;
@@ -4741,7 +4868,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
vimvaridx = find_vim_var(name + 2, &di_flags);
if (vimvaridx < 0)
{
semsg(_(e_var_notfound), arg);
semsg(_(e_var_notfound), var_start);
goto theend;
}
// We use the current value of "sandbox" here, is that OK?
@@ -4767,11 +4894,11 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
lvar = lookup_local(arg, varlen, cctx);
lvar = lookup_local(var_start, varlen, cctx);
if (lvar == NULL)
{
CLEAR_FIELD(arg_lvar);
if (lookup_arg(arg, varlen,
if (lookup_arg(var_start, varlen,
&arg_lvar.lv_idx, &arg_lvar.lv_type,
&arg_lvar.lv_from_outer, cctx) == OK)
{
@@ -4792,13 +4919,14 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
}
else if (lvar->lv_const)
{
semsg(_("E1018: Cannot assign to a constant: %s"), name);
semsg(_("E1018: Cannot assign to a constant: %s"),
name);
goto theend;
}
}
else if (STRNCMP(arg, "s:", 2) == 0
|| lookup_script(arg, varlen) == OK
|| find_imported(arg, varlen, cctx) != NULL)
else if (STRNCMP(var_start, "s:", 2) == 0
|| lookup_script(var_start, varlen) == OK
|| find_imported(var_start, varlen, cctx) != NULL)
{
dest = dest_script;
if (is_decl)
@@ -4810,7 +4938,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
}
else if (name[1] == ':' && name[2] != NUL)
{
semsg(_("E1082: Cannot use a namespaced variable: %s"), name);
semsg(_("E1082: Cannot use a namespaced variable: %s"),
name);
goto theend;
}
else if (!is_decl)
@@ -4822,7 +4951,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
}
// handle "a:name" as a name, not index "name" on "a"
if (varlen > 1 || arg[varlen] != ':')
if (varlen > 1 || var_start[varlen] != ':')
p = var_end;
if (dest != dest_option)
@@ -4843,20 +4972,9 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
type = lvar->lv_type;
}
sp = p;
p = skipwhite(p);
op = p;
oplen = assignment_len(p, &heredoc);
if (oplen > 0 && (!VIM_ISWHITE(*sp) || !VIM_ISWHITE(op[oplen])))
{
char_u buf[4];
vim_strncpy(buf, op, oplen);
semsg(_(e_white_both), buf);
}
if (oplen == 3 && !heredoc && dest != dest_global
&& type->tt_type != VAR_STRING && type->tt_type != VAR_ANY)
&& type->tt_type != VAR_STRING
&& type->tt_type != VAR_ANY)
{
emsg(_("E1019: Can only concatenate to string"));
goto theend;
@@ -4875,14 +4993,15 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
// new local variable
if (type->tt_type == VAR_FUNC && var_check_func_name(name, TRUE))
goto theend;
lvar = reserve_local(cctx, arg, varlen, cmdidx == CMD_const, type);
lvar = reserve_local(cctx, var_start, varlen,
cmdidx == CMD_const, type);
if (lvar == NULL)
goto theend;
new_local = TRUE;
}
member_type = type;
if (var_end > arg + varlen)
if (var_end > var_start + varlen)
{
// Something follows after the variable: "var[idx]".
if (is_decl)
@@ -4891,7 +5010,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
if (arg[varlen] == '[')
if (var_start[varlen] == '[')
{
has_index = TRUE;
if (type->tt_member == NULL)
@@ -4903,7 +5022,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
}
else
{
semsg("Not supported yet: %s", arg);
semsg("Not supported yet: %s", var_start);
goto theend;
}
}
@@ -4913,29 +5032,12 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
if (heredoc)
if (!heredoc)
{
list_T *l;
listitem_T *li;
// [let] varname =<< [trim] {end}
eap->getline = exarg_getline;
eap->cookie = cctx;
l = heredoc_get(eap, op + 3, FALSE);
// Push each line and the create the list.
FOR_ALL_LIST_ITEMS(l, li)
if (oplen > 0)
{
generate_PUSHS(cctx, li->li_tv.vval.v_string);
li->li_tv.vval.v_string = NULL;
}
generate_NEWLIST(cctx, l->lv_len);
type = &t_list_string;
member_type = &t_list_string;
list_free(l);
p += STRLEN(p);
}
else if (oplen > 0)
// For "var = expr" evaluate the expression.
if (var_count == 0)
{
int r;
@@ -4952,17 +5054,25 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
}
}
// Compile the expression. Temporarily hide the new local variable
// here, it is not available to this expression.
// Compile the expression. Temporarily hide the new local
// variable here, it is not available to this expression.
if (new_local)
--cctx->ctx_locals.ga_len;
instr_count = instr->ga_len;
p = skipwhite(p + oplen);
p = skipwhite(op + oplen);
r = compile_expr0(&p, cctx);
if (new_local)
++cctx->ctx_locals.ga_len;
if (r == FAIL)
goto theend;
}
else
{
// For "[var, var] = expr" get the "var_idx" item from the
// list.
if (generate_GETITEM(cctx, var_idx) == FAIL)
return FAIL;
}
if (cctx->ctx_skip != TRUE)
{
@@ -4976,13 +5086,13 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
{
if (stacktype->tt_type == VAR_VOID)
{
emsg(_("E1031: Cannot use void value"));
emsg(_(e_cannot_use_void));
goto theend;
}
else
{
// An empty list or dict has a &t_void member, for a
// variable that implies &t_any.
// An empty list or dict has a &t_void member,
// for a variable that implies &t_any.
if (stacktype == &t_list_empty)
lvar->lv_type = &t_list_any;
else if (stacktype == &t_dict_empty)
@@ -5001,7 +5111,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
if (use_type == NULL)
use_type = &t_void;
}
if (need_type(stacktype, use_type, -1, cctx) == FAIL)
if (need_type(stacktype, use_type, -1, cctx)
== FAIL)
goto theend;
}
}
@@ -5066,7 +5177,9 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
break;
}
}
if (var_count == 0)
end = p;
}
if (oplen > 0 && *op != '=')
{
@@ -5107,7 +5220,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
// Compile the "idx" in "var[idx]".
if (new_local)
--cctx->ctx_locals.ga_len;
p = skipwhite(arg + varlen + 1);
p = skipwhite(var_start + varlen + 1);
r = compile_expr0(&p, cctx);
if (new_local)
++cctx->ctx_locals.ga_len;
@@ -5212,7 +5325,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
if (name_s == NULL)
name_s = name;
else
vim_snprintf((char *)name_s, len, "s:%s", name);
vim_snprintf((char *)name_s, len,
"s:%s", name);
}
generate_OLDSCRIPT(cctx, ISN_STORES, name_s, sid,
&t_any);
@@ -5227,11 +5341,13 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
case dest_local:
if (lvar != NULL)
{
isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
isn_T *isn = ((isn_T *)instr->ga_data)
+ instr->ga_len - 1;
// optimization: turn "var = 123" from ISN_PUSHNR +
// ISN_STORE into ISN_STORENR
if (!lvar->lv_from_outer && instr->ga_len == instr_count + 1
if (!lvar->lv_from_outer
&& instr->ga_len == instr_count + 1
&& isn->isn_type == ISN_PUSHNR)
{
varnumber_T val = isn->isn_arg.number;
@@ -5251,6 +5367,15 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
break;
}
}
if (var_idx + 1 < var_count)
var_start = skipwhite(var_end + 1);
}
// for "[var, var] = expr" drop the "expr" value
if (var_count > 0 && generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
goto theend;
ret = end;
theend:
@@ -6575,12 +6700,22 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|| find_imported(ea.cmd, len, &cctx) != NULL)
{
line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
if (line == NULL)
if (line == NULL || line == ea.cmd)
goto erret;
continue;
}
}
}
if (*ea.cmd == '[')
{
// [var, var] = expr
line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
if (line == NULL)
goto erret;
if (line != ea.cmd)
continue;
}
}
/*
@@ -6646,6 +6781,8 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
case CMD_let:
case CMD_const:
line = compile_assignment(p, &ea, ea.cmdidx, &cctx);
if (line == p)
line = NULL;
break;
case CMD_unlet:
@@ -6957,6 +7094,7 @@ delete_instr(isn_T *isn)
case ISN_EXECUTE:
case ISN_FOR:
case ISN_INDEX:
case ISN_GETITEM:
case ISN_MEMBER:
case ISN_JUMP:
case ISN_LOAD:

View File

@@ -2114,6 +2114,31 @@ call_def_function(
}
break;
case ISN_GETITEM:
{
listitem_T *li;
int index = iptr->isn_arg.number;
// get list item: list is at stack-1, push item
tv = STACK_TV_BOT(-1);
if (tv->v_type != VAR_LIST)
{
emsg(_(e_listreq));
goto failed;
}
if ((li = list_find(tv->vval.v_list, index)) == NULL)
{
semsg(_(e_listidx), index);
goto failed;
}
if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
goto failed;
++ectx.ec_stack.ga_len;
copy_tv(&li->li_tv, STACK_TV_BOT(-1));
}
break;
case ISN_MEMBER:
{
dict_T *dict;
@@ -2789,6 +2814,8 @@ ex_disassemble(exarg_T *eap)
// expression operations
case ISN_CONCAT: smsg("%4d CONCAT", current); break;
case ISN_INDEX: smsg("%4d INDEX", current); break;
case ISN_GETITEM: smsg("%4d ITEM %lld",
current, iptr->isn_arg.number); break;
case ISN_MEMBER: smsg("%4d MEMBER", current); break;
case ISN_STRINGMEMBER: smsg("%4d MEMBER %s", current,
iptr->isn_arg.string); break;