mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
patch 8.2.1870: Vim9: no need to keep all script variables
Problem: Vim9: no need to keep all script variables. Solution: Only keep script variables when a function was defined that could use them. Fix freeing static string on exit.
This commit is contained in:
@@ -930,16 +930,22 @@ leave_block(cstack_T *cstack)
|
|||||||
{
|
{
|
||||||
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||||
int i;
|
int i;
|
||||||
|
int func_defined =
|
||||||
|
cstack->cs_flags[cstack->cs_idx] & CSF_FUNC_DEF;
|
||||||
|
|
||||||
for (i = cstack->cs_script_var_len[cstack->cs_idx];
|
for (i = cstack->cs_script_var_len[cstack->cs_idx];
|
||||||
i < si->sn_var_vals.ga_len; ++i)
|
i < si->sn_var_vals.ga_len; ++i)
|
||||||
{
|
{
|
||||||
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + i;
|
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + i;
|
||||||
|
|
||||||
|
// sv_name is set to NULL if it was already removed. This happens
|
||||||
|
// when it was defined in an inner block and no functions were
|
||||||
|
// defined there.
|
||||||
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, i);
|
// if "func_defined" is non-zero.
|
||||||
|
hide_script_var(si, i, func_defined);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: is this needed?
|
// TODO: is this needed?
|
||||||
|
@@ -9,7 +9,7 @@ int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T
|
|||||||
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, int idx);
|
void hide_script_var(scriptitem_T *si, int idx, int func_defined);
|
||||||
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);
|
||||||
|
@@ -917,6 +917,8 @@ typedef struct {
|
|||||||
# define CSF_SILENT 0x1000 // "emsg_silent" reset by ":try"
|
# define CSF_SILENT 0x1000 // "emsg_silent" reset by ":try"
|
||||||
// Note that CSF_ELSE is only used when CSF_TRY and CSF_WHILE are unset
|
// Note that CSF_ELSE is only used when CSF_TRY and CSF_WHILE are unset
|
||||||
// (an ":if"), and CSF_SILENT is only used when CSF_TRY is set.
|
// (an ":if"), and CSF_SILENT is only used when CSF_TRY is set.
|
||||||
|
//
|
||||||
|
#define CSF_FUNC_DEF 0x2000 // a function was defined in this block
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* What's pending for being reactivated at the ":endtry" of this try
|
* What's pending for being reactivated at the ":endtry" of this try
|
||||||
|
@@ -296,6 +296,25 @@ def Test_block_local_vars()
|
|||||||
delete('Xdidit')
|
delete('Xdidit')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_block_local_vars_with_func()
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
if true
|
||||||
|
var foo = 'foo'
|
||||||
|
if true
|
||||||
|
var bar = 'bar'
|
||||||
|
def Func(): list<string>
|
||||||
|
return [foo, bar]
|
||||||
|
enddef
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
# function is compiled here, after blocks have finished, can still access
|
||||||
|
# "foo" and "bar"
|
||||||
|
assert_equal(['foo', 'bar'], Func())
|
||||||
|
END
|
||||||
|
CheckScriptSuccess(lines)
|
||||||
|
enddef
|
||||||
|
|
||||||
func g:NoSuchFunc()
|
func g:NoSuchFunc()
|
||||||
echo 'none'
|
echo 'none'
|
||||||
endfunc
|
endfunc
|
||||||
|
@@ -3472,26 +3472,34 @@ define_function(exarg_T *eap, char_u *name_arg)
|
|||||||
if (eap->cmdidx == CMD_def)
|
if (eap->cmdidx == CMD_def)
|
||||||
{
|
{
|
||||||
int lnum_save = SOURCING_LNUM;
|
int lnum_save = SOURCING_LNUM;
|
||||||
|
cstack_T *cstack = eap->cstack;
|
||||||
|
|
||||||
fp->uf_def_status = UF_TO_BE_COMPILED;
|
fp->uf_def_status = UF_TO_BE_COMPILED;
|
||||||
|
|
||||||
// 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)
|
if (cstack != NULL && cstack->cs_idx >= 0)
|
||||||
{
|
{
|
||||||
int count = eap->cstack->cs_idx + 1;
|
int count = cstack->cs_idx + 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
// The block context may be needed for script variables declared in
|
// The block context may be needed for script variables declared in
|
||||||
// a block visible now but not when the function is compiled.
|
// a block that is visible now but not when the function is called
|
||||||
|
// later.
|
||||||
fp->uf_block_ids = ALLOC_MULT(int, count);
|
fp->uf_block_ids = ALLOC_MULT(int, count);
|
||||||
if (fp->uf_block_ids != NULL)
|
if (fp->uf_block_ids != NULL)
|
||||||
{
|
{
|
||||||
mch_memmove(fp->uf_block_ids, eap->cstack->cs_block_id,
|
mch_memmove(fp->uf_block_ids, cstack->cs_block_id,
|
||||||
sizeof(int) * count);
|
sizeof(int) * count);
|
||||||
fp->uf_block_depth = count;
|
fp->uf_block_depth = count;
|
||||||
}
|
}
|
||||||
// TODO: set flag in each block to indicate a function was defined
|
|
||||||
|
// Set flag in each block to indicate a function was defined. This
|
||||||
|
// is used to keep the variable when leaving the block, see
|
||||||
|
// hide_script_var().
|
||||||
|
for (i = 0; i <= cstack->cs_idx; ++i)
|
||||||
|
cstack->cs_flags[i] |= CSF_FUNC_DEF;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse the argument types
|
// parse the argument types
|
||||||
|
@@ -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 */
|
||||||
|
/**/
|
||||||
|
1870,
|
||||||
/**/
|
/**/
|
||||||
1869,
|
1869,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -51,8 +51,8 @@ ex_vim9script(exarg_T *eap)
|
|||||||
|
|
||||||
if (STRCMP(p_cpo, CPO_VIM) != 0)
|
if (STRCMP(p_cpo, CPO_VIM) != 0)
|
||||||
{
|
{
|
||||||
si->sn_save_cpo = p_cpo;
|
si->sn_save_cpo = vim_strsave(p_cpo);
|
||||||
p_cpo = vim_strsave((char_u *)CPO_VIM);
|
set_option_value((char_u *)"cpo", 0L, (char_u *)CPO_VIM, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,8 +569,8 @@ vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Vim9 part of adding a script variable: add it to sn_all_vars and
|
* Vim9 part of adding a script variable: add it to sn_all_vars (lookup by name
|
||||||
* sn_var_vals.
|
* with a hashtable) and sn_var_vals (lookup by index).
|
||||||
* When "type" is NULL use "tv" for the type.
|
* When "type" is NULL use "tv" for the type.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@@ -628,9 +628,11 @@ add_vim9_script_var(dictitem_T *di, typval_T *tv, type_T *type)
|
|||||||
/*
|
/*
|
||||||
* Hide a script variable when leaving a block.
|
* Hide a script variable when leaving a block.
|
||||||
* "idx" is de index in sn_var_vals.
|
* "idx" is de index in sn_var_vals.
|
||||||
|
* When "func_defined" is non-zero then a function was defined in this block,
|
||||||
|
* the variable may be accessed by it. Otherwise the variable can be cleared.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
hide_script_var(scriptitem_T *si, int idx)
|
hide_script_var(scriptitem_T *si, int idx, int func_defined)
|
||||||
{
|
{
|
||||||
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + 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();
|
||||||
@@ -639,6 +641,7 @@ hide_script_var(scriptitem_T *si, int idx)
|
|||||||
hashitem_T *all_hi;
|
hashitem_T *all_hi;
|
||||||
|
|
||||||
// Remove a variable declared inside the block, if it still exists.
|
// Remove a variable declared inside the block, if it still exists.
|
||||||
|
// If it was added in a nested block it will already have been removed.
|
||||||
// The typval is moved into the sallvar_T.
|
// The typval is moved into the sallvar_T.
|
||||||
script_hi = hash_find(script_ht, sv->sv_name);
|
script_hi = hash_find(script_ht, sv->sv_name);
|
||||||
all_hi = hash_find(all_ht, sv->sv_name);
|
all_hi = hash_find(all_ht, sv->sv_name);
|
||||||
@@ -646,20 +649,37 @@ hide_script_var(scriptitem_T *si, int idx)
|
|||||||
{
|
{
|
||||||
dictitem_T *di = HI2DI(script_hi);
|
dictitem_T *di = HI2DI(script_hi);
|
||||||
sallvar_T *sav = HI2SAV(all_hi);
|
sallvar_T *sav = HI2SAV(all_hi);
|
||||||
|
sallvar_T *sav_prev = NULL;
|
||||||
|
|
||||||
// There can be multiple entries with the same name in different
|
// There can be multiple entries with the same name in different
|
||||||
// blocks, find the right one.
|
// blocks, find the right one.
|
||||||
while (sav != NULL && sav->sav_var_vals_idx != idx)
|
while (sav != NULL && sav->sav_var_vals_idx != idx)
|
||||||
|
{
|
||||||
|
sav_prev = sav;
|
||||||
sav = sav->sav_next;
|
sav = sav->sav_next;
|
||||||
|
}
|
||||||
if (sav != NULL)
|
if (sav != NULL)
|
||||||
{
|
{
|
||||||
|
if (func_defined)
|
||||||
|
{
|
||||||
|
// move the typval from the dictitem to the sallvar
|
||||||
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);
|
|
||||||
sv->sv_tv = &sav->sav_tv;
|
sv->sv_tv = &sav->sav_tv;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (sav_prev == NULL)
|
||||||
|
hash_remove(all_ht, all_hi);
|
||||||
|
else
|
||||||
|
sav_prev->sav_next = sav->sav_next;
|
||||||
|
sv->sv_name = NULL;
|
||||||
|
vim_free(sav);
|
||||||
|
}
|
||||||
|
delete_var(script_ht, script_hi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user