forked from aniani/vim
patch 8.2.0695: Vim9: cannot define a function inside a function
Problem: Vim9: cannot define a function inside a function. Solution: Initial support for :def inside :def.
This commit is contained in:
parent
80a8d3889b
commit
04b1269783
@ -2,6 +2,7 @@
|
|||||||
void func_init(void);
|
void func_init(void);
|
||||||
hashtab_T *func_tbl_get(void);
|
hashtab_T *func_tbl_get(void);
|
||||||
int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, garray_T *argtypes, int *varargs, garray_T *default_args, int skip, exarg_T *eap, char_u **line_to_free);
|
int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, garray_T *argtypes, int *varargs, garray_T *default_args, int skip, exarg_T *eap, char_u **line_to_free);
|
||||||
|
char_u *get_lambda_name(void);
|
||||||
int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate);
|
int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate);
|
||||||
char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
|
char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
|
||||||
void emsg_funcname(char *ermsg, char_u *name);
|
void emsg_funcname(char *ermsg, char_u *name);
|
||||||
@ -22,6 +23,7 @@ void user_func_error(int error, char_u *name);
|
|||||||
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe);
|
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe);
|
||||||
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, void *context);
|
||||||
void ex_function(exarg_T *eap);
|
void ex_function(exarg_T *eap);
|
||||||
int eval_fname_script(char_u *p);
|
int eval_fname_script(char_u *p);
|
||||||
int translated_function_exists(char_u *name, int is_global);
|
int translated_function_exists(char_u *name, int is_global);
|
||||||
|
@ -2,19 +2,7 @@
|
|||||||
|
|
||||||
source check.vim
|
source check.vim
|
||||||
source view_util.vim
|
source view_util.vim
|
||||||
|
source vim9.vim
|
||||||
" Check that "lines" inside ":def" results in an "error" message.
|
|
||||||
func CheckDefFailure(lines, error)
|
|
||||||
call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef')
|
|
||||||
call assert_fails('so Xdef', a:error, a:lines)
|
|
||||||
call delete('Xdef')
|
|
||||||
endfunc
|
|
||||||
|
|
||||||
func CheckScriptFailure(lines, error)
|
|
||||||
call writefile(a:lines, 'Xdef')
|
|
||||||
call assert_fails('so Xdef', a:error, a:lines)
|
|
||||||
call delete('Xdef')
|
|
||||||
endfunc
|
|
||||||
|
|
||||||
func Test_def_basic()
|
func Test_def_basic()
|
||||||
def SomeFunc(): string
|
def SomeFunc(): string
|
||||||
@ -95,8 +83,17 @@ def Test_call_default_args()
|
|||||||
assert_equal('one', MyDefaultArgs('one'))
|
assert_equal('one', MyDefaultArgs('one'))
|
||||||
assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
|
assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
|
||||||
|
|
||||||
call CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef'], 'E1001:')
|
CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef'], 'E1001:')
|
||||||
call CheckScriptFailure(['def Func(arg: number = "text")', 'enddef'], 'E1013: argument 1: type mismatch, expected number but got string')
|
CheckScriptFailure(['def Func(arg: number = "text")', 'enddef'], 'E1013: argument 1: type mismatch, expected number but got string')
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Test_nested_function()
|
||||||
|
def Nested(arg: string): string
|
||||||
|
return 'nested ' .. arg
|
||||||
|
enddef
|
||||||
|
assert_equal('nested function', Nested('function'))
|
||||||
|
|
||||||
|
CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
func Test_call_default_args_from_func()
|
func Test_call_default_args_from_func()
|
||||||
@ -721,5 +718,13 @@ def Test_closure_using_argument()
|
|||||||
unlet g:UseVararg
|
unlet g:UseVararg
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_nested_closure()
|
||||||
|
let local = 'text'
|
||||||
|
def Closure(arg: string): string
|
||||||
|
return local .. arg
|
||||||
|
enddef
|
||||||
|
assert_equal('text!!!', Closure('!!!'))
|
||||||
|
enddef
|
||||||
|
|
||||||
|
|
||||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@ -328,6 +328,19 @@ set_ufunc_name(ufunc_T *fp, char_u *name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a name for a lambda. Returned in static memory.
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
get_lambda_name(void)
|
||||||
|
{
|
||||||
|
static char_u name[30];
|
||||||
|
static int lambda_no = 0;
|
||||||
|
|
||||||
|
sprintf((char*)name, "<lambda>%d", ++lambda_no);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse a lambda expression and get a Funcref from "*arg".
|
* Parse a lambda expression and get a Funcref from "*arg".
|
||||||
* Return OK or FAIL. Returns NOTDONE for dict or {expr}.
|
* Return OK or FAIL. Returns NOTDONE for dict or {expr}.
|
||||||
@ -344,7 +357,6 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
int ret;
|
int ret;
|
||||||
char_u *start = skipwhite(*arg + 1);
|
char_u *start = skipwhite(*arg + 1);
|
||||||
char_u *s, *e;
|
char_u *s, *e;
|
||||||
static int lambda_no = 0;
|
|
||||||
int *old_eval_lavars = eval_lavars_used;
|
int *old_eval_lavars = eval_lavars_used;
|
||||||
int eval_lavars = FALSE;
|
int eval_lavars = FALSE;
|
||||||
|
|
||||||
@ -392,9 +404,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
{
|
{
|
||||||
int len, flags = 0;
|
int len, flags = 0;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
char_u name[20];
|
char_u *name = get_lambda_name();
|
||||||
|
|
||||||
sprintf((char*)name, "<lambda>%d", ++lambda_no);
|
|
||||||
|
|
||||||
fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
|
fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
|
||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
@ -2364,10 +2374,11 @@ untrans_function_name(char_u *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ":function"
|
* ":function" also supporting nested ":def".
|
||||||
|
* Returns a pointer to the function or NULL if no function defined.
|
||||||
*/
|
*/
|
||||||
void
|
ufunc_T *
|
||||||
ex_function(exarg_T *eap)
|
def_function(exarg_T *eap, char_u *name_arg, void *context)
|
||||||
{
|
{
|
||||||
char_u *theline;
|
char_u *theline;
|
||||||
char_u *line_to_free = NULL;
|
char_u *line_to_free = NULL;
|
||||||
@ -2375,7 +2386,7 @@ ex_function(exarg_T *eap)
|
|||||||
int c;
|
int c;
|
||||||
int saved_did_emsg;
|
int saved_did_emsg;
|
||||||
int saved_wait_return = need_wait_return;
|
int saved_wait_return = need_wait_return;
|
||||||
char_u *name = NULL;
|
char_u *name = name_arg;
|
||||||
int is_global = FALSE;
|
int is_global = FALSE;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
char_u *arg;
|
char_u *arg;
|
||||||
@ -2387,7 +2398,7 @@ ex_function(exarg_T *eap)
|
|||||||
int varargs = FALSE;
|
int varargs = FALSE;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
char_u *ret_type = NULL;
|
char_u *ret_type = NULL;
|
||||||
ufunc_T *fp;
|
ufunc_T *fp = NULL;
|
||||||
int overwrite = FALSE;
|
int overwrite = FALSE;
|
||||||
int indent;
|
int indent;
|
||||||
int nesting;
|
int nesting;
|
||||||
@ -2429,7 +2440,7 @@ ex_function(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
eap->nextcmd = check_nextcmd(eap->arg);
|
eap->nextcmd = check_nextcmd(eap->arg);
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2469,7 +2480,7 @@ ex_function(exarg_T *eap)
|
|||||||
if (*p == '/')
|
if (*p == '/')
|
||||||
++p;
|
++p;
|
||||||
eap->nextcmd = check_nextcmd(p);
|
eap->nextcmd = check_nextcmd(p);
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ga_init(&newargs);
|
ga_init(&newargs);
|
||||||
@ -2493,25 +2504,34 @@ ex_function(exarg_T *eap)
|
|||||||
* g:func global function name, same as "func"
|
* g:func global function name, same as "func"
|
||||||
*/
|
*/
|
||||||
p = eap->arg;
|
p = eap->arg;
|
||||||
name = trans_function_name(&p, &is_global, eap->skip,
|
if (name_arg != NULL)
|
||||||
TFN_NO_AUTOLOAD, &fudi, NULL);
|
|
||||||
paren = (vim_strchr(p, '(') != NULL);
|
|
||||||
if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
|
|
||||||
{
|
{
|
||||||
/*
|
// nested function, argument is (args).
|
||||||
* Return on an invalid expression in braces, unless the expression
|
paren = TRUE;
|
||||||
* evaluation has been cancelled due to an aborting error, an
|
CLEAR_FIELD(fudi);
|
||||||
* interrupt, or an exception.
|
}
|
||||||
*/
|
else
|
||||||
if (!aborting())
|
{
|
||||||
|
name = trans_function_name(&p, &is_global, eap->skip,
|
||||||
|
TFN_NO_AUTOLOAD, &fudi, NULL);
|
||||||
|
paren = (vim_strchr(p, '(') != NULL);
|
||||||
|
if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
|
||||||
{
|
{
|
||||||
if (!eap->skip && fudi.fd_newkey != NULL)
|
/*
|
||||||
semsg(_(e_dictkey), fudi.fd_newkey);
|
* Return on an invalid expression in braces, unless the expression
|
||||||
vim_free(fudi.fd_newkey);
|
* evaluation has been cancelled due to an aborting error, an
|
||||||
return;
|
* interrupt, or an exception.
|
||||||
|
*/
|
||||||
|
if (!aborting())
|
||||||
|
{
|
||||||
|
if (!eap->skip && fudi.fd_newkey != NULL)
|
||||||
|
semsg(_(e_dictkey), fudi.fd_newkey);
|
||||||
|
vim_free(fudi.fd_newkey);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
eap->skip = TRUE;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
eap->skip = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// An error in a function call during evaluation of an expression in magic
|
// An error in a function call during evaluation of an expression in magic
|
||||||
@ -2596,7 +2616,7 @@ ex_function(exarg_T *eap)
|
|||||||
|
|
||||||
ga_init2(&newlines, (int)sizeof(char_u *), 3);
|
ga_init2(&newlines, (int)sizeof(char_u *), 3);
|
||||||
|
|
||||||
if (!eap->skip)
|
if (!eap->skip && name_arg == NULL)
|
||||||
{
|
{
|
||||||
// Check the name of the function. Unless it's a dictionary function
|
// Check the name of the function. Unless it's a dictionary function
|
||||||
// (that we are overwriting).
|
// (that we are overwriting).
|
||||||
@ -3255,7 +3275,7 @@ ex_function(exarg_T *eap)
|
|||||||
|
|
||||||
// ":def Func()" needs to be compiled
|
// ":def Func()" needs to be compiled
|
||||||
if (eap->cmdidx == CMD_def)
|
if (eap->cmdidx == CMD_def)
|
||||||
compile_def_function(fp, FALSE, NULL);
|
compile_def_function(fp, FALSE, context);
|
||||||
|
|
||||||
goto ret_free;
|
goto ret_free;
|
||||||
|
|
||||||
@ -3269,10 +3289,22 @@ ret_free:
|
|||||||
vim_free(skip_until);
|
vim_free(skip_until);
|
||||||
vim_free(line_to_free);
|
vim_free(line_to_free);
|
||||||
vim_free(fudi.fd_newkey);
|
vim_free(fudi.fd_newkey);
|
||||||
vim_free(name);
|
if (name != name_arg)
|
||||||
|
vim_free(name);
|
||||||
vim_free(ret_type);
|
vim_free(ret_type);
|
||||||
did_emsg |= saved_did_emsg;
|
did_emsg |= saved_did_emsg;
|
||||||
need_wait_return |= saved_wait_return;
|
need_wait_return |= saved_wait_return;
|
||||||
|
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ":function"
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ex_function(exarg_T *eap)
|
||||||
|
{
|
||||||
|
def_function(eap, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -746,6 +746,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 */
|
||||||
|
/**/
|
||||||
|
695,
|
||||||
/**/
|
/**/
|
||||||
694,
|
694,
|
||||||
/**/
|
/**/
|
||||||
|
@ -101,6 +101,7 @@ typedef struct {
|
|||||||
int lv_from_outer; // when TRUE using ctx_outer scope
|
int lv_from_outer; // when TRUE using ctx_outer scope
|
||||||
int lv_const; // when TRUE cannot be assigned to
|
int lv_const; // when TRUE cannot be assigned to
|
||||||
int lv_arg; // when TRUE this is an argument
|
int lv_arg; // when TRUE this is an argument
|
||||||
|
int lv_func_idx; // for nested function
|
||||||
} lvar_T;
|
} lvar_T;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2615,6 +2616,7 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init)
|
|||||||
int error = FCERR_NONE;
|
int error = FCERR_NONE;
|
||||||
ufunc_T *ufunc;
|
ufunc_T *ufunc;
|
||||||
int res = FAIL;
|
int res = FAIL;
|
||||||
|
lvar_T *lvar;
|
||||||
|
|
||||||
if (varlen >= sizeof(namebuf))
|
if (varlen >= sizeof(namebuf))
|
||||||
{
|
{
|
||||||
@ -2641,6 +2643,16 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init)
|
|||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the name is a nested function.
|
||||||
|
lvar = lookup_local(namebuf, varlen, cctx);
|
||||||
|
if (lvar != NULL && lvar->lv_func_idx > 0)
|
||||||
|
{
|
||||||
|
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||||
|
+ lvar->lv_func_idx;
|
||||||
|
res = generate_CALL(cctx, dfunc->df_ufunc, argcount);
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
|
|
||||||
// If we can find the function by name generate the right call.
|
// If we can find the function by name generate the right call.
|
||||||
ufunc = find_func(name, FALSE, cctx);
|
ufunc = find_func(name, FALSE, cctx);
|
||||||
if (ufunc != NULL)
|
if (ufunc != NULL)
|
||||||
@ -4048,6 +4060,64 @@ compile_return(char_u *arg, int set_return_type, cctx_T *cctx)
|
|||||||
return skipwhite(p);
|
return skipwhite(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a line from the compilation context, compatible with exarg_T getline().
|
||||||
|
* Return a pointer to the line in allocated memory.
|
||||||
|
* Return NULL for end-of-file or some error.
|
||||||
|
*/
|
||||||
|
static char_u *
|
||||||
|
exarg_getline(
|
||||||
|
int c UNUSED,
|
||||||
|
void *cookie,
|
||||||
|
int indent UNUSED,
|
||||||
|
int do_concat UNUSED)
|
||||||
|
{
|
||||||
|
cctx_T *cctx = (cctx_T *)cookie;
|
||||||
|
|
||||||
|
if (cctx->ctx_lnum == cctx->ctx_ufunc->uf_lines.ga_len)
|
||||||
|
{
|
||||||
|
iemsg("Heredoc got to end");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
++cctx->ctx_lnum;
|
||||||
|
return vim_strsave(((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)
|
||||||
|
[cctx->ctx_lnum]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compile a nested :def command.
|
||||||
|
*/
|
||||||
|
static char_u *
|
||||||
|
compile_nested_function(exarg_T *eap, cctx_T *cctx)
|
||||||
|
{
|
||||||
|
char_u *name_start = eap->arg;
|
||||||
|
char_u *name_end = to_name_end(eap->arg, FALSE);
|
||||||
|
char_u *name = get_lambda_name();
|
||||||
|
lvar_T *lvar;
|
||||||
|
ufunc_T *ufunc;
|
||||||
|
|
||||||
|
eap->arg = name_end;
|
||||||
|
eap->getline = exarg_getline;
|
||||||
|
eap->cookie = cctx;
|
||||||
|
eap->skip = cctx->ctx_skip == TRUE;
|
||||||
|
eap->forceit = FALSE;
|
||||||
|
ufunc = def_function(eap, name, cctx);
|
||||||
|
|
||||||
|
if (ufunc == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Define a local variable for the function, but change the index to -1 to
|
||||||
|
// mark it as a function name.
|
||||||
|
lvar = reserve_local(cctx, name_start, name_end - name_start,
|
||||||
|
TRUE, &t_func_unknown);
|
||||||
|
lvar->lv_idx = 0;
|
||||||
|
++cctx->ctx_locals_count; // doesn't count as a local variable
|
||||||
|
lvar->lv_func_idx = ufunc->uf_dfunc_idx;
|
||||||
|
|
||||||
|
// TODO: warning for trailing?
|
||||||
|
return (char_u *)"";
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the length of an assignment operator, or zero if there isn't one.
|
* Return the length of an assignment operator, or zero if there isn't one.
|
||||||
*/
|
*/
|
||||||
@ -4077,30 +4147,6 @@ static char *reserved[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Get a line for "=<<".
|
|
||||||
* Return a pointer to the line in allocated memory.
|
|
||||||
* Return NULL for end-of-file or some error.
|
|
||||||
*/
|
|
||||||
static char_u *
|
|
||||||
heredoc_getline(
|
|
||||||
int c UNUSED,
|
|
||||||
void *cookie,
|
|
||||||
int indent UNUSED,
|
|
||||||
int do_concat UNUSED)
|
|
||||||
{
|
|
||||||
cctx_T *cctx = (cctx_T *)cookie;
|
|
||||||
|
|
||||||
if (cctx->ctx_lnum == cctx->ctx_ufunc->uf_lines.ga_len)
|
|
||||||
{
|
|
||||||
iemsg("Heredoc got to end");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
++cctx->ctx_lnum;
|
|
||||||
return vim_strsave(((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)
|
|
||||||
[cctx->ctx_lnum]);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
dest_local,
|
dest_local,
|
||||||
dest_option,
|
dest_option,
|
||||||
@ -4394,7 +4440,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
listitem_T *li;
|
listitem_T *li;
|
||||||
|
|
||||||
// [let] varname =<< [trim] {end}
|
// [let] varname =<< [trim] {end}
|
||||||
eap->getline = heredoc_getline;
|
eap->getline = exarg_getline;
|
||||||
eap->cookie = cctx;
|
eap->cookie = cctx;
|
||||||
l = heredoc_get(eap, op + 3, FALSE);
|
l = heredoc_get(eap, op + 3, FALSE);
|
||||||
|
|
||||||
@ -6299,9 +6345,12 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
|||||||
switch (ea.cmdidx)
|
switch (ea.cmdidx)
|
||||||
{
|
{
|
||||||
case CMD_def:
|
case CMD_def:
|
||||||
|
ea.arg = p;
|
||||||
|
line = compile_nested_function(&ea, &cctx);
|
||||||
|
break;
|
||||||
|
|
||||||
case CMD_function:
|
case CMD_function:
|
||||||
// TODO: Nested function
|
emsg(_("E1086: Cannot use :function inside :def"));
|
||||||
emsg("Nested function not implemented yet");
|
|
||||||
goto erret;
|
goto erret;
|
||||||
|
|
||||||
case CMD_return:
|
case CMD_return:
|
||||||
|
@ -206,6 +206,11 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx)
|
|||||||
+ dfunc->df_varcount + dfunc->df_closure_count) == FAIL)
|
+ dfunc->df_varcount + dfunc->df_closure_count) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
|
// Closure may need the function context where it was defined.
|
||||||
|
// TODO: assuming current context.
|
||||||
|
ectx->ec_outer_stack = &ectx->ec_stack;
|
||||||
|
ectx->ec_outer_frame = ectx->ec_frame_idx;
|
||||||
|
|
||||||
// Move the vararg-list to below the missing optional arguments.
|
// Move the vararg-list to below the missing optional arguments.
|
||||||
if (vararg_count > 0 && arg_to_add > 0)
|
if (vararg_count > 0 && arg_to_add > 0)
|
||||||
*STACK_TV_BOT(arg_to_add - 1) = *STACK_TV_BOT(-1);
|
*STACK_TV_BOT(arg_to_add - 1) = *STACK_TV_BOT(-1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user