mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.1846: Vim9: block variables are not found in compiled function
Problem: Vim9: variables declared in a local block are not found in when a function is compiled. Solution: Look for script variables in sn_all_vars.
This commit is contained in:
parent
8d739de43b
commit
fbbcd00367
@ -918,7 +918,8 @@ enter_block(cstack_T *cstack)
|
|||||||
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||||
|
|
||||||
cstack->cs_script_var_len[cstack->cs_idx] = si->sn_var_vals.ga_len;
|
cstack->cs_script_var_len[cstack->cs_idx] = si->sn_var_vals.ga_len;
|
||||||
cstack->cs_block_id[cstack->cs_idx] = ++si->sn_current_block_id;
|
cstack->cs_block_id[cstack->cs_idx] = ++si->sn_last_block_id;
|
||||||
|
si->sn_current_block_id = si->sn_last_block_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -938,11 +939,16 @@ leave_block(cstack_T *cstack)
|
|||||||
if (sv->sv_name != NULL)
|
if (sv->sv_name != NULL)
|
||||||
// Remove a variable declared inside the block, if it still
|
// Remove a variable declared inside the block, if it still
|
||||||
// exists, from sn_vars and move the value into sn_all_vars.
|
// exists, from sn_vars and move the value into sn_all_vars.
|
||||||
hide_script_var(si, sv);
|
hide_script_var(si, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: is this needed?
|
// TODO: is this needed?
|
||||||
cstack->cs_script_var_len[cstack->cs_idx] = si->sn_var_vals.ga_len;
|
cstack->cs_script_var_len[cstack->cs_idx] = si->sn_var_vals.ga_len;
|
||||||
|
|
||||||
|
if (cstack->cs_idx == 0)
|
||||||
|
si->sn_current_block_id = 0;
|
||||||
|
else
|
||||||
|
si->sn_current_block_id = cstack->cs_block_id[cstack->cs_idx - 1];
|
||||||
}
|
}
|
||||||
--cstack->cs_idx;
|
--cstack->cs_idx;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typva
|
|||||||
char_u *printable_func_name(ufunc_T *fp);
|
char_u *printable_func_name(ufunc_T *fp);
|
||||||
char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial);
|
char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial);
|
||||||
char_u *untrans_function_name(char_u *name);
|
char_u *untrans_function_name(char_u *name);
|
||||||
ufunc_T *def_function(exarg_T *eap, char_u *name_arg);
|
ufunc_T *define_function(exarg_T *eap, char_u *name_arg);
|
||||||
void ex_function(exarg_T *eap);
|
void ex_function(exarg_T *eap);
|
||||||
void ex_defcompile(exarg_T *eap);
|
void ex_defcompile(exarg_T *eap);
|
||||||
int eval_fname_script(char_u *p);
|
int eval_fname_script(char_u *p);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* vim9compile.c */
|
/* vim9compile.c */
|
||||||
int check_defined(char_u *p, size_t len, cctx_T *cctx);
|
int check_defined(char_u *p, size_t len, cctx_T *cctx);
|
||||||
int check_compare_types(exptype_T type, typval_T *tv1, typval_T *tv2);
|
int check_compare_types(exptype_T type, typval_T *tv1, typval_T *tv2);
|
||||||
int get_script_item_idx(int sid, char_u *name, int check_writable);
|
int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx);
|
||||||
imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
|
imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
|
||||||
imported_T *find_imported_in_script(char_u *name, size_t len, int sid);
|
imported_T *find_imported_in_script(char_u *name, size_t len, int sid);
|
||||||
int vim9_comment_start(char_u *p);
|
int vim9_comment_start(char_u *p);
|
||||||
|
@ -5,11 +5,11 @@ int not_in_vim9(exarg_T *eap);
|
|||||||
void ex_export(exarg_T *eap);
|
void ex_export(exarg_T *eap);
|
||||||
void free_imports_and_script_vars(int sid);
|
void free_imports_and_script_vars(int sid);
|
||||||
void ex_import(exarg_T *eap);
|
void ex_import(exarg_T *eap);
|
||||||
int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type);
|
int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx);
|
||||||
char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, evalarg_T *evalarg, void *cctx);
|
char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, evalarg_T *evalarg, void *cctx);
|
||||||
char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg);
|
char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg);
|
||||||
void add_vim9_script_var(dictitem_T *di, typval_T *tv, type_T *type);
|
void add_vim9_script_var(dictitem_T *di, typval_T *tv, type_T *type);
|
||||||
void hide_script_var(scriptitem_T *si, svar_T *sv);
|
void hide_script_var(scriptitem_T *si, int idx);
|
||||||
void free_all_script_vars(scriptitem_T *si);
|
void free_all_script_vars(scriptitem_T *si);
|
||||||
svar_T *find_typval_in_script(typval_T *dest);
|
svar_T *find_typval_in_script(typval_T *dest);
|
||||||
int check_script_var_type(typval_T *dest, typval_T *value, char_u *name);
|
int check_script_var_type(typval_T *dest, typval_T *value, char_u *name);
|
||||||
|
@ -1582,6 +1582,8 @@ typedef struct
|
|||||||
char_u *uf_va_name; // name from "...name" or NULL
|
char_u *uf_va_name; // name from "...name" or NULL
|
||||||
type_T *uf_va_type; // type from "...name: type" or NULL
|
type_T *uf_va_type; // type from "...name: type" or NULL
|
||||||
type_T *uf_func_type; // type of the function, &t_func_any if unknown
|
type_T *uf_func_type; // type of the function, &t_func_any if unknown
|
||||||
|
int uf_block_depth; // nr of entries in uf_block_ids
|
||||||
|
int *uf_block_ids; // blocks a :def function is defined inside
|
||||||
# if defined(FEAT_LUA)
|
# if defined(FEAT_LUA)
|
||||||
cfunc_T uf_cb; // callback function for cfunc
|
cfunc_T uf_cb; // callback function for cfunc
|
||||||
cfunc_free_T uf_cb_free; // callback function to free cfunc
|
cfunc_free_T uf_cb_free; // callback function to free cfunc
|
||||||
@ -1792,7 +1794,8 @@ typedef struct
|
|||||||
|
|
||||||
garray_T sn_imports; // imported items, imported_T
|
garray_T sn_imports; // imported items, imported_T
|
||||||
garray_T sn_type_list; // keeps types used by variables
|
garray_T sn_type_list; // keeps types used by variables
|
||||||
int sn_current_block_id; // Unique ID for each script block
|
int sn_current_block_id; // ID for current block, 0 for outer
|
||||||
|
int sn_last_block_id; // Unique ID for each script block
|
||||||
|
|
||||||
int sn_version; // :scriptversion
|
int sn_version; // :scriptversion
|
||||||
int sn_had_command; // TRUE if any command was executed
|
int sn_had_command; // TRUE if any command was executed
|
||||||
|
@ -250,6 +250,36 @@ def Test_block_failure()
|
|||||||
CheckDefFailure(['{', 'echo 1'], 'E1026:')
|
CheckDefFailure(['{', 'echo 1'], 'E1026:')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_block_local_vars()
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
if true
|
||||||
|
var text = 'hello'
|
||||||
|
def SayHello(): string
|
||||||
|
return text
|
||||||
|
enddef
|
||||||
|
def SetText(v: string)
|
||||||
|
text = v
|
||||||
|
enddef
|
||||||
|
endif
|
||||||
|
|
||||||
|
if true
|
||||||
|
var text = 'again'
|
||||||
|
def SayAgain(): string
|
||||||
|
return text
|
||||||
|
enddef
|
||||||
|
endif
|
||||||
|
defcompile
|
||||||
|
|
||||||
|
assert_equal('hello', SayHello())
|
||||||
|
assert_equal('again', SayAgain())
|
||||||
|
|
||||||
|
SetText('foobar')
|
||||||
|
assert_equal('foobar', SayHello())
|
||||||
|
END
|
||||||
|
CheckScriptSuccess(lines)
|
||||||
|
enddef
|
||||||
|
|
||||||
func g:NoSuchFunc()
|
func g:NoSuchFunc()
|
||||||
echo 'none'
|
echo 'none'
|
||||||
endfunc
|
endfunc
|
||||||
@ -1265,15 +1295,16 @@ def Test_import_absolute()
|
|||||||
|
|
||||||
assert_equal(9876, g:imported_abs)
|
assert_equal(9876, g:imported_abs)
|
||||||
assert_equal(8888, g:imported_after)
|
assert_equal(8888, g:imported_after)
|
||||||
assert_match('<SNR>\d\+_UseExported.*' ..
|
assert_match('<SNR>\d\+_UseExported\_s*' ..
|
||||||
'g:imported_abs = exported.*' ..
|
'g:imported_abs = exported\_s*' ..
|
||||||
'0 LOADSCRIPT exported from .*Xexport_abs.vim.*' ..
|
'0 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
|
||||||
'1 STOREG g:imported_abs.*' ..
|
'1 STOREG g:imported_abs\_s*' ..
|
||||||
'exported = 8888.*' ..
|
'exported = 8888\_s*' ..
|
||||||
'3 STORESCRIPT exported in .*Xexport_abs.vim.*' ..
|
'2 PUSHNR 8888\_s*' ..
|
||||||
'g:imported_after = exported.*' ..
|
'3 STORESCRIPT exported-2 in .*Xexport_abs.vim\_s*' ..
|
||||||
'4 LOADSCRIPT exported from .*Xexport_abs.vim.*' ..
|
'g:imported_after = exported\_s*' ..
|
||||||
'5 STOREG g:imported_after.*',
|
'4 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
|
||||||
|
'5 STOREG g:imported_after',
|
||||||
g:import_disassembled)
|
g:import_disassembled)
|
||||||
|
|
||||||
Undo_export_script_lines()
|
Undo_export_script_lines()
|
||||||
|
@ -1134,6 +1134,7 @@ func_clear_items(ufunc_T *fp)
|
|||||||
ga_clear_strings(&(fp->uf_lines));
|
ga_clear_strings(&(fp->uf_lines));
|
||||||
VIM_CLEAR(fp->uf_arg_types);
|
VIM_CLEAR(fp->uf_arg_types);
|
||||||
VIM_CLEAR(fp->uf_def_arg_idx);
|
VIM_CLEAR(fp->uf_def_arg_idx);
|
||||||
|
VIM_CLEAR(fp->uf_block_ids);
|
||||||
VIM_CLEAR(fp->uf_va_name);
|
VIM_CLEAR(fp->uf_va_name);
|
||||||
clear_type_list(&fp->uf_type_list);
|
clear_type_list(&fp->uf_type_list);
|
||||||
|
|
||||||
@ -2658,7 +2659,7 @@ list_functions(regmatch_T *regmatch)
|
|||||||
* Returns a pointer to the function or NULL if no function defined.
|
* Returns a pointer to the function or NULL if no function defined.
|
||||||
*/
|
*/
|
||||||
ufunc_T *
|
ufunc_T *
|
||||||
def_function(exarg_T *eap, char_u *name_arg)
|
define_function(exarg_T *eap, char_u *name_arg)
|
||||||
{
|
{
|
||||||
char_u *theline;
|
char_u *theline;
|
||||||
char_u *line_to_free = NULL;
|
char_u *line_to_free = NULL;
|
||||||
@ -3477,9 +3478,24 @@ def_function(exarg_T *eap, char_u *name_arg)
|
|||||||
// error messages are for the first function line
|
// error messages are for the first function line
|
||||||
SOURCING_LNUM = sourcing_lnum_top;
|
SOURCING_LNUM = sourcing_lnum_top;
|
||||||
|
|
||||||
|
if (eap->cstack != NULL && eap->cstack->cs_idx >= 0)
|
||||||
|
{
|
||||||
|
int count = eap->cstack->cs_idx + 1;
|
||||||
|
|
||||||
|
// The block context may be needed for script variables declared in
|
||||||
|
// a block visible now but not when the function is compiled.
|
||||||
|
fp->uf_block_ids = ALLOC_MULT(int, count);
|
||||||
|
if (fp->uf_block_ids != NULL)
|
||||||
|
{
|
||||||
|
mch_memmove(fp->uf_block_ids, eap->cstack->cs_block_id,
|
||||||
|
sizeof(int) * count);
|
||||||
|
fp->uf_block_depth = count;
|
||||||
|
}
|
||||||
|
// TODO: set flag in each block to indicate a function was defined
|
||||||
|
}
|
||||||
|
|
||||||
// parse the argument types
|
// parse the argument types
|
||||||
ga_init2(&fp->uf_type_list, sizeof(type_T *), 10);
|
ga_init2(&fp->uf_type_list, sizeof(type_T *), 10);
|
||||||
|
|
||||||
if (argtypes.ga_len > 0)
|
if (argtypes.ga_len > 0)
|
||||||
{
|
{
|
||||||
// When "varargs" is set the last name/type goes into uf_va_name
|
// When "varargs" is set the last name/type goes into uf_va_name
|
||||||
@ -3608,7 +3624,7 @@ ret_free:
|
|||||||
void
|
void
|
||||||
ex_function(exarg_T *eap)
|
ex_function(exarg_T *eap)
|
||||||
{
|
{
|
||||||
(void)def_function(eap, NULL);
|
(void)define_function(eap, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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 */
|
||||||
|
/**/
|
||||||
|
1846,
|
||||||
/**/
|
/**/
|
||||||
1845,
|
1845,
|
||||||
/**/
|
/**/
|
||||||
|
@ -195,7 +195,7 @@ lookup_local(char_u *name, size_t len, cctx_T *cctx)
|
|||||||
* Returns OK when found, FAIL otherwise.
|
* Returns OK when found, FAIL otherwise.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
lookup_arg(
|
arg_exists(
|
||||||
char_u *name,
|
char_u *name,
|
||||||
size_t len,
|
size_t len,
|
||||||
int *idxp,
|
int *idxp,
|
||||||
@ -247,7 +247,7 @@ lookup_arg(
|
|||||||
if (cctx->ctx_outer != NULL)
|
if (cctx->ctx_outer != NULL)
|
||||||
{
|
{
|
||||||
// Lookup the name for an argument of the outer function.
|
// Lookup the name for an argument of the outer function.
|
||||||
if (lookup_arg(name, len, idxp, type, gen_load_outer, cctx->ctx_outer)
|
if (arg_exists(name, len, idxp, type, gen_load_outer, cctx->ctx_outer)
|
||||||
== OK)
|
== OK)
|
||||||
{
|
{
|
||||||
*gen_load_outer = TRUE;
|
*gen_load_outer = TRUE;
|
||||||
@ -258,6 +258,57 @@ lookup_arg(
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup a script-local variable in the current script, possibly defined in a
|
||||||
|
* block that contains the function "cctx->ctx_ufunc".
|
||||||
|
* "cctx" is NULL at the script level.
|
||||||
|
* if "len" is <= 0 "name" must be NUL terminated.
|
||||||
|
* Return NULL when not found.
|
||||||
|
*/
|
||||||
|
static sallvar_T *
|
||||||
|
find_script_var(char_u *name, size_t len, cctx_T *cctx)
|
||||||
|
{
|
||||||
|
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||||
|
hashitem_T *hi;
|
||||||
|
int cc;
|
||||||
|
sallvar_T *sav;
|
||||||
|
ufunc_T *ufunc;
|
||||||
|
|
||||||
|
// Find the list of all script variables with the right name.
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
cc = name[len];
|
||||||
|
name[len] = NUL;
|
||||||
|
}
|
||||||
|
hi = hash_find(&si->sn_all_vars.dv_hashtab, name);
|
||||||
|
if (len > 0)
|
||||||
|
name[len] = cc;
|
||||||
|
if (HASHITEM_EMPTY(hi))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
sav = HI2SAV(hi);
|
||||||
|
if (sav->sav_block_id == 0 || cctx == NULL)
|
||||||
|
// variable defined in the script scope or not in a function.
|
||||||
|
return sav;
|
||||||
|
|
||||||
|
// Go over the variables with this name and find one that was visible
|
||||||
|
// from the function.
|
||||||
|
ufunc = cctx->ctx_ufunc;
|
||||||
|
while (sav != NULL)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
// Go over the blocks that this function was defined in. If the
|
||||||
|
// variable block ID matches it was visible to the function.
|
||||||
|
for (idx = 0; idx < ufunc->uf_block_depth; ++idx)
|
||||||
|
if (ufunc->uf_block_ids[idx] == sav->sav_block_id)
|
||||||
|
return sav;
|
||||||
|
sav = sav->sav_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returnd TRUE if the script context is Vim9 script.
|
* Returnd TRUE if the script context is Vim9 script.
|
||||||
*/
|
*/
|
||||||
@ -268,33 +319,50 @@ script_is_vim9()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lookup a variable in the current script.
|
* Lookup a variable (without s: prefix) in the current script.
|
||||||
* If "vim9script" is TRUE the script must be Vim9 script. Used for "var"
|
* If "vim9script" is TRUE the script must be Vim9 script. Used for "var"
|
||||||
* without "s:".
|
* without "s:".
|
||||||
|
* "cctx" is NULL at the script level.
|
||||||
* Returns OK or FAIL.
|
* Returns OK or FAIL.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
lookup_script(char_u *name, size_t len, int vim9script)
|
script_var_exists(char_u *name, size_t len, int vim9script, cctx_T *cctx)
|
||||||
{
|
{
|
||||||
int cc;
|
int is_vim9_script;
|
||||||
hashtab_T *ht;
|
|
||||||
dictitem_T *di;
|
|
||||||
|
|
||||||
if (current_sctx.sc_sid <= 0)
|
if (current_sctx.sc_sid <= 0)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
ht = &SCRIPT_VARS(current_sctx.sc_sid);
|
is_vim9_script = script_is_vim9();
|
||||||
if (vim9script && !script_is_vim9())
|
if (vim9script && !is_vim9_script)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
if (is_vim9_script)
|
||||||
|
{
|
||||||
|
// Check script variables that were visible where the function was
|
||||||
|
// defined.
|
||||||
|
if (find_script_var(name, len, cctx) != NULL)
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hashtab_T *ht = &SCRIPT_VARS(current_sctx.sc_sid);
|
||||||
|
dictitem_T *di;
|
||||||
|
int cc;
|
||||||
|
|
||||||
|
// Check script variables that are currently visible
|
||||||
cc = name[len];
|
cc = name[len];
|
||||||
name[len] = NUL;
|
name[len] = NUL;
|
||||||
di = find_var_in_ht(ht, 0, name, TRUE);
|
di = find_var_in_ht(ht, 0, name, TRUE);
|
||||||
name[len] = cc;
|
name[len] = cc;
|
||||||
return di == NULL ? FAIL: OK;
|
if (di != NULL)
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if "p[len]" is already defined, either in script "import_sid" or in
|
* Check if "p[len]" is already defined, either in script "import_sid" or in
|
||||||
* compilation context "cctx".
|
* compilation context "cctx". "cctx" is NULL at the script level.
|
||||||
* Does not check the global namespace.
|
* Does not check the global namespace.
|
||||||
* Return FAIL and give an error if it defined.
|
* Return FAIL and give an error if it defined.
|
||||||
*/
|
*/
|
||||||
@ -305,10 +373,10 @@ check_defined(char_u *p, size_t len, cctx_T *cctx)
|
|||||||
ufunc_T *ufunc = NULL;
|
ufunc_T *ufunc = NULL;
|
||||||
|
|
||||||
p[len] = NUL;
|
p[len] = NUL;
|
||||||
if (lookup_script(p, len, FALSE) == OK
|
if (script_var_exists(p, len, FALSE, cctx) == OK
|
||||||
|| (cctx != NULL
|
|| (cctx != NULL
|
||||||
&& (lookup_local(p, len, cctx) != NULL
|
&& (lookup_local(p, len, cctx) != NULL
|
||||||
|| lookup_arg(p, len, NULL, NULL, NULL, cctx) == OK))
|
|| arg_exists(p, len, NULL, NULL, NULL, cctx) == OK))
|
||||||
|| find_imported(p, len, cctx) != NULL
|
|| find_imported(p, len, cctx) != NULL
|
||||||
|| (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL)
|
|| (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL)
|
||||||
{
|
{
|
||||||
@ -1699,7 +1767,7 @@ reserve_local(
|
|||||||
{
|
{
|
||||||
lvar_T *lvar;
|
lvar_T *lvar;
|
||||||
|
|
||||||
if (lookup_arg(name, len, NULL, NULL, NULL, cctx) == OK)
|
if (arg_exists(name, len, NULL, NULL, NULL, cctx) == OK)
|
||||||
{
|
{
|
||||||
emsg_namelen(_(e_str_is_used_as_argument), name, (int)len);
|
emsg_namelen(_(e_str_is_used_as_argument), name, (int)len);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1760,16 +1828,30 @@ free_locals(cctx_T *cctx)
|
|||||||
* If not found returns -2.
|
* If not found returns -2.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
get_script_item_idx(int sid, char_u *name, int check_writable)
|
get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx)
|
||||||
{
|
{
|
||||||
hashtab_T *ht;
|
hashtab_T *ht;
|
||||||
dictitem_T *di;
|
dictitem_T *di;
|
||||||
scriptitem_T *si = SCRIPT_ITEM(sid);
|
scriptitem_T *si = SCRIPT_ITEM(sid);
|
||||||
|
svar_T *sv;
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
// First look the name up in the hashtable.
|
|
||||||
if (!SCRIPT_ID_VALID(sid))
|
if (!SCRIPT_ID_VALID(sid))
|
||||||
return -1;
|
return -1;
|
||||||
|
if (sid == current_sctx.sc_sid)
|
||||||
|
{
|
||||||
|
sallvar_T *sav = find_script_var(name, (size_t)-1, cctx);
|
||||||
|
|
||||||
|
if (sav == NULL)
|
||||||
|
return -2;
|
||||||
|
idx = sav->sav_var_vals_idx;
|
||||||
|
sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
|
||||||
|
if (check_writable && sv->sv_const)
|
||||||
|
semsg(_(e_readonlyvar), name);
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First look the name up in the hashtable.
|
||||||
ht = &SCRIPT_VARS(sid);
|
ht = &SCRIPT_VARS(sid);
|
||||||
di = find_var_in_ht(ht, 0, name, TRUE);
|
di = find_var_in_ht(ht, 0, name, TRUE);
|
||||||
if (di == NULL)
|
if (di == NULL)
|
||||||
@ -1778,8 +1860,7 @@ get_script_item_idx(int sid, char_u *name, int check_writable)
|
|||||||
// Now find the svar_T index in sn_var_vals.
|
// Now find the svar_T index in sn_var_vals.
|
||||||
for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
|
for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
|
||||||
{
|
{
|
||||||
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
|
sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
|
||||||
|
|
||||||
if (sv->sv_tv == &di->di_tv)
|
if (sv->sv_tv == &di->di_tv)
|
||||||
{
|
{
|
||||||
if (check_writable && sv->sv_const)
|
if (check_writable && sv->sv_const)
|
||||||
@ -2083,7 +2164,7 @@ compile_load_scriptvar(
|
|||||||
if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
|
if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
|
||||||
return FAIL;
|
return FAIL;
|
||||||
si = SCRIPT_ITEM(current_sctx.sc_sid);
|
si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||||
idx = get_script_item_idx(current_sctx.sc_sid, name, FALSE);
|
idx = get_script_item_idx(current_sctx.sc_sid, name, FALSE, cctx);
|
||||||
if (idx == -1 || si->sn_version != SCRIPT_VERSION_VIM9)
|
if (idx == -1 || si->sn_version != SCRIPT_VERSION_VIM9)
|
||||||
{
|
{
|
||||||
// variable is not in sn_var_vals: old style script.
|
// variable is not in sn_var_vals: old style script.
|
||||||
@ -2130,7 +2211,7 @@ compile_load_scriptvar(
|
|||||||
cc = *p;
|
cc = *p;
|
||||||
*p = NUL;
|
*p = NUL;
|
||||||
|
|
||||||
idx = find_exported(import->imp_sid, exp_name, &ufunc, &type);
|
idx = find_exported(import->imp_sid, exp_name, &ufunc, &type, cctx);
|
||||||
*p = cc;
|
*p = cc;
|
||||||
p = skipwhite(p);
|
p = skipwhite(p);
|
||||||
|
|
||||||
@ -2257,7 +2338,7 @@ compile_load(
|
|||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
if (lookup_arg(*arg, len, &idx, &type, &gen_load_outer, cctx) == OK)
|
if (arg_exists(*arg, len, &idx, &type, &gen_load_outer, cctx) == OK)
|
||||||
{
|
{
|
||||||
if (!gen_load_outer)
|
if (!gen_load_outer)
|
||||||
gen_load = TRUE;
|
gen_load = TRUE;
|
||||||
@ -2279,7 +2360,7 @@ compile_load(
|
|||||||
{
|
{
|
||||||
// "var" can be script-local even without using "s:" if it
|
// "var" can be script-local even without using "s:" if it
|
||||||
// already exists in a Vim9 script or when it's imported.
|
// already exists in a Vim9 script or when it's imported.
|
||||||
if (lookup_script(*arg, len, TRUE) == OK
|
if (script_var_exists(*arg, len, TRUE, cctx) == OK
|
||||||
|| find_imported(name, 0, cctx) != NULL)
|
|| find_imported(name, 0, cctx) != NULL)
|
||||||
res = compile_load_scriptvar(cctx, name, *arg, &end, FALSE);
|
res = compile_load_scriptvar(cctx, name, *arg, &end, FALSE);
|
||||||
|
|
||||||
@ -4468,7 +4549,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
|
|||||||
eap->skip = cctx->ctx_skip == SKIP_YES;
|
eap->skip = cctx->ctx_skip == SKIP_YES;
|
||||||
eap->forceit = FALSE;
|
eap->forceit = FALSE;
|
||||||
lambda_name = get_lambda_name();
|
lambda_name = get_lambda_name();
|
||||||
ufunc = def_function(eap, lambda_name);
|
ufunc = define_function(eap, lambda_name);
|
||||||
|
|
||||||
if (ufunc == NULL)
|
if (ufunc == NULL)
|
||||||
return eap->skip ? (char_u *)"" : NULL;
|
return eap->skip ? (char_u *)"" : NULL;
|
||||||
@ -4494,12 +4575,25 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
|
|||||||
// Define a local variable for the function reference.
|
// Define a local variable for the function reference.
|
||||||
lvar_T *lvar = reserve_local(cctx, name_start, name_end - name_start,
|
lvar_T *lvar = reserve_local(cctx, name_start, name_end - name_start,
|
||||||
TRUE, ufunc->uf_func_type);
|
TRUE, ufunc->uf_func_type);
|
||||||
|
int block_depth = cctx->ctx_ufunc->uf_block_depth;
|
||||||
|
|
||||||
if (lvar == NULL)
|
if (lvar == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (generate_FUNCREF(cctx, ufunc) == FAIL)
|
if (generate_FUNCREF(cctx, ufunc) == FAIL)
|
||||||
return NULL;
|
return NULL;
|
||||||
r = generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL);
|
r = generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL);
|
||||||
|
|
||||||
|
// copy over the block scope IDs
|
||||||
|
if (block_depth > 0)
|
||||||
|
{
|
||||||
|
ufunc->uf_block_ids = ALLOC_MULT(int, block_depth);
|
||||||
|
if (ufunc->uf_block_ids != NULL)
|
||||||
|
{
|
||||||
|
mch_memmove(ufunc->uf_block_ids, cctx->ctx_ufunc->uf_block_ids,
|
||||||
|
sizeof(int) * block_depth);
|
||||||
|
ufunc->uf_block_depth = block_depth;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: warning for trailing text?
|
// TODO: warning for trailing text?
|
||||||
@ -4900,7 +4994,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
if (lvar == NULL)
|
if (lvar == NULL)
|
||||||
{
|
{
|
||||||
CLEAR_FIELD(arg_lvar);
|
CLEAR_FIELD(arg_lvar);
|
||||||
if (lookup_arg(var_start, varlen,
|
if (arg_exists(var_start, varlen,
|
||||||
&arg_lvar.lv_idx, &arg_lvar.lv_type,
|
&arg_lvar.lv_idx, &arg_lvar.lv_type,
|
||||||
&arg_lvar.lv_from_outer, cctx) == OK)
|
&arg_lvar.lv_from_outer, cctx) == OK)
|
||||||
{
|
{
|
||||||
@ -4925,8 +5019,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
int script_namespace = varlen > 1
|
int script_namespace = varlen > 1
|
||||||
&& STRNCMP(var_start, "s:", 2) == 0;
|
&& STRNCMP(var_start, "s:", 2) == 0;
|
||||||
int script_var = (script_namespace
|
int script_var = (script_namespace
|
||||||
? lookup_script(var_start + 2, varlen - 2, FALSE)
|
? script_var_exists(var_start + 2, varlen - 2,
|
||||||
: lookup_script(var_start, varlen, TRUE)) == OK;
|
FALSE, cctx)
|
||||||
|
: script_var_exists(var_start, varlen,
|
||||||
|
TRUE, cctx)) == OK;
|
||||||
imported_T *import =
|
imported_T *import =
|
||||||
find_imported(var_start, varlen, cctx);
|
find_imported(var_start, varlen, cctx);
|
||||||
|
|
||||||
@ -4962,7 +5058,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
if (SCRIPT_ID_VALID(scriptvar_sid))
|
if (SCRIPT_ID_VALID(scriptvar_sid))
|
||||||
{
|
{
|
||||||
scriptvar_idx = get_script_item_idx(scriptvar_sid,
|
scriptvar_idx = get_script_item_idx(scriptvar_sid,
|
||||||
rawname, TRUE);
|
rawname, TRUE, cctx);
|
||||||
if (scriptvar_idx >= 0)
|
if (scriptvar_idx >= 0)
|
||||||
{
|
{
|
||||||
scriptitem_T *si = SCRIPT_ITEM(scriptvar_sid);
|
scriptitem_T *si = SCRIPT_ITEM(scriptvar_sid);
|
||||||
@ -6964,9 +7060,10 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
|||||||
|| *ea.cmd == '@'
|
|| *ea.cmd == '@'
|
||||||
|| ((len) > 2 && ea.cmd[1] == ':')
|
|| ((len) > 2 && ea.cmd[1] == ':')
|
||||||
|| lookup_local(ea.cmd, len, &cctx) != NULL
|
|| lookup_local(ea.cmd, len, &cctx) != NULL
|
||||||
|| lookup_arg(ea.cmd, len, NULL, NULL,
|
|| arg_exists(ea.cmd, len, NULL, NULL,
|
||||||
NULL, &cctx) == OK
|
NULL, &cctx) == OK
|
||||||
|| lookup_script(ea.cmd, len, FALSE) == OK
|
|| script_var_exists(ea.cmd, len,
|
||||||
|
FALSE, &cctx) == OK
|
||||||
|| find_imported(ea.cmd, len, &cctx) != NULL)
|
|| find_imported(ea.cmd, len, &cctx) != NULL)
|
||||||
{
|
{
|
||||||
line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
|
line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
|
||||||
|
@ -2962,8 +2962,10 @@ ex_disassemble(exarg_T *eap)
|
|||||||
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
|
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
|
||||||
+ iptr->isn_arg.script.script_idx;
|
+ iptr->isn_arg.script.script_idx;
|
||||||
|
|
||||||
smsg("%4d LOADSCRIPT %s from %s", current,
|
smsg("%4d LOADSCRIPT %s-%d from %s", current,
|
||||||
sv->sv_name, si->sn_name);
|
sv->sv_name,
|
||||||
|
iptr->isn_arg.script.script_idx,
|
||||||
|
si->sn_name);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ISN_LOADS:
|
case ISN_LOADS:
|
||||||
@ -3054,8 +3056,10 @@ ex_disassemble(exarg_T *eap)
|
|||||||
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
|
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
|
||||||
+ iptr->isn_arg.script.script_idx;
|
+ iptr->isn_arg.script.script_idx;
|
||||||
|
|
||||||
smsg("%4d STORESCRIPT %s in %s", current,
|
smsg("%4d STORESCRIPT %s-%d in %s", current,
|
||||||
sv->sv_name, si->sn_name);
|
sv->sv_name,
|
||||||
|
iptr->isn_arg.script.script_idx,
|
||||||
|
si->sn_name);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ISN_STOREOPT:
|
case ISN_STOREOPT:
|
||||||
|
@ -193,7 +193,8 @@ find_exported(
|
|||||||
int sid,
|
int sid,
|
||||||
char_u *name,
|
char_u *name,
|
||||||
ufunc_T **ufunc,
|
ufunc_T **ufunc,
|
||||||
type_T **type)
|
type_T **type,
|
||||||
|
cctx_T *cctx)
|
||||||
{
|
{
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
svar_T *sv;
|
svar_T *sv;
|
||||||
@ -201,7 +202,7 @@ find_exported(
|
|||||||
|
|
||||||
// find name in "script"
|
// find name in "script"
|
||||||
// TODO: also find script-local user function
|
// TODO: also find script-local user function
|
||||||
idx = get_script_item_idx(sid, name, FALSE);
|
idx = get_script_item_idx(sid, name, FALSE, cctx);
|
||||||
if (idx >= 0)
|
if (idx >= 0)
|
||||||
{
|
{
|
||||||
sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
|
sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
|
||||||
@ -248,6 +249,7 @@ find_exported(
|
|||||||
/*
|
/*
|
||||||
* Handle an ":import" command and add the resulting imported_T to "gap", when
|
* Handle an ":import" command and add the resulting imported_T to "gap", when
|
||||||
* not NULL, or script "import_sid" sn_imports.
|
* not NULL, or script "import_sid" sn_imports.
|
||||||
|
* "cctx" is NULL at the script level.
|
||||||
* Returns a pointer to after the command or NULL in case of failure
|
* Returns a pointer to after the command or NULL in case of failure
|
||||||
*/
|
*/
|
||||||
char_u *
|
char_u *
|
||||||
@ -461,7 +463,7 @@ handle_import(
|
|||||||
ufunc_T *ufunc = NULL;
|
ufunc_T *ufunc = NULL;
|
||||||
type_T *type;
|
type_T *type;
|
||||||
|
|
||||||
idx = find_exported(sid, name, &ufunc, &type);
|
idx = find_exported(sid, name, &ufunc, &type, cctx);
|
||||||
|
|
||||||
if (idx < 0 && ufunc == NULL)
|
if (idx < 0 && ufunc == NULL)
|
||||||
goto erret;
|
goto erret;
|
||||||
@ -623,9 +625,14 @@ add_vim9_script_var(dictitem_T *di, typval_T *tv, type_T *type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hide a script variable when leaving a block.
|
||||||
|
* "idx" is de index in sn_var_vals.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
hide_script_var(scriptitem_T *si, svar_T *sv)
|
hide_script_var(scriptitem_T *si, int idx)
|
||||||
{
|
{
|
||||||
|
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
|
||||||
hashtab_T *script_ht = get_script_local_ht();
|
hashtab_T *script_ht = get_script_local_ht();
|
||||||
hashtab_T *all_ht = &si->sn_all_vars.dv_hashtab;
|
hashtab_T *all_ht = &si->sn_all_vars.dv_hashtab;
|
||||||
hashitem_T *script_hi;
|
hashitem_T *script_hi;
|
||||||
@ -640,11 +647,19 @@ hide_script_var(scriptitem_T *si, svar_T *sv)
|
|||||||
dictitem_T *di = HI2DI(script_hi);
|
dictitem_T *di = HI2DI(script_hi);
|
||||||
sallvar_T *sav = HI2SAV(all_hi);
|
sallvar_T *sav = HI2SAV(all_hi);
|
||||||
|
|
||||||
|
// There can be multiple entries with the same name in different
|
||||||
|
// blocks, find the right one.
|
||||||
|
while (sav != NULL && sav->sav_var_vals_idx != idx)
|
||||||
|
sav = sav->sav_next;
|
||||||
|
if (sav != NULL)
|
||||||
|
{
|
||||||
sav->sav_tv = di->di_tv;
|
sav->sav_tv = di->di_tv;
|
||||||
di->di_tv.v_type = VAR_UNKNOWN;
|
di->di_tv.v_type = VAR_UNKNOWN;
|
||||||
sav->sav_flags = di->di_flags;
|
sav->sav_flags = di->di_flags;
|
||||||
sav->sav_di = NULL;
|
sav->sav_di = NULL;
|
||||||
delete_var(script_ht, script_hi);
|
delete_var(script_ht, script_hi);
|
||||||
|
sv->sv_tv = &sav->sav_tv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user