mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.2.3692: Vim9: cannot use :func inside a :def function
Problem: Vim9: cannot use :func inside a :def function. Solution: Make it work.
This commit is contained in:
@@ -355,8 +355,7 @@ EXTERN char e_cannot_delete_vim9_script_function_str[]
|
||||
INIT(= N_("E1084: Cannot delete Vim9 script function %s"));
|
||||
EXTERN char e_not_callable_type_str[]
|
||||
INIT(= N_("E1085: Not a callable type: %s"));
|
||||
EXTERN char e_cannot_use_function_inside_def[]
|
||||
INIT(= N_("E1086: Cannot use :function inside :def"));
|
||||
// E1086 unused
|
||||
EXTERN char e_cannot_use_index_when_declaring_variable[]
|
||||
INIT(= N_("E1087: Cannot use an index when declaring a variable"));
|
||||
// E1088 unused
|
||||
|
@@ -1699,6 +1699,7 @@ typedef struct
|
||||
#define FC_VIM9 0x400 // defined in vim9 script file
|
||||
#define FC_CFUNC 0x800 // defined as Lua C func
|
||||
#define FC_COPY 0x1000 // copy of another function by copy_func()
|
||||
#define FC_LAMBDA 0x2000 // one line "return {expr}"
|
||||
|
||||
#define MAX_FUNC_ARGS 20 // maximum number of function arguments
|
||||
#define VAR_SHORT_LEN 20 // short variable name length
|
||||
|
@@ -586,15 +586,19 @@ def Test_func_with_comments()
|
||||
enddef
|
||||
|
||||
def Test_nested_function()
|
||||
def Nested(arg: string): string
|
||||
def NestedDef(arg: string): string
|
||||
return 'nested ' .. arg
|
||||
enddef
|
||||
Nested('function')->assert_equal('nested function')
|
||||
NestedDef(':def')->assert_equal('nested :def')
|
||||
|
||||
func NestedFunc(arg)
|
||||
return 'nested ' .. a:arg
|
||||
endfunc
|
||||
NestedFunc(':func')->assert_equal('nested :func')
|
||||
|
||||
CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:')
|
||||
CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:')
|
||||
|
||||
CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:')
|
||||
CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:')
|
||||
CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:')
|
||||
|
||||
@@ -702,6 +706,26 @@ def Test_nested_global_function()
|
||||
END
|
||||
CheckScriptSuccess(lines)
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
def Outer()
|
||||
func g:Inner()
|
||||
return 'inner'
|
||||
endfunc
|
||||
enddef
|
||||
defcompile
|
||||
Outer()
|
||||
g:Inner()->assert_equal('inner')
|
||||
delfunc g:Inner
|
||||
Outer()
|
||||
g:Inner()->assert_equal('inner')
|
||||
delfunc g:Inner
|
||||
Outer()
|
||||
g:Inner()->assert_equal('inner')
|
||||
delfunc g:Inner
|
||||
END
|
||||
CheckScriptSuccess(lines)
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
def Outer()
|
||||
|
@@ -523,7 +523,7 @@ register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state)
|
||||
fp->uf_def_status = UF_NOT_COMPILED;
|
||||
fp->uf_refcount = 1;
|
||||
fp->uf_varargs = TRUE;
|
||||
fp->uf_flags = FC_CFUNC;
|
||||
fp->uf_flags = FC_CFUNC | FC_LAMBDA;
|
||||
fp->uf_calls = 0;
|
||||
fp->uf_script_ctx = current_sctx;
|
||||
fp->uf_cb = cb;
|
||||
@@ -1205,6 +1205,7 @@ lambda_function_body(
|
||||
set_ufunc_name(ufunc, name);
|
||||
if (hash_add(&func_hashtab, UF2HIKEY(ufunc)) == FAIL)
|
||||
goto erret;
|
||||
ufunc->uf_flags = FC_LAMBDA;
|
||||
ufunc->uf_refcount = 1;
|
||||
ufunc->uf_args = *newargs;
|
||||
newargs->ga_data = NULL;
|
||||
@@ -1399,7 +1400,7 @@ get_lambda_tv(
|
||||
if (evaluate)
|
||||
{
|
||||
int len;
|
||||
int flags = 0;
|
||||
int flags = FC_LAMBDA;
|
||||
char_u *p;
|
||||
char_u *line_end;
|
||||
char_u *name = get_lambda_name();
|
||||
@@ -2506,8 +2507,7 @@ call_user_func(
|
||||
return;
|
||||
}
|
||||
|
||||
if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
|
||||
islambda = TRUE;
|
||||
islambda = fp->uf_flags & FC_LAMBDA;
|
||||
|
||||
/*
|
||||
* Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables
|
||||
|
@@ -757,6 +757,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
3692,
|
||||
/**/
|
||||
3691,
|
||||
/**/
|
||||
|
@@ -322,7 +322,8 @@ typedef struct {
|
||||
|
||||
// arguments to ISN_FUNCREF
|
||||
typedef struct {
|
||||
int fr_func; // function index
|
||||
int fr_dfunc_idx; // function index for :def function
|
||||
char_u *fr_func_name; // function name for legacy function
|
||||
} funcref_T;
|
||||
|
||||
// arguments to ISN_NEWFUNC
|
||||
|
@@ -1675,7 +1675,10 @@ generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc)
|
||||
RETURN_OK_IF_SKIP(cctx);
|
||||
if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
|
||||
return FAIL;
|
||||
isn->isn_arg.funcref.fr_func = ufunc->uf_dfunc_idx;
|
||||
if (ufunc->uf_def_status == UF_NOT_COMPILED)
|
||||
isn->isn_arg.funcref.fr_func_name = vim_strsave(ufunc->uf_name);
|
||||
else
|
||||
isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx;
|
||||
cctx->ctx_has_closure = 1;
|
||||
|
||||
// If the referenced function is a closure, it may use items further up in
|
||||
@@ -5835,6 +5838,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
|
||||
fill_exarg_from_cctx(eap, cctx);
|
||||
|
||||
eap->forceit = FALSE;
|
||||
// We use the special <Lamba>99 name, but it's not really a lambda.
|
||||
lambda_name = vim_strsave(get_lambda_name());
|
||||
if (lambda_name == NULL)
|
||||
return NULL;
|
||||
@@ -9976,16 +9980,11 @@ compile_def_function(
|
||||
switch (ea.cmdidx)
|
||||
{
|
||||
case CMD_def:
|
||||
case CMD_function:
|
||||
ea.arg = p;
|
||||
line = compile_nested_function(&ea, &cctx);
|
||||
break;
|
||||
|
||||
case CMD_function:
|
||||
// TODO: should we allow this, e.g. to declare a global
|
||||
// function?
|
||||
emsg(_(e_cannot_use_function_inside_def));
|
||||
goto erret;
|
||||
|
||||
case CMD_return:
|
||||
line = compile_return(p, check_return_type,
|
||||
local_cmdmod.cmod_flags & CMOD_LEGACY, &cctx);
|
||||
@@ -10442,12 +10441,23 @@ delete_instr(isn_T *isn)
|
||||
|
||||
case ISN_FUNCREF:
|
||||
{
|
||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||
+ isn->isn_arg.funcref.fr_func;
|
||||
ufunc_T *ufunc = dfunc->df_ufunc;
|
||||
if (isn->isn_arg.funcref.fr_func_name == NULL)
|
||||
{
|
||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||
+ isn->isn_arg.funcref.fr_dfunc_idx;
|
||||
ufunc_T *ufunc = dfunc->df_ufunc;
|
||||
|
||||
if (ufunc != NULL && func_name_refcount(ufunc->uf_name))
|
||||
func_ptr_unref(ufunc);
|
||||
if (ufunc != NULL && func_name_refcount(ufunc->uf_name))
|
||||
func_ptr_unref(ufunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
char_u *name = isn->isn_arg.funcref.fr_func_name;
|
||||
|
||||
if (name != NULL)
|
||||
func_unref(name);
|
||||
vim_free(isn->isn_arg.funcref.fr_func_name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@@ -3168,8 +3168,8 @@ exec_instructions(ectx_T *ectx)
|
||||
case ISN_FUNCREF:
|
||||
{
|
||||
partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
|
||||
dfunc_T *pt_dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||
+ iptr->isn_arg.funcref.fr_func;
|
||||
ufunc_T *ufunc;
|
||||
funcref_T *funcref = &iptr->isn_arg.funcref;
|
||||
|
||||
if (pt == NULL)
|
||||
goto theend;
|
||||
@@ -3178,8 +3178,18 @@ exec_instructions(ectx_T *ectx)
|
||||
vim_free(pt);
|
||||
goto theend;
|
||||
}
|
||||
if (fill_partial_and_closure(pt, pt_dfunc->df_ufunc,
|
||||
ectx) == FAIL)
|
||||
if (funcref->fr_func_name == NULL)
|
||||
{
|
||||
dfunc_T *pt_dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||
+ funcref->fr_dfunc_idx;
|
||||
|
||||
ufunc = pt_dfunc->df_ufunc;
|
||||
}
|
||||
else
|
||||
{
|
||||
ufunc = find_func(funcref->fr_func_name, FALSE, NULL);
|
||||
}
|
||||
if (fill_partial_and_closure(pt, ufunc, ectx) == FAIL)
|
||||
goto theend;
|
||||
tv = STACK_TV_BOT(0);
|
||||
++ectx->ec_stack.ga_len;
|
||||
@@ -5454,10 +5464,17 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
||||
case ISN_FUNCREF:
|
||||
{
|
||||
funcref_T *funcref = &iptr->isn_arg.funcref;
|
||||
dfunc_T *df = ((dfunc_T *)def_functions.ga_data)
|
||||
+ funcref->fr_func;
|
||||
char_u *name;
|
||||
|
||||
smsg("%s%4d FUNCREF %s", pfx, current, df->df_ufunc->uf_name);
|
||||
if (funcref->fr_func_name == NULL)
|
||||
{
|
||||
dfunc_T *df = ((dfunc_T *)def_functions.ga_data)
|
||||
+ funcref->fr_dfunc_idx;
|
||||
name = df->df_ufunc->uf_name;
|
||||
}
|
||||
else
|
||||
name = funcref->fr_func_name;
|
||||
smsg("%s%4d FUNCREF %s", pfx, current, name);
|
||||
}
|
||||
break;
|
||||
|
||||
|
Reference in New Issue
Block a user