|
|
|
@@ -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:
|
|
|
|
|