|
|
|
@@ -97,6 +97,7 @@ struct scope_S {
|
|
|
|
|
typedef struct {
|
|
|
|
|
char_u *lv_name;
|
|
|
|
|
type_T *lv_type;
|
|
|
|
|
int lv_idx; // index of the variable on the stack
|
|
|
|
|
int lv_const; // when TRUE cannot be assigned to
|
|
|
|
|
int lv_arg; // when TRUE this is an argument
|
|
|
|
|
} lvar_T;
|
|
|
|
@@ -112,7 +113,7 @@ struct cctx_S {
|
|
|
|
|
garray_T ctx_instr; // generated instructions
|
|
|
|
|
|
|
|
|
|
garray_T ctx_locals; // currently visible local variables
|
|
|
|
|
int ctx_max_local; // maximum number of locals at one time
|
|
|
|
|
int ctx_locals_count; // total number of local variables
|
|
|
|
|
|
|
|
|
|
garray_T ctx_imports; // imported items
|
|
|
|
|
|
|
|
|
@@ -120,6 +121,9 @@ struct cctx_S {
|
|
|
|
|
// commands after "else"
|
|
|
|
|
scope_T *ctx_scope; // current scope, NULL at toplevel
|
|
|
|
|
|
|
|
|
|
cctx_T *ctx_outer; // outer scope for lambda or nested
|
|
|
|
|
// function
|
|
|
|
|
|
|
|
|
|
garray_T ctx_type_stack; // type of each item on the stack
|
|
|
|
|
garray_T *ctx_type_list; // list of pointers to allocated types
|
|
|
|
|
};
|
|
|
|
@@ -135,24 +139,25 @@ static void arg_type_mismatch(type_T *expected, type_T *actual, int argidx);
|
|
|
|
|
static int check_type(type_T *expected, type_T *actual, int give_msg);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Lookup variable "name" in the local scope and return the index.
|
|
|
|
|
* Lookup variable "name" in the local scope and return it.
|
|
|
|
|
* Return NULL if not found.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
static lvar_T *
|
|
|
|
|
lookup_local(char_u *name, size_t len, cctx_T *cctx)
|
|
|
|
|
{
|
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
|
return -1;
|
|
|
|
|
return NULL;
|
|
|
|
|
for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx)
|
|
|
|
|
{
|
|
|
|
|
lvar_T *lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
|
|
|
|
|
|
|
|
|
|
if (STRNCMP(name, lvar->lv_name, len) == 0
|
|
|
|
|
&& STRLEN(lvar->lv_name) == len)
|
|
|
|
|
return idx;
|
|
|
|
|
return lvar;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -217,7 +222,7 @@ check_defined(char_u *p, int len, cctx_T *cctx)
|
|
|
|
|
{
|
|
|
|
|
if (lookup_script(p, len) == OK
|
|
|
|
|
|| (cctx != NULL
|
|
|
|
|
&& (lookup_local(p, len, cctx) >= 0
|
|
|
|
|
&& (lookup_local(p, len, cctx) != NULL
|
|
|
|
|
|| find_imported(p, len, cctx) != NULL)))
|
|
|
|
|
{
|
|
|
|
|
semsg("E1073: imported name already defined: %s", p);
|
|
|
|
@@ -1458,33 +1463,34 @@ generate_EXECCONCAT(cctx_T *cctx, int count)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Reserve space for a local variable.
|
|
|
|
|
* Return the index or -1 if it failed.
|
|
|
|
|
* Return the variable or NULL if it failed.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
static lvar_T *
|
|
|
|
|
reserve_local(cctx_T *cctx, char_u *name, size_t len, int isConst, type_T *type)
|
|
|
|
|
{
|
|
|
|
|
int idx;
|
|
|
|
|
lvar_T *lvar;
|
|
|
|
|
|
|
|
|
|
if (lookup_arg(name, len, cctx) >= 0 || lookup_vararg(name, len, cctx))
|
|
|
|
|
{
|
|
|
|
|
emsg_namelen(_("E1006: %s is used as an argument"), name, (int)len);
|
|
|
|
|
return -1;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ga_grow(&cctx->ctx_locals, 1) == FAIL)
|
|
|
|
|
return -1;
|
|
|
|
|
idx = cctx->ctx_locals.ga_len;
|
|
|
|
|
if (cctx->ctx_max_local < idx + 1)
|
|
|
|
|
cctx->ctx_max_local = idx + 1;
|
|
|
|
|
++cctx->ctx_locals.ga_len;
|
|
|
|
|
return NULL;
|
|
|
|
|
lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + cctx->ctx_locals.ga_len++;
|
|
|
|
|
|
|
|
|
|
// Every local variable uses the next entry on the stack. We could re-use
|
|
|
|
|
// the last ones when leaving a scope, but then variables used in a closure
|
|
|
|
|
// might get overwritten. To keep things simple do not re-use stack
|
|
|
|
|
// entries. This is less efficient, but memory is cheap these days.
|
|
|
|
|
lvar->lv_idx = cctx->ctx_locals_count++;
|
|
|
|
|
|
|
|
|
|
lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
|
|
|
|
|
lvar->lv_name = vim_strnsave(name, (int)(len == 0 ? STRLEN(name) : len));
|
|
|
|
|
lvar->lv_const = isConst;
|
|
|
|
|
lvar->lv_type = type;
|
|
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
|
return lvar;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -1511,7 +1517,7 @@ unwind_locals(cctx_T *cctx, int new_top)
|
|
|
|
|
* Free all local variables.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
free_local(cctx_T *cctx)
|
|
|
|
|
free_locals(cctx_T *cctx)
|
|
|
|
|
{
|
|
|
|
|
unwind_locals(cctx, 0);
|
|
|
|
|
ga_clear(&cctx->ctx_locals);
|
|
|
|
@@ -2331,10 +2337,12 @@ compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error)
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
idx = lookup_local(*arg, len, cctx);
|
|
|
|
|
if (idx >= 0)
|
|
|
|
|
lvar_T *lvar = lookup_local(*arg, len, cctx);
|
|
|
|
|
|
|
|
|
|
if (lvar != NULL)
|
|
|
|
|
{
|
|
|
|
|
type = (((lvar_T *)cctx->ctx_locals.ga_data) + idx)->lv_type;
|
|
|
|
|
type = lvar->lv_type;
|
|
|
|
|
idx = lvar->lv_idx;
|
|
|
|
|
gen_load = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
@@ -4040,7 +4048,6 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|
|
|
|
int semicolon = 0;
|
|
|
|
|
size_t varlen;
|
|
|
|
|
garray_T *instr = &cctx->ctx_instr;
|
|
|
|
|
int idx = -1;
|
|
|
|
|
int new_local = FALSE;
|
|
|
|
|
char_u *op;
|
|
|
|
|
int opt_type;
|
|
|
|
@@ -4050,7 +4057,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|
|
|
|
int oplen = 0;
|
|
|
|
|
int heredoc = FALSE;
|
|
|
|
|
type_T *type = &t_any;
|
|
|
|
|
lvar_T *lvar;
|
|
|
|
|
lvar_T *lvar = NULL;
|
|
|
|
|
char_u *name;
|
|
|
|
|
char_u *sp;
|
|
|
|
|
int has_type = FALSE;
|
|
|
|
@@ -4203,6 +4210,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
|
|
for (idx = 0; reserved[idx] != NULL; ++idx)
|
|
|
|
|
if (STRCMP(reserved[idx], name) == 0)
|
|
|
|
|
{
|
|
|
|
@@ -4210,8 +4219,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|
|
|
|
goto theend;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
idx = lookup_local(arg, varlen, cctx);
|
|
|
|
|
if (idx >= 0)
|
|
|
|
|
lvar = lookup_local(arg, varlen, cctx);
|
|
|
|
|
if (lvar != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (is_decl)
|
|
|
|
|
{
|
|
|
|
@@ -4220,10 +4229,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
|
|
|
|
|
if (lvar->lv_const)
|
|
|
|
|
{
|
|
|
|
|
semsg(_("E1018: Cannot assign to a constant: %s"), name);
|
|
|
|
|
semsg(_("E1018: Cannot assign to a constant: %s"),
|
|
|
|
|
name);
|
|
|
|
|
goto theend;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -4262,11 +4271,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|
|
|
|
type = parse_type(&p, cctx->ctx_type_list);
|
|
|
|
|
has_type = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else if (idx >= 0)
|
|
|
|
|
{
|
|
|
|
|
lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
|
|
|
|
|
else if (lvar != NULL)
|
|
|
|
|
type = lvar->lv_type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sp = p;
|
|
|
|
@@ -4288,7 +4294,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|
|
|
|
goto theend;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (idx < 0 && dest == dest_local && cctx->ctx_skip != TRUE)
|
|
|
|
|
if (lvar == NULL && dest == dest_local && cctx->ctx_skip != TRUE)
|
|
|
|
|
{
|
|
|
|
|
if (oplen > 1 && !heredoc)
|
|
|
|
|
{
|
|
|
|
@@ -4301,8 +4307,8 @@ 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;
|
|
|
|
|
idx = reserve_local(cctx, arg, varlen, cmdidx == CMD_const, type);
|
|
|
|
|
if (idx < 0)
|
|
|
|
|
lvar = reserve_local(cctx, arg, varlen, cmdidx == CMD_const, type);
|
|
|
|
|
if (lvar == NULL)
|
|
|
|
|
goto theend;
|
|
|
|
|
new_local = TRUE;
|
|
|
|
|
}
|
|
|
|
@@ -4370,7 +4376,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|
|
|
|
generate_LOADV(cctx, name + 2, TRUE);
|
|
|
|
|
break;
|
|
|
|
|
case dest_local:
|
|
|
|
|
generate_LOAD(cctx, ISN_LOAD, idx, NULL, type);
|
|
|
|
|
generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -4392,9 +4398,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|
|
|
|
stack = &cctx->ctx_type_stack;
|
|
|
|
|
stacktype = stack->ga_len == 0 ? &t_void
|
|
|
|
|
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
|
|
|
|
if (idx >= 0 && (is_decl || !has_type))
|
|
|
|
|
if (lvar != NULL && (is_decl || !has_type))
|
|
|
|
|
{
|
|
|
|
|
lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
|
|
|
|
|
if (new_local && !has_type)
|
|
|
|
|
{
|
|
|
|
|
if (stacktype->tt_type == VAR_VOID)
|
|
|
|
@@ -4546,6 +4551,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|
|
|
|
char_u *rawname = name + (name[1] == ':' ? 2 : 0);
|
|
|
|
|
imported_T *import = NULL;
|
|
|
|
|
int sid = current_sctx.sc_sid;
|
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
|
|
if (name[1] != ':')
|
|
|
|
|
{
|
|
|
|
@@ -4581,6 +4587,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case dest_local:
|
|
|
|
|
if (lvar != NULL)
|
|
|
|
|
{
|
|
|
|
|
isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
|
|
|
|
|
|
|
|
|
@@ -4593,13 +4600,13 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|
|
|
|
garray_T *stack = &cctx->ctx_type_stack;
|
|
|
|
|
|
|
|
|
|
isn->isn_type = ISN_STORENR;
|
|
|
|
|
isn->isn_arg.storenr.stnr_idx = idx;
|
|
|
|
|
isn->isn_arg.storenr.stnr_idx = lvar->lv_idx;
|
|
|
|
|
isn->isn_arg.storenr.stnr_val = val;
|
|
|
|
|
if (stack->ga_len > 0)
|
|
|
|
|
--stack->ga_len;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
generate_STORE(cctx, ISN_STORE, idx, NULL);
|
|
|
|
|
generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@@ -5283,8 +5290,8 @@ compile_for(char_u *arg, cctx_T *cctx)
|
|
|
|
|
garray_T *instr = &cctx->ctx_instr;
|
|
|
|
|
garray_T *stack = &cctx->ctx_type_stack;
|
|
|
|
|
scope_T *scope;
|
|
|
|
|
int loop_idx; // index of loop iteration variable
|
|
|
|
|
int var_idx; // index of "var"
|
|
|
|
|
lvar_T *loop_lvar; // loop iteration variable
|
|
|
|
|
lvar_T *var_lvar; // variable for "var"
|
|
|
|
|
type_T *vartype;
|
|
|
|
|
|
|
|
|
|
// TODO: list of variables: "for [key, value] in dict"
|
|
|
|
@@ -5292,8 +5299,8 @@ compile_for(char_u *arg, cctx_T *cctx)
|
|
|
|
|
for (p = arg; eval_isnamec1(*p); ++p)
|
|
|
|
|
;
|
|
|
|
|
varlen = p - arg;
|
|
|
|
|
var_idx = lookup_local(arg, varlen, cctx);
|
|
|
|
|
if (var_idx >= 0)
|
|
|
|
|
var_lvar = lookup_local(arg, varlen, cctx);
|
|
|
|
|
if (var_lvar != NULL)
|
|
|
|
|
{
|
|
|
|
|
semsg(_("E1023: variable already defined: %s"), arg);
|
|
|
|
|
return NULL;
|
|
|
|
@@ -5314,23 +5321,24 @@ compile_for(char_u *arg, cctx_T *cctx)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
// Reserve a variable to store the loop iteration counter.
|
|
|
|
|
loop_idx = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number);
|
|
|
|
|
if (loop_idx < 0)
|
|
|
|
|
loop_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number);
|
|
|
|
|
if (loop_lvar == NULL)
|
|
|
|
|
{
|
|
|
|
|
// only happens when out of memory
|
|
|
|
|
// out of memory
|
|
|
|
|
drop_scope(cctx);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reserve a variable to store "var"
|
|
|
|
|
var_idx = reserve_local(cctx, arg, varlen, FALSE, &t_any);
|
|
|
|
|
if (var_idx < 0)
|
|
|
|
|
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_idx, -1);
|
|
|
|
|
generate_STORENR(cctx, loop_lvar->lv_idx, -1);
|
|
|
|
|
|
|
|
|
|
// compile "expr", it remains on the stack until "endfor"
|
|
|
|
|
arg = p;
|
|
|
|
@@ -5349,17 +5357,13 @@ compile_for(char_u *arg, cctx_T *cctx)
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
if (vartype->tt_member->tt_type != VAR_ANY)
|
|
|
|
|
{
|
|
|
|
|
lvar_T *lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + var_idx;
|
|
|
|
|
|
|
|
|
|
lvar->lv_type = vartype->tt_member;
|
|
|
|
|
}
|
|
|
|
|
var_lvar->lv_type = vartype->tt_member;
|
|
|
|
|
|
|
|
|
|
// "for_end" is set when ":endfor" is found
|
|
|
|
|
scope->se_u.se_for.fs_top_label = instr->ga_len;
|
|
|
|
|
|
|
|
|
|
generate_FOR(cctx, loop_idx);
|
|
|
|
|
generate_STORE(cctx, ISN_STORE, var_idx, NULL);
|
|
|
|
|
generate_FOR(cctx, loop_lvar->lv_idx);
|
|
|
|
|
generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL);
|
|
|
|
|
|
|
|
|
|
return arg;
|
|
|
|
|
}
|
|
|
|
@@ -6158,7 +6162,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
|
|
|
|
|
|| *ea.cmd == '$'
|
|
|
|
|
|| *ea.cmd == '@'
|
|
|
|
|
|| ((p - ea.cmd) > 2 && ea.cmd[1] == ':')
|
|
|
|
|
|| lookup_local(ea.cmd, p - ea.cmd, &cctx) >= 0
|
|
|
|
|
|| lookup_local(ea.cmd, p - ea.cmd, &cctx) != NULL
|
|
|
|
|
|| lookup_script(ea.cmd, p - ea.cmd) == OK
|
|
|
|
|
|| find_imported(ea.cmd, p - ea.cmd, &cctx) != NULL)
|
|
|
|
|
{
|
|
|
|
@@ -6175,7 +6179,8 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
|
|
|
|
|
* COMMAND after range
|
|
|
|
|
*/
|
|
|
|
|
ea.cmd = skip_range(ea.cmd, NULL);
|
|
|
|
|
p = find_ex_command(&ea, NULL, is_ex_command ? NULL : lookup_local,
|
|
|
|
|
p = find_ex_command(&ea, NULL, is_ex_command ? NULL
|
|
|
|
|
: (void *(*)(char_u *, size_t, cctx_T *))lookup_local,
|
|
|
|
|
&cctx);
|
|
|
|
|
|
|
|
|
|
if (p == ea.cmd && ea.cmdidx != CMD_SIZE)
|
|
|
|
@@ -6349,7 +6354,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
|
|
|
|
|
dfunc->df_deleted = FALSE;
|
|
|
|
|
dfunc->df_instr = instr->ga_data;
|
|
|
|
|
dfunc->df_instr_count = instr->ga_len;
|
|
|
|
|
dfunc->df_varcount = cctx.ctx_max_local;
|
|
|
|
|
dfunc->df_varcount = cctx.ctx_locals_count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
@@ -6431,7 +6436,7 @@ erret:
|
|
|
|
|
|
|
|
|
|
current_sctx = save_current_sctx;
|
|
|
|
|
free_imported(&cctx);
|
|
|
|
|
free_local(&cctx);
|
|
|
|
|
free_locals(&cctx);
|
|
|
|
|
ga_clear(&cctx.ctx_type_stack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|